Exemplo n.º 1
0
    def monitor_settings(self):
        """Check if a modification of bridge settings is requested by seeing
        if the config file has been changed and try to update the bridge
        contract (gather 2/3 validators signatures).

        """
        config_data = load_config_data(self.config_file_path)
        t_anchor, t_final = query_aergo_tempo(self.hera, self.aergo_bridge)
        unfreeze_fee = query_unfreeze_fee(self.hera, self.aergo_bridge)
        config_t_anchor = (config_data['networks'][self.aergo_net]['bridges']
                           [self.eth_net]['t_anchor'])
        if t_anchor != config_t_anchor:
            logger.info(
                '\"Anchoring periode update requested: %s\"', config_t_anchor)
            self.update_t_anchor(config_t_anchor)
        config_t_final = (config_data['networks'][self.aergo_net]['bridges']
                          [self.eth_net]['t_final'])
        if t_final != config_t_final:
            logger.info('\"Finality update requested: %s\"', config_t_final)
            self.update_t_final(config_t_final)
        config_unfreeze_fee = (config_data['networks'][self.aergo_net]
                               ['bridges'][self.eth_net]['unfreeze_fee'])
        if unfreeze_fee != config_unfreeze_fee:
            logger.info(
                '\"Unfreeze fee update requested: %s\"', config_unfreeze_fee)
            self.update_unfreeze_fee(config_unfreeze_fee)
        if self.oracle_update:
            validators = query_aergo_validators(self.hera, self.aergo_oracle)
            config_validators = \
                [val['addr'] for val in config_data['validators']]
            if validators != config_validators:
                logger.info(
                    '\"Validator set update requested: %s\"',
                    config_validators
                )
                if self.update_validators(config_validators):
                    self.val_connect.use_new_validators(config_data)
            oracle = query_aergo_oracle(self.hera, self.aergo_bridge)
            config_oracle = (config_data['networks'][self.aergo_net]['bridges']
                             [self.eth_net]['oracle'])
            if oracle != config_oracle:
                logger.info('\"Oracle change requested: %s\"', config_oracle)
                self.update_oracle(config_oracle)
Exemplo n.º 2
0
    def is_valid_eth_anchor(self, anchor) -> Optional[str]:
        """ An anchor is valid if :
            1- it's height is finalized
            2- it's root for that height is correct.
            3- it's nonce is correct
            4- it's height is higher than previous anchored height + t_anchor
        """
        t_anchor, t_final = query_aergo_tempo(self.hera, self.aergo_oracle)
        # 1- get the last block height and check anchor height > LIB
        # lib = best_height - finalized_from
        best_height = self.web3.eth.blockNumber
        lib = best_height - t_final
        if anchor.height > lib:
            return (
                "anchor height not finalized, got: {}, expected: {}".format(
                    anchor.height, lib))

        # 2- get contract state root at origin_height
        # and check equals anchor root
        root = self.web3.eth.getBlock(anchor.height).stateRoot
        if root != anchor.root:
            return (
                "root doesn't match height {}, got: {}, expected: {}".format(
                    lib, anchor.root.hex(), root))

        # 3- check merkle bridge nonces are correct
        last_nonce_to = int(
            self.hera.query_sc_state(self.aergo_oracle,
                                     ["_sv__nonce"]).var_proofs[0].value)
        if last_nonce_to != anchor.destination_nonce:
            return ("anchor nonce invalid, got: {}, expected: {}".format(
                anchor.destination_nonce, last_nonce_to))

        # 4- check anchored height comes after the previous one and t_anchor is
        # passed
        last_merged_height_from = int(
            self.hera.query_sc_state(
                self.aergo_oracle, ["_sv__anchorHeight"]).var_proofs[0].value)
        if last_merged_height_from + t_anchor > anchor.height:
            return ("anchor height too soon, got: {}, expected: {}".format(
                anchor.height, last_merged_height_from + t_anchor))
        return None
Exemplo n.º 3
0
    def __init__(
        self,
        config_file_path: str,
        aergo_net: str,
        eth_net: str,
        eth_block_time: int,
        privkey_name: str = None,
        privkey_pwd: str = None,
        anchoring_on: bool = False,
        auto_update: bool = False,
        oracle_update: bool = False,
        aergo_gas_price: int = None,
        bridge_anchoring: bool = True
    ) -> None:
        threading.Thread.__init__(self, name="AergoProposerClient")
        if aergo_gas_price is None:
            aergo_gas_price = 0
        self.aergo_gas_price = aergo_gas_price
        self.config_file_path = config_file_path
        config_data = load_config_data(self.config_file_path)
        self.eth_block_time = eth_block_time
        self.eth_net = eth_net
        self.aergo_net = aergo_net
        self.anchoring_on = anchoring_on
        self.auto_update = auto_update
        self.oracle_update = oracle_update
        self.bridge_anchoring = bridge_anchoring
        logger.info("\"Connect Aergo and Ethereum providers\"")
        self.hera = herapy.Aergo()
        self.hera.connect(config_data['networks'][aergo_net]['ip'])

        ip = config_data['networks'][eth_net]['ip']
        self.web3 = Web3(Web3.HTTPProvider(ip))
        eth_poa = config_data['networks'][eth_net]['isPOA']
        if eth_poa:
            self.web3.middleware_onion.inject(geth_poa_middleware, layer=0)
        assert self.web3.isConnected()

        self.eth_bridge = (config_data['networks'][eth_net]['bridges']
                           [aergo_net]['addr'])
        self.aergo_bridge = (config_data['networks'][aergo_net]['bridges']
                             [eth_net]['addr'])
        self.aergo_oracle = (config_data['networks'][aergo_net]['bridges']
                             [eth_net]['oracle'])

        # get the current t_anchor and t_final for both sides of bridge
        self.t_anchor, self.t_final = query_aergo_tempo(
            self.hera, self.aergo_bridge
        )
        logger.info(
            "\"%s <- %s (t_final=%s) : t_anchor=%s\"", aergo_net, eth_net,
            self.t_final, self.t_anchor
        )

        if privkey_name is None:
            privkey_name = 'proposer'
        if privkey_pwd is None:
            privkey_pwd = getpass("Decrypt exported private key '{}'\n"
                                  "Password: "******"\"Connect to AergoValidators\"")
        self.val_connect = AergoValConnect(
            config_data, self.hera, self.aergo_oracle)
Exemplo n.º 4
0
    def __init__(
        self,
        config_file_path: str,
        aergo_net: str,
        eth_net: str,
        eth_block_time: int,
        privkey_name: str = None,
        privkey_pwd: str = None,
        anchoring_on: bool = False,
        auto_update: bool = False,
        oracle_update: bool = False,
        aergo_gas_price: int = None,
        bridge_anchoring: bool = True,
        root_path: str = './',
        eco: bool = False
    ) -> None:
        threading.Thread.__init__(self, name="AergoProposerClient")
        if aergo_gas_price is None:
            aergo_gas_price = 0
        self.aergo_gas_price = aergo_gas_price
        self.config_file_path = config_file_path
        config_data = load_config_data(self.config_file_path)
        self.eth_block_time = eth_block_time
        self.eth_net = eth_net
        self.aergo_net = aergo_net
        self.anchoring_on = anchoring_on
        self.auto_update = auto_update
        self.oracle_update = oracle_update
        self.bridge_anchoring = bridge_anchoring
        self.eco = eco

        logger.info("\"Connect Aergo and Ethereum providers\"")
        self.hera = herapy.Aergo()
        self.hera.connect(config_data['networks'][aergo_net]['ip'])

        ip = config_data['networks'][eth_net]['ip']
        self.web3 = Web3(Web3.HTTPProvider(ip))
        eth_poa = config_data['networks'][eth_net]['isPOA']
        if eth_poa:
            self.web3.middleware_onion.inject(geth_poa_middleware, layer=0)
        assert self.web3.isConnected()

        eth_bridge_abi_path = (config_data['networks'][eth_net]['bridges']
                               [aergo_net]['bridge_abi'])
        with open(root_path + eth_bridge_abi_path, "r") as f:
            eth_bridge_abi = f.read()
        self.eth_bridge_addr = (config_data['networks'][eth_net]['bridges']
                                [aergo_net]['addr'])
        self.eth_bridge = self.web3.eth.contract(
            address=self.eth_bridge_addr,
            abi=eth_bridge_abi
        )

        self.aergo_bridge = (config_data['networks'][aergo_net]['bridges']
                             [eth_net]['addr'])
        self.aergo_oracle = (config_data['networks'][aergo_net]['bridges']
                             [eth_net]['oracle'])

        # get the current t_anchor and t_final for both sides of bridge
        self.t_anchor, self.t_final = query_aergo_tempo(
            self.hera, self.aergo_bridge
        )
        logger.info(
            "\"%s <- %s (t_final=%s) : t_anchor=%s\"", aergo_net, eth_net,
            self.t_final, self.t_anchor
        )

        if not anchoring_on and not auto_update:
            # if anchoring and auto update are off, use proposer as monitoring
            # system
            return

        if privkey_name is None:
            privkey_name = 'proposer'
        keystore_path = config_data["wallet"][privkey_name]['keystore']
        with open(root_path + keystore_path, "r") as f:
            keystore = f.read()
        if privkey_pwd is None:
            while True:
                try:
                    privkey_pwd = getpass(
                        "Decrypt Aergo keystore: '{}'\nPassword: "******"\"Wrong password, try again\"")
        else:
            self.aergo_tx = AergoTx(
                self.hera, keystore, privkey_pwd, self.aergo_oracle,
                aergo_gas_price, self.t_anchor, eth_block_time
            )

        logger.info("\"Connect to AergoValidators\"")
        self.val_connect = AergoValConnect(
            config_data, self.hera, self.aergo_oracle)
Exemplo n.º 5
0
def check_bridge_status(root_path: str, config_data: Dict, aergo_net: str,
                        eth_net: str, auto_update: bool, oracle_update: bool):
    logger.info("\"Connect Aergo and Ethereum\"")
    hera = herapy.Aergo()
    hera.connect(config_data['networks'][aergo_net]['ip'])

    ip = config_data['networks'][eth_net]['ip']
    web3 = Web3(Web3.HTTPProvider(ip))
    eth_poa = config_data['networks'][eth_net]['isPOA']
    if eth_poa:
        web3.middleware_onion.inject(geth_poa_middleware, layer=0)
    assert web3.isConnected()

    # remember bridge contracts
    # eth bridge
    bridge_abi_path = (
        config_data['networks'][eth_net]['bridges'][aergo_net]['bridge_abi'])
    with open(root_path + bridge_abi_path, "r") as f:
        bridge_abi = f.read()
    eth_bridge_addr = (
        config_data['networks'][eth_net]['bridges'][aergo_net]['addr'])
    # eth oracle
    oracle_abi_path = (
        config_data['networks'][eth_net]['bridges'][aergo_net]['oracle_abi'])
    with open(root_path + oracle_abi_path, "r") as f:
        oracle_abi = f.read()
    eth_oracle_addr = (
        config_data['networks'][eth_net]['bridges'][aergo_net]['oracle'])
    # aergo contracts
    aergo_bridge = (
        config_data['networks'][aergo_net]['bridges'][eth_net]['addr'])
    aergo_oracle = (
        config_data['networks'][aergo_net]['bridges'][eth_net]['oracle'])

    # check validators are correct and warn the validator will vote for
    # a new validator set
    aergo_vals = query_aergo_validators(hera, aergo_oracle)
    eth_vals = query_eth_validators(web3, eth_oracle_addr, oracle_abi)
    logger.info("\"Current Aergo validators : %s\"", aergo_vals)
    logger.info("\"Current Ethereum validators : %s\"", eth_vals)
    # get the current t_anchor and t_final for both sides of bridge
    t_anchor_aergo, t_final_aergo = query_aergo_tempo(hera, aergo_bridge)
    t_anchor_eth, t_final_eth = query_eth_tempo(web3, eth_bridge_addr,
                                                bridge_abi)
    logger.info("\"%s <- %s (t_final=%s) : t_anchor=%s\"", aergo_net, eth_net,
                t_final_aergo, t_anchor_aergo)
    logger.info("\"%s (t_final=%s) -> %s : t_anchor=%s\"", aergo_net,
                t_final_eth, eth_net, t_anchor_eth)

    if auto_update:
        if oracle_update:
            logger.warning(
                "\"WARNING: This validator will vote for updating the oracle\""
            )
        logger.warning(
            "\"WARNING: This validator will vote for settings update in "
            "config.json\"")
        if len(aergo_vals) != len(eth_vals):
            logger.warning(
                "\"WARNING: different number of validators on both sides of "
                "the bridge\"")
        if len(config_data['validators']) != len(aergo_vals):
            logger.warning(
                "\"WARNING: This validator is voting for a new set of aergo "
                "validators\"")
        if len(config_data['validators']) != len(eth_vals):
            logger.warning(
                "\"WARNING: This validator is voting for a new set of eth "
                "validators\"")
        for i, validator in enumerate(config_data['validators']):
            try:
                if validator['addr'] != aergo_vals[i]:
                    logger.warning(
                        "\"WARNING: This validator is voting for a new set of "
                        "aergo validators\"")
            except IndexError:
                # new validators index larger than current validators
                pass
            try:
                if validator['eth-addr'] != eth_vals[i]:
                    logger.warning(
                        "\"WARNING: This validator is voting for a new set of "
                        "eth validators\"")
            except IndexError:
                # new validators index larger than current validators
                pass

        t_anchor_aergo_c = (
            config_data['networks'][aergo_net]['bridges'][eth_net]['t_anchor'])
        t_final_aergo_c = (
            config_data['networks'][aergo_net]['bridges'][eth_net]['t_final'])
        t_anchor_eth_c = (
            config_data['networks'][eth_net]['bridges'][aergo_net]['t_anchor'])
        t_final_eth_c = (
            config_data['networks'][eth_net]['bridges'][aergo_net]['t_final'])
        if t_anchor_aergo_c != t_anchor_aergo:
            logger.warning(
                "\"WARNING: This validator is voting to update anchoring"
                " periode on aergo\"")
        if t_final_aergo_c != t_final_aergo:
            logger.warning(
                "\"WARNING: This validator is voting to update finality of eth"
                " on aergo\"")
        if t_anchor_eth_c != t_anchor_eth:
            logger.warning(
                "\"WARNING: This validator is voting to update anchoring"
                " periode on eth\"")
        if t_final_eth_c != t_final_eth:
            logger.warning(
                "\"WARNING: This validator is voting to update finality of"
                " aergo on eth\"")

    aergo_id = query_aergo_id(hera, aergo_oracle)
    eth_id = query_eth_id(web3, eth_oracle_addr, oracle_abi)

    return aergo_id, eth_id