"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const log_1 = tslib_1.__importDefault(require("../log"));
const network_1 = require("../network");
const proto_1 = require("./proto");
/**
 * BEvm service
 */
class BEvmRPC {
    constructor(roster) {
        this.timeout = 60 * 1000; // 60 seconds
        this.conns = roster.list.map((srvid) => new network_1.WebSocketConnection(srvid.getWebSocketAddress(), BEvmRPC.serviceName));
    }
    // Simple implementation of Promise.any()
    // Return a promise that resolves when the first given promise resolves,
    // or fails when they all do.
    static anyPromise(promises) {
        // Number of promises, used to determine when all have failed
        let count = promises.length;
        // Array to collect the promise failures
        const errors = Array.from({ length: count });
        if (count === 0) {
            return Promise.reject("Empty list of promises");
        }
        return new Promise((resolve, reject) => promises.forEach((p, index) => p.then((value) => resolve(value), (reason) => {
            errors[index] = reason;
            count--;
            if (count === 0) {
                reject(errors);
            }
        })));
    }
    /**
     * Set a new timeout value for future requests.
     *
     * @param value Timeout in [ms]
     */
    setTimeout(value) {
        this.timeout = value;
    }
    /**
     * Execute a view method (read-only)
     *
     * @param byzcoinId         ByzCoin ID
     * @param bevmInstanceId    BEvm instance ID
     * @param accountAddress    Address of the EVM account
     * @param contractAddress   Address of the smart contract
     * @param callData          ABI-packed call arguments
     * @param minBlockIndex     Minimum block index that nodes must have to
     *                          execute the view method
     *
     * @return Result of the view method execution
     */
    viewCall(byzcoinId, bevmInstanceId, accountAddress, contractAddress, callData, minBlockIndex = 0) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this.conns.forEach((conn) => conn.setTimeout(this.timeout));
            log_1.default.lvl3("Sending BEvm call request...");
            const msg = new proto_1.ViewCallRequest({
                accountAddress,
                bevmInstanceId,
                byzcoinId,
                callData,
                contractAddress,
                minBlockIndex,
            });
            // Send to the whole roster, use the first answer received
            return BEvmRPC.anyPromise(this.conns.map((conn) => conn.send(msg, proto_1.ViewCallResponse)));
        });
    }
}
exports.BEvmRPC = BEvmRPC;
BEvmRPC.serviceName = "BEvm";
