def verify(self, snapshot: storage.Snapshot, tx: payloads.Transaction) -> bool: """ Verifies the attribute with the transaction Returns: True if verification passes. False otherwise. """ if any( map(lambda signer: signer.scope != payloads.WitnessScope.NONE, tx.signers)): return False if tx.script != self._FIXED_ORACLE_SCRIPT: return False oracle = contracts.native.OracleContract() request = oracle.get_request(snapshot, self.id) if request is None: return False if tx.network_fee + tx.system_fee != request.gas_for_response: return False oracle_account = contracts.Contract.get_consensus_address( contracts.DesignationContract().get_designated_by_role( snapshot, contracts.DesignateRole.ORACLE, snapshot.best_block_height + 1)) return any( map(lambda signer: signer.account == oracle_account, tx.signers))
def test_assign_and_get_role(self): engine = test_engine(has_snapshot=True, has_container=True) # set signers list to our committee to pass check_committee() validation engine.script_container.signers = [ payloads.Signer( types.UInt160.from_string( "54166e586e86b9d653bf96f61e6568df7a8ecb50"), payloads.WitnessScope.GLOBAL) ] public_key1 = cryptography.KeyPair(b'\x01' * 32).public_key public_key2 = cryptography.KeyPair(b'\x02' * 32).public_key public_key3 = cryptography.KeyPair(b'\x03' * 32).public_key c = contracts.DesignationContract() c.designate_as_role(engine, contracts.DesignateRole.STATE_VALIDATOR, [public_key1, public_key2]) c.designate_as_role(engine, contracts.DesignateRole.ORACLE, [public_key3]) index = engine.snapshot.persisting_block.index + 1 state_nodes = c.get_designated_by_role( engine.snapshot, contracts.DesignateRole.STATE_VALIDATOR, index) self.assertEqual(2, len(state_nodes)) self.assertIn(public_key1, state_nodes) self.assertIn(public_key2, state_nodes) oracle_nodes = c.get_designated_by_role(engine.snapshot, contracts.DesignateRole.ORACLE, index) self.assertEqual(1, len(oracle_nodes)) self.assertEqual(public_key3, oracle_nodes[0])
def init(self): self._methods: Dict[int, _NativeMethodMeta] = {} # offset, meta self._management = contracts.ManagementContract() self._neo = contracts.NeoToken() self._gas = contracts.GasToken() self._policy = contracts.PolicyContract() self._oracle = contracts.OracleContract() self._ledger = contracts.LedgerContract() self._role = contracts.DesignationContract() self._crypto = contracts.CryptoContract() self._stdlib = contracts.StdLibContract() # Find all methods that have been augmented by the @register decorator # and turn them into methods that can be called by VM scripts methods_meta = [] for pair in inspect.getmembers(self, lambda m: hasattr(m, "native_call")): methods_meta.append(_NativeMethodMeta(pair[1])) methods_meta.sort( key=lambda x: (x.descriptor.name, len(x.descriptor.parameters))) sb = vm.ScriptBuilder() for meta in methods_meta: meta.descriptor.offset = len(sb) sb.emit_push(0) self._methods.update({len(sb): meta}) sb.emit_syscall(1736177434) # "System.Contract.CallNative" sb.emit(vm.OpCode.RET) self._script: bytes = sb.to_array() self.nef = contracts.NEF("neo-core-v3.0", self._script) sender = types.UInt160.zero() # OpCode.PUSH1 sb = vm.ScriptBuilder() sb.emit(vm.OpCode.ABORT) sb.emit_push(sender.to_array()) sb.emit_push(0) sb.emit_push(self.service_name()) self._hash: types.UInt160 = to_script_hash(sb.to_array()) self._manifest: contracts.ContractManifest = contracts.ContractManifest( ) self._manifest.name = self.service_name() self._manifest.abi.methods = list( map(lambda m: m.descriptor, methods_meta)) if self._id != NativeContract._id: self._contracts.update({self.service_name(): self}) self._contract_hashes.update({self._hash: self}) self.active_block_index = settings.native_contract_activation.get( self.service_name, 0)
def post_persist(self, engine: contracts.ApplicationEngine) -> None: super(OracleContract, self).post_persist(engine) nodes = [] for tx in engine.snapshot.persisting_block.transactions: response = tx.try_get_attribute(payloads.OracleResponse) if response is None: continue # remove request from storage sk_request = self.key_request + response.id.to_bytes(8, 'little') si_request = engine.snapshot.storages.try_get(sk_request) if si_request is None: continue request = OracleRequest.deserialize_from_bytes(si_request.value) engine.snapshot.storages.delete(sk_request) # remove id from id list sk_id_list = self.key_id_list + self._get_url_hash(request.url) si_id_list = engine.snapshot.storages.try_get(sk_id_list, read_only=False) if si_id_list is None: si_id_list = storage.StorageItem(b'\x00') id_list = si_id_list.get(_IdList) id_list.remove(response.id) if len(id_list) == 0: engine.snapshot.storages.delete(sk_id_list) # mint gas for oracle nodes nodes_public_keys = contracts.DesignationContract( ).get_designated_by_role(engine.snapshot, contracts.DesignateRole.ORACLE, engine.snapshot.persisting_block.index) for public_key in nodes_public_keys: nodes.append([ to_script_hash( contracts.Contract.create_signature_redeemscript( public_key)), vm.BigInteger.zero() ]) if len(nodes) > 0: idx = response.id % len(nodes) # mypy can't figure out that the second item is a BigInteger nodes[idx][1] += self.get_price( engine.snapshot) # type: ignore for pair in nodes: if pair[1].sign > 0: # type: ignore self._gas.mint(engine, pair[0], pair[1], False)