def get_tempo( self, hera: herapy.Aergo, aergo_from: str, aergo_to: str, oracle_to: str, id_to: str, tempo_msg, tempo_str, tempo_id, current_tempo, ): # 1 - check destination nonce is correct nonce = int( hera.query_sc_state( oracle_to, ["_sv__nonce"]).var_proofs[0].value ) if nonce != tempo_msg.destination_nonce: err_msg = ("Incorrect Nonce, got: {}, expected: {}" .format(tempo_msg.destination_nonce, nonce)) logger.warning( error_log_template, self.validator_index, "false", "\u231B " + tempo_str, aergo_to, err_msg ) return Approval(error=err_msg) config_data = self.load_config_data() tempo = (config_data['networks'][aergo_to]['bridges'] [aergo_from][tempo_str]) # 2 - check new tempo is different from current one to prevent # update spamming if current_tempo == tempo: err_msg = "Not voting for a new {}".format(tempo_str) logger.warning( error_log_template, self.validator_index, "false", "\u231B " + tempo_str, aergo_to, err_msg ) return Approval(error=err_msg) # 3 - check tempo matches the one in config if tempo != tempo_msg.tempo: err_msg = ("Invalid {}, got: {}, expected: {}" .format(tempo_str, tempo_msg.tempo, tempo)) logger.warning( error_log_template, self.validator_index, "false", "\u231B " + tempo_str, aergo_to, err_msg ) return Approval(error=err_msg) # sign anchor and return approval msg = bytes( str(tempo) + str(nonce) + id_to + tempo_id, 'utf-8' ) h = hashlib.sha256(msg).digest() sig = hera.account.private_key.sign_msg(h) approval = Approval(address=self.address, sig=sig) logger.info( success_log_template, self.validator_index, "true", "\u231B " + tempo_str, aergo_to, tempo_msg.tempo, tempo_msg.destination_nonce ) return approval
def get_validators( self, hera: herapy.Aergo, oracle_to: str, id_to: str, aergo_to, val_msg, ): # 1 - check destination nonce is correct nonce = int( hera.query_sc_state( oracle_to, ["_sv__nonce"]).var_proofs[0].value ) if nonce != val_msg.destination_nonce: err_msg = ("Incorrect Nonce, got: {}, expected: {}" .format(val_msg.destination_nonce, nonce)) logger.warning( error_log_template, self.validator_index, "false", "\U0001f58b validator set", aergo_to, err_msg ) return Approval(error=err_msg) config_data = self.load_config_data() config_vals = [val['addr'] for val in config_data['validators']] # 2 - check new validators are different from current ones to prevent # update spamming current_validators = query_validators(hera, oracle_to) if current_validators == config_vals: err_msg = "Not voting for a new validator set" logger.warning( error_log_template, self.validator_index, "false", "\U0001f58b validator set", aergo_to, err_msg ) return Approval(error=err_msg) # 3 - check validators are same in config file if config_vals != val_msg.validators: err_msg = ("Invalid validator set, got: {}, expected: {}" .format(val_msg.validators, config_vals)) logger.warning( error_log_template, self.validator_index, "false", "\U0001f58b validator set", aergo_to, err_msg ) return Approval(error=err_msg) # sign validators data = "" for val in config_vals: data += val data += str(nonce) + id_to + "V" data_bytes = bytes(data, 'utf-8') h = hashlib.sha256(data_bytes).digest() sig = hera.account.private_key.sign_msg(h) approval = Approval(address=self.address, sig=sig) logger.info( success_log_template, self.validator_index, "true", "\U0001f58b validator set", aergo_to, val_msg.validators, val_msg.destination_nonce ) return approval
def get_oracle(self, hera: herapy.Aergo, aergo_from: str, aergo_to: str, oracle_to: str, id_to: str, bridge_to: str, oracle_msg): """Get a vote(signature) from the validator to update the oracle controlling the bridge contract """ # 1 - check destination nonce is correct nonce = int( hera.query_sc_state(oracle_to, ["_sv__nonce"]).var_proofs[0].value) if nonce != oracle_msg.destination_nonce: err_msg = ("Incorrect Nonce, got: {}, expected: {}".format( oracle_msg.destination_nonce, nonce)) logger.warning(error_log_template, self.validator_index, "false", "\U0001f58b oracle change", aergo_to, err_msg) return Approval(error=err_msg) config_data = self.load_config_data() config_oracle = \ config_data['networks'][aergo_to]['bridges'][aergo_from]['oracle'] # 2 - check new oracle is different from current one to prevent # update spamming current_oracle = query_oracle(hera, bridge_to) if current_oracle == config_oracle: err_msg = "Not voting for a new oracle" logger.warning(error_log_template, self.validator_index, "false", "\U0001f58b oracle change", aergo_to, err_msg) return Approval(error=err_msg) # 3 - check validators are same in config file if config_oracle != oracle_msg.oracle: err_msg = ("Invalid oracle, got: {}, expected: {}".format( oracle_msg.oracle, config_oracle)) logger.warning(error_log_template, self.validator_index, "false", "\U0001f58b oracle change", aergo_to, err_msg) return Approval(error=err_msg) # sign validators data = oracle_msg.oracle \ + str(oracle_msg.destination_nonce) + id_to + "O" data_bytes = bytes(data, 'utf-8') h = hashlib.sha256(data_bytes).digest() sig = hera.account.private_key.sign_msg(h) approval = Approval(address=self.address, sig=sig) logger.info(success_log_template, self.validator_index, "true", "\U0001f58b oracle change", aergo_to, "\"{}\"".format(oracle_msg.oracle), oracle_msg.destination_nonce) return approval
def GetValidatorsSignature(self, val_msg, context): if not (self.auto_update and self.oracle_update): return Approval(error="Oracle validators update not enabled") if val_msg.is_from_mainnet: return self.get_validators(self.hera2, self.oracle2, self.id2, self.aergo2, val_msg) else: return self.get_validators(self.hera1, self.oracle1, self.id1, self.aergo2, val_msg)
def GetAnchorSignature(self, anchor, context): """ Verifies the anchors are valid and signes them aergo1 and aergo2 must be trusted. """ if not self.anchoring_on: return Approval(error="Anchoring not enabled") destination = "" bridge_id = "" if anchor.is_from_mainnet: # aergo1 is considered to be mainnet side of bridge err_msg = self.is_valid_anchor( anchor, self.hera1, self.hera2, self.oracle2) destination = self.aergo2 bridge_id = self.id2 else: err_msg = self.is_valid_anchor( anchor, self.hera2, self.hera1, self.oracle1) destination = self.aergo1 bridge_id = self.id1 if err_msg is not None: logger.warning( error_log_template, self.validator_index, "false", "\u2693 anchor", destination, err_msg ) return Approval(error=err_msg) # sign anchor and return approval msg = bytes( anchor.root + ',' + str(anchor.height) + str(anchor.destination_nonce) + bridge_id + "R", 'utf-8' ) h = hashlib.sha256(msg).digest() sig = self.hera1.account.private_key.sign_msg(h) approval = Approval(address=self.address, sig=sig) logger.info( success_log_template, self.validator_index, "true", "\u2693 anchor", destination, "{{\"root\": \"0x{}\", \"height\": {}}}" .format(anchor.root, anchor.height), anchor.destination_nonce ) return approval
def GetOracleSignature(self, oracle_msg, context): if not (self.auto_update and self.oracle_update): return Approval(error="Oracle update not enabled") if oracle_msg.is_from_mainnet: return self.get_oracle(self.hera2, self.aergo1, self.aergo2, self.oracle2, self.id2, self.bridge2, oracle_msg) else: return self.get_oracle(self.hera1, self.aergo2, self.aergo1, self.oracle1, self.id1, self.bridge1, oracle_msg)
def GetTFinalSignature(self, tempo_msg, context): """Get a vote(signature) from the validator to update the t_final setting in the Aergo bridge contract """ if not self.auto_update: return Approval(error="Setting update not enabled") if tempo_msg.is_from_mainnet: current_tempo = query_tempo(self.hera2, self.oracle2, ["_sv__tFinal"]) return self.get_tempo(self.hera2, self.aergo1, self.aergo2, self.oracle2, self.id2, tempo_msg, 't_final', "F", current_tempo) else: current_tempo = query_tempo(self.hera1, self.oracle1, ["_sv__tFinal"]) return self.get_tempo(self.hera1, self.aergo2, self.aergo1, self.oracle1, self.id1, tempo_msg, 't_final', "F", current_tempo)