def current_scripthash(self) -> types.UInt160: """ Get the script hash of the current executing smart contract Note: a smart contract can call other smart contracts. """ return to_script_hash(self.current_context.script._value)
def post_persist(self, engine: contracts.ApplicationEngine): super(NeoToken, self).post_persist(engine) # distribute GAS for committee m = len(settings.standby_committee) n = settings.network.validators_count index = engine.snapshot.persisting_block.index % m gas_per_block = self.get_gas_per_block(engine.snapshot) committee = self.get_committee_from_cache(engine.snapshot) pubkey = committee[index] account = to_script_hash(contracts.Contract.create_signature_redeemscript(pubkey)) GasToken().mint(engine, account, gas_per_block * self._COMMITTEE_REWARD_RATIO / 100, False) if self._should_refresh_committee(engine.snapshot.persisting_block.index): voter_reward_of_each_committee = gas_per_block * self._VOTER_REWARD_RATIO * 100000000 * m / (m + n) / 100 for i, member in enumerate(committee): factor = 2 if i < n else 1 member_votes = self._committee_state[member] if member_votes > 0: voter_sum_reward_per_neo = voter_reward_of_each_committee * factor / member_votes voter_reward_key = (self.key_voter_reward_per_committee + member + self._to_uint32(engine.snapshot.persisting_block.index + 1) ) border = (self.key_voter_reward_per_committee + member).to_array() try: pair = next(engine.snapshot.storages.find_range(voter_reward_key.to_array(), border, "reverse")) result = vm.BigInteger(pair[1].value) except StopIteration: result = vm.BigInteger.zero() voter_sum_reward_per_neo += result engine.snapshot.storages.put(voter_reward_key, storage.StorageItem(voter_sum_reward_per_neo.to_array()))
def get_committee_address(self, snapshot: storage.Snapshot) -> types.UInt160: """ Get the script hash of the current committee """ comittees = self.get_committee(snapshot) return to_script_hash( contracts.Contract.create_multisig_redeemscript( len(comittees) - (len(comittees) - 1) // 2, comittees))
def test_storage_get_key_not_found(self): engine = test_engine(has_snapshot=True, has_container=True) script = vm.ScriptBuilder() # key parameter for the `Storage.Get` syscall script.emit(vm.OpCode.PUSH2) script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) # at this point our stack looks like follows # * storage context # * key script.emit_syscall(syscall_name_to_int("System.Storage.Get")) engine.load_script(vm.Script(script.to_array())) # we have to store our contract or some sanity checks will fail (like getting a StorageContext nef = contracts.NEF(script=script.to_array()) contract = contracts.ContractState(1, nef, self.manifest, 0, to_script_hash(nef.script)) engine.snapshot.contracts.put(contract) storage_key = storage.StorageKey(contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.NullStackItem)
def test_storage_put_new(self): # see `test_storage_get_key_not_found()` for a description on why the storage is setup with a script as is # setup engine = test_engine(has_snapshot=True) script = vm.ScriptBuilder() script.emit(vm.OpCode.PUSH2) # storage put value script.emit(vm.OpCode.PUSH1) # storage put key script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) script.emit_syscall(syscall_name_to_int("System.Storage.Put")) engine.load_script(vm.Script(script.to_array())) nef = contracts.NEF(script=script.to_array()) manifest = contracts.ContractManifest(f"contractname1") manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY, True) ] hash_ = to_script_hash(nef.script) contract = contracts.ContractState(1, nef, manifest, 0, hash_) engine.snapshot.contracts.put(contract) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) storage_key = storage.StorageKey(1, b'\x01') item = engine.snapshot.storages.try_get(storage_key) self.assertIsNotNone(item) self.assertEqual(b'\x02', item.value)
def test_policy_unblock_account(self): # we've tested the full round trip via "System.Contract.Call" in the test # test_policy_set_and_get_blocked_accounts() # Here we take the shortcut and test the unblock account function directly engine = test_engine(has_snapshot=True) block = test_block(0) engine.snapshot.persisting_block = block engine.invoke_syscall_by_name("Neo.Native.Deploy") # we must add a script_container with valid signature to pass the check_comittee() validation check # in the function itself engine.script_container = TestIVerifiable() validator = settings.standby_committee[0] script_hash = to_script_hash( contracts.Contract.create_multisig_redeemscript(1, [validator])) engine.script_container.script_hashes = [script_hash] policy = contracts.PolicyContract() account_not_found = types.UInt160(data=b'\x11' * 20) account = types.UInt160.zero() self.assertTrue(policy._block_account(engine, account)) self.assertFalse(policy._unblock_account(engine, account_not_found)) self.assertTrue(policy._unblock_account(engine, account)) storage_key = storage.StorageKey(policy.script_hash, policy._PREFIX_BLOCKED_ACCOUNTS) storage_item = engine.snapshot.storages.try_get(storage_key) self.assertIsNotNone(storage_item) self.assertEqual(b'\x00', storage_item.value)
def test_storage_get_ok2(self): # this is basically the same as `test_storage_get_ok` # but performed by executing a script # it exists to validate that the `Optional[bytes]` return value is converted properly engine = test_engine(has_snapshot=True) script = vm.ScriptBuilder() script.emit(vm.OpCode.PUSH1) script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) script.emit_syscall(syscall_name_to_int("System.Storage.Get")) engine.load_script(vm.Script(script.to_array())) nef = contracts.NEF(script=script.to_array()) contract_hash = to_script_hash(nef.script) contract = contracts.ContractState(1, nef, self.manifest, 0, contract_hash) engine.snapshot.contracts.put(contract) storage_key = storage.StorageKey(contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(storage_item.value, item.to_array())
def register_candidate(self, engine: contracts.ApplicationEngine, public_key: cryptography.ECPoint) -> bool: """ Register a candidate for consensus node election. Args: engine: Application engine instance public_key: the candidate's public key Returns: True is succesfully registered. False otherwise. """ script_hash = to_script_hash( contracts.Contract.create_signature_redeemscript(public_key)) if not engine.checkwitness(script_hash): return False engine.add_gas(self.get_register_price(engine.snapshot)) storage_key = self.key_candidate + public_key storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: state = _CandidateState() state.registered = True storage_item = storage.StorageItem(state.to_array()) engine.snapshot.storages.put(storage_key, storage_item) else: state = storage_item.get(_CandidateState) state.registered = True self._candidates_dirty = True return True
def __init__(self, password: str, private_key: Optional[bytes] = None, watch_only: bool = False, address: Optional[str] = None, label: Optional[str] = None, lock: bool = False, contract: Optional[contracts.Contract] = None, extra: Optional[Dict[str, Any]] = None): """ Instantiate an account. This constructor should only be directly called when it's desired to create a new account using just a password and a randomly generated private key, otherwise use the alternative constructors """ public_key: Optional[cryptography.ECPoint] = None encrypted_key: Optional[bytes] = None contract_script: Optional[bytes] = None if watch_only: if address is None: raise ValueError( "Creating a watch only account requires an address") else: self.validate_address(address) else: key_pair: cryptography.KeyPair if private_key is None: key_pair = cryptography.KeyPair.generate() private_key = key_pair.private_key else: key_pair = cryptography.KeyPair(private_key) encrypted_key = self.private_key_to_nep2(private_key, password) contract_script = contracts.Contract.create_signature_redeemscript( key_pair.public_key) script_hash = to_script_hash(contract_script) address = address if address else self.script_hash_to_address( script_hash) public_key = key_pair.public_key self.label: Optional[str] = label self.address: str = address self.public_key = public_key self.encrypted_key = encrypted_key self.lock = lock if not isinstance(contract, AccountContract): if contract is not None: contract = AccountContract.from_contract(contract) elif contract_script is not None: default_parameters_list = [ contracts.ContractParameterDefinition( name='signature', type=contracts.ContractParameterType.SIGNATURE) ] contract = AccountContract(contract_script, default_parameters_list) self.contract: Optional[AccountContract] = contract self.extra = extra if extra else {}
def unregister_candidate(self, engine: contracts.ApplicationEngine, public_key: cryptography.ECPoint) -> bool: """ Remove a candidate from the consensus node candidate list. Args: engine: Application engine instance public_key: the candidate's public key Returns: True is succesfully removed. False otherwise. """ script_hash = to_script_hash( contracts.Contract.create_signature_redeemscript(public_key)) if not engine.checkwitness(script_hash): return False storage_key = self.key_candidate + public_key storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: return True else: state = storage_item.get(_CandidateState) state.registered = False if state.votes == 0: engine.snapshot.storages.delete(storage_key) self._candidates_dirty = True return True
def __init__(self, script: bytes, parameter_list: List[contracts.ContractParameterType]): #: The contract instructions (OpCodes) self.script = script self.parameter_list = parameter_list self._script_hash = to_script_hash(self.script) self._address = None
def entry_scripthash(self) -> types.UInt160: """ Get the script hash of the first smart contract loaded into the engine Note: a smart contract can call other smart contracts. """ return to_script_hash(self.entry_context.script._value)
def contract_hash(sender: types.UInt160, checksum: int, name: str) -> types.UInt160: sb = vm.ScriptBuilder() sb.emit(vm.OpCode.ABORT) sb.emit_push(sender.to_array()) sb.emit_push(checksum) sb.emit_push(name) return to_script_hash(sb.to_array())
def load_context(self, context: vm.ExecutionContext) -> None: if len(context.scripthash_bytes) == 0: context.scripthash_bytes = to_script_hash(context.script._value).to_array() contract_hash = types.UInt160(data=context.scripthash_bytes) counter = self._invocation_counter.get(contract_hash, 0) self._invocation_counter.update({contract_hash: counter + 1}) super(ApplicationEngine, self).load_context(context)
def test_checkwitness_called_by_entry(self): """ We need to setup 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract 2) callee_contract: uses a System.Runtime.CheckWitness """ engine = test_engine(has_snapshot=True, has_container=False, default_script=False) tx = test_tx() tx.signers[0].scope = payloads.WitnessScope.CALLED_BY_ENTRY engine.script_container = tx sb = vm.ScriptBuilder() sb.emit_push(tx.sender.to_array()) sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness")) callee_contract_script = sb.to_array() callee_manifest = contracts.ContractManifest( contract_hash=to_script_hash(callee_contract_script)) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY) ] callee_contract = storage.ContractState(callee_contract_script, callee_manifest) sb = vm.ScriptBuilder() sb.emit(vm.OpCode.NEWARRAY0) # args (empty array) sb.emit_push('test_func') # target method name sb.emit_push(callee_contract.script_hash().to_array()) # contract hash sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) caller_script = sb.to_array() caller_manifest = contracts.ContractManifest( contract_hash=to_script_hash(caller_script)) caller_contract = storage.ContractState(caller_script, caller_manifest) engine.snapshot.contracts.put(callee_contract) engine.snapshot.contracts.put(caller_contract) engine.load_script(vm.Script(caller_script)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertTrue(item.to_boolean())
def on_persist(self, engine: contracts.ApplicationEngine) -> None: super(GasToken, self).on_persist(engine) total_network_fee = 0 for tx in engine.snapshot.persisting_block.transactions: total_network_fee += tx.network_fee self.burn(engine, tx.sender, vm.BigInteger(tx.system_fee + tx.network_fee)) pub_keys = NeoToken().get_next_block_validators(engine.snapshot) primary = pub_keys[engine.snapshot.persisting_block.primary_index] script_hash = to_script_hash(contracts.Contract.create_signature_redeemscript(primary)) self.mint(engine, script_hash, vm.BigInteger(total_network_fee), False)
def get_script_hashes_for_verifying( self, snapshot: storage.Snapshot) -> List[types.UInt160]: validators = contracts.NeoToken().get_next_block_validators(snapshot) if len(validators) < self.validator_index: raise ValueError("Validator index is out of range") return [ to_script_hash( contracts.Contract.create_signature_redeemscript( validators[self.validator_index])) ]
def setUpClass(cls) -> None: settings.network.standby_committee = ['02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765'] settings.network.validators_count = 1 cls.validator_public_key = cryptography.ECPoint.deserialize_from_bytes( binascii.unhexlify(settings.network.standby_committee[0]) ) cls.validator_account = to_script_hash( contracts.Contract.create_multisig_redeemscript(1, [cls.validator_public_key])) blockchain.Blockchain()
def private_key_to_nep2( private_key: bytes, passphrase: str, scrypt_parameters: Optional[wallet.ScryptParameters] = None ) -> bytes: """ Encrypt a private key into a nep2 key. Args: private_key: the key that will be encrypt. passphrase: the password to encrypt the nep2 key. scrypt_parameters: a ScryptParameters object that will be passed to the key derivation function. Returns: the encrypted nep2 key. """ if scrypt_parameters is None: scrypt_parameters = wallet.ScryptParameters() key_pair = cryptography.KeyPair(private_key=private_key) script_hash = to_script_hash( contracts.Contract.create_signature_redeemscript( key_pair.public_key)) address = Account.script_hash_to_address(script_hash) # NEP2 checksum: hash the address twice and get the first 4 bytes first_hash = hashlib.sha256(address.encode("utf-8")).digest() second_hash = hashlib.sha256(first_hash).digest() checksum = second_hash[:4] pwd_normalized = bytes(unicodedata.normalize("NFC", passphrase), "utf-8") derived = hashlib.scrypt(password=pwd_normalized, salt=checksum, n=scrypt_parameters.n, r=scrypt_parameters.r, p=scrypt_parameters.p, dklen=64) derived1 = derived[:32] derived2 = derived[32:] xor_ed = Account._xor_bytes(bytes(private_key), derived1) cipher = AES.new(derived2, AES.MODE_ECB) encrypted = cipher.encrypt(xor_ed) nep2 = bytearray() nep2.extend(NEP_HEADER) nep2.extend(NEP_FLAG) nep2.extend(checksum) nep2.extend(encrypted) # Finally, encode with Base58Check encoded_nep2 = base58.b58encode_check(bytes(nep2)) return encoded_nep2
def test_getcallingscripthash(self): """ Testing this requires 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract 2) callee_contract: uses a System.Runtime.GetCallingScriptHash to return the calling script """ sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetCallingScriptHash")) callee_contract_script = sb.to_array() callee_manifest = contracts.ContractManifest( contract_hash=to_script_hash(callee_contract_script)) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY) ] callee_contract = storage.ContractState(callee_contract_script, callee_manifest) # create caller_contract script sb = vm.ScriptBuilder() sb.emit(vm.OpCode.NEWARRAY0) # args (empty array) sb.emit_push('test_func') # target method name sb.emit_push(callee_contract.script_hash().to_array()) # contract hash sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) caller_script = sb.to_array() caller_manifest = contracts.ContractManifest( contract_hash=to_script_hash(caller_script)) caller_contract = storage.ContractState(caller_script, caller_manifest) engine = test_engine(has_snapshot=True, default_script=False) engine.snapshot.contracts.put(callee_contract) engine.snapshot.contracts.put(caller_contract) engine.load_script(vm.Script(caller_script)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(caller_contract.script_hash().to_array(), item.to_array())
def test_get_invocation_counter_ok(self): """ We need to setup 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will increase the invocation counter of the callee contract 2) callee_contract: uses a System.Runtime.GetInvocationCounter """ engine = test_engine(has_snapshot=True, has_container=False, default_script=False) sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetInvocationCounter")) callee_contract_script = sb.to_array() callee_manifest = contracts.ContractManifest( contract_hash=to_script_hash(callee_contract_script)) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY) ] callee_contract = storage.ContractState(callee_contract_script, callee_manifest) sb = vm.ScriptBuilder() sb.emit(vm.OpCode.NEWARRAY0) # args (empty array) sb.emit_push('test_func') # target method name sb.emit_push(callee_contract.script_hash().to_array()) # contract hash sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) caller_script = sb.to_array() caller_manifest = contracts.ContractManifest( contract_hash=to_script_hash(caller_script)) caller_contract = storage.ContractState(caller_script, caller_manifest) engine.snapshot.contracts.put(callee_contract) engine.snapshot.contracts.put(caller_contract) engine.load_script(vm.Script(caller_script)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(1, int(item))
def do_checkwitness(engine: contracts.ApplicationEngine, data: bytes) -> bool: if len(data) == 20: hash_ = types.UInt160(data) elif len(data) == 33: redeemscript = contracts.Contract.create_signature_redeemscript( cryptography.ECPoint.deserialize_from_bytes(data)) hash_ = to_script_hash(redeemscript) else: raise ValueError("Supplied CheckWitness data is not a valid hash") return engine.checkwitness(hash_)
def contract_create_with_data( self, engine: contracts.ApplicationEngine, nef_file: bytes, manifest: bytes, data: vm.StackItem) -> contracts.ContractState: if not isinstance(engine.script_container, payloads.Transaction): raise ValueError( "Cannot create contract without a Transaction script container" ) nef_len = len(nef_file) manifest_len = len(manifest) if (nef_len == 0 or nef_len > engine.MAX_CONTRACT_LENGTH or manifest_len == 0 or manifest_len > contracts.ContractManifest.MAX_LENGTH): raise ValueError("Invalid NEF or manifest length") engine.add_gas( max(engine.STORAGE_PRICE * (nef_len + manifest_len), self.get_minimum_deployment_fee(engine.snapshot))) nef = contracts.NEF.deserialize_from_bytes(nef_file) parsed_manifest = contracts.ContractManifest.from_json( json.loads(manifest.decode())) self.validate(nef.script, parsed_manifest.abi) sb = vm.ScriptBuilder() sb.emit(vm.OpCode.ABORT) sb.emit_push(engine.script_container.sender.to_array()) sb.emit_push(nef.checksum) sb.emit_push(parsed_manifest.name) hash_ = to_script_hash(sb.to_array()) existing_contract = engine.snapshot.contracts.try_get(hash_) if existing_contract is not None: raise ValueError("Contract already exists") contract = contracts.ContractState( self.get_next_available_id(engine.snapshot), nef, parsed_manifest, 0, hash_) if not contract.manifest.is_valid(hash_): raise ValueError("Error: invalid manifest") engine.snapshot.contracts.put(contract) method_descriptor = contract.manifest.abi.get_method("_deploy", 2) if method_descriptor is not None: engine.call_from_native(self.hash, hash_, method_descriptor.name, [data, vm.BooleanStackItem(False)]) msgrouter.interop_notify( self.hash, "Deploy", vm.ArrayStackItem(engine.reference_counter, vm.ByteStringStackItem( contract.hash.to_array()))) return contract
def setUp(self) -> None: self.RET = b'\x40' self.manifest = contracts.ContractManifest("contract_name") self.nef = contracts.NEF(script=self.RET) self.contract_hash = to_script_hash(self.nef.script) self.contract = contracts.ContractState(1, self.nef, self.manifest, 0, self.contract_hash) self.contract.manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY, True) ]
def test_contract_create_standard_account(self): keypair = cryptography.KeyPair(b'\x01' * 32) engine = test_engine() engine.push(vm.ByteStringStackItem(keypair.public_key.to_array())) engine.invoke_syscall_by_name("System.Contract.CreateStandardAccount") engine.execute() self.assertEqual(1, len(engine.result_stack)) signature_redeem_script = contracts.Contract.create_signature_redeemscript( keypair.public_key) result_item = types.UInt160(engine.result_stack.pop().to_array()) self.assertEqual(to_script_hash(signature_redeem_script), result_item)
def calling_scripthash(self) -> types.UInt160: """ Get the script hash of the smart contract that called the current executing smart contract. Note: a smart contract can call other smart contracts. Raises: ValueError: if the current executing contract has not been called by another contract. """ if len(self.current_context.calling_script) == 0: raise ValueError("Cannot retrieve calling script_hash - current context has not yet been called") return to_script_hash(self.current_context.calling_script._value)
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 test_policy_block_account_and_is_blocked(self): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block sb = vm.ScriptBuilder() # set or we won't pass the check_comittee() in the policy contract function implementations engine.script_container = TestIVerifiable() validator = settings.standby_committee[0] script_hash = to_script_hash( contracts.Contract.create_multisig_redeemscript(1, [validator])) engine.script_container.script_hashes = [script_hash] # first we setup the stack for calling `blockAccount` # push data to create a vm.Array holding 20 bytes for the UInt160 Account parameter of the _block_account function. sb.emit_push(b'\x11' * 20) sb.emit(vm.OpCode.PUSH1) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # call flags sb.emit_push("blockAccount") sb.emit_push(contracts.PolicyContract().hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) # next we call `isBlocked` sb.emit_push(b'\x11' * 20) sb.emit(vm.OpCode.PUSH1) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # call flags sb.emit_push("isBlocked") sb.emit_push(contracts.PolicyContract().hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) script = vm.Script(sb.to_array()) engine.load_script(script) # storing the current script in a contract otherwise "System.Contract.Call" will fail its checks nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") sender = engine.script_container.script_hashes[0] contract = contracts.ContractState( 1, nef, manifest, 0, contract_hash(sender, nef.checksum, manifest.name)) engine.snapshot.contracts.put(contract) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(2, len(engine.result_stack)) get_is_blocked_result = engine.result_stack.pop() set_blocked_account_result = engine.result_stack.pop() self.assertTrue(set_blocked_account_result.to_boolean()) self.assertTrue(get_is_blocked_result.to_boolean())
def test_getcallingscripthash(self): """ Testing this requires 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract 2) callee_contract: uses a System.Runtime.GetCallingScriptHash to return the calling script """ sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetCallingScriptHash")) callee_contract_script = sb.to_array() callee_nef = contracts.NEF(script=callee_contract_script) callee_contract_name = "callee_contract" callee_manifest = contracts.ContractManifest(callee_contract_name) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY, True) ] callee_contract_hash = contract_hash(types.UInt160.zero(), callee_nef.checksum, callee_contract_name) callee_contract = contracts.ContractState(1, callee_nef, callee_manifest, 0, callee_contract_hash) # create caller_contract script sb = vm.ScriptBuilder() sb.emit_dynamic_call(callee_contract.hash, "test_func") caller_script = sb.to_array() caller_nef = contracts.NEF(script=caller_script) caller_contract_name = "caller_contract" caller_manifest = contracts.ContractManifest(caller_contract_name) caller_contract_hash = contract_hash(types.UInt160.zero(), caller_nef.checksum, caller_contract_name) caller_contract = contracts.ContractState(2, caller_nef, caller_manifest, 0, caller_contract_hash) engine = test_engine(has_snapshot=True, default_script=False) engine.snapshot.contracts.put(callee_contract) engine.snapshot.contracts.put(caller_contract) engine.load_script(vm.Script(caller_script)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual( to_script_hash(caller_nef.script).to_array(), item.to_array())
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)