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 test_transfer_partial_balance_to_account_with_balance(self): gas = contracts.GasToken() manifest = contracts.ContractManifest("contract_name") nef = contracts.NEF(script=b'\x40') state_to = contracts.ContractState( 1, nef, manifest, 0, contract_hash(types.UInt160.zero(), nef.checksum, manifest.name)) account_to = state_to.hash storage_key_to = gas.key_account + account_to account_to_state = gas._state() account_to_state.balance = vm.BigInteger(100) storage_item_to = storage.StorageItem(account_to_state.to_array()) account_from = types.UInt160(b'\x01' * 20) storage_key_from = gas.key_account + account_from account_from_state = gas._state() account_from_state.balance = vm.BigInteger(123) storage_item_from = storage.StorageItem(account_from_state.to_array()) amount = vm.BigInteger(50) engine = self.transfer_helper(gas, account_from, account_to, amount) # ensure the source and destination account have balances engine.snapshot.storages.put(storage_key_from, storage_item_from) engine.snapshot.storages.put(storage_key_to, storage_item_to) transfer_event = () def notify_listener(contract_script_hash, event, state): nonlocal transfer_event transfer_event = (contract_script_hash, event, state) msgrouter.interop_notify += notify_listener engine.execute() self.assertEqual(1, len(engine.result_stack)) result = engine.result_stack.pop() self.assertTrue(result) self.assertEqual(gas.hash, transfer_event[0]) self.assertEqual("Transfer", transfer_event[1]) state_items = list(transfer_event[2]) self.assertEqual(account_from, types.UInt160(state_items[0].to_array())) self.assertEqual(account_to, types.UInt160(state_items[1].to_array())) self.assertEqual(amount, state_items[2].to_biginteger()) # validate from account is deducted by `amount` new_storage_account_from = engine.snapshot.storages.get( storage_key_from) new_account_state_from = gas._state.deserialize_from_bytes( new_storage_account_from.value) self.assertEqual(account_from_state.balance - amount, new_account_state_from.balance) # validate to account is credited with `amount` new_storage_account_to = engine.snapshot.storages.get(storage_key_to) new_account_state_to = gas._state.deserialize_from_bytes( new_storage_account_to.value) self.assertEqual(account_to_state.balance + amount, new_account_state_to.balance)
def transfer_helper(self, contract: contracts.NativeContract, from_account: types.UInt160, to_account: types.UInt160, amount: vm.BigInteger): 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 engine.invocation_stack.pop() # we no longer need the default script engine.script_container = TestIVerifiable() engine.script_container.script_hashes = [from_account] sb = vm.ScriptBuilder() sb.emit(vm.OpCode.PUSHNULL) sb.emit_push(amount) sb.emit_push(to_account.to_array()) sb.emit_push(from_account.to_array()) sb.emit_push(4) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # callflags sb.emit_push(b'transfer') sb.emit_push(contract.hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) engine.load_script(vm.Script(sb.to_array())) nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") contract_state = contracts.ContractState( 1, nef, manifest, 0, contract_hash(from_account, nef.checksum, manifest.name)) engine.snapshot.contracts.put(contract_state) return engine
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_nef = contracts.NEF(script=callee_contract_script) callee_manifest = contracts.ContractManifest("contract1") callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY, True) ] callee_contract = contracts.ContractState( 1, callee_nef, callee_manifest, 0, contract_hash(types.UInt160.zero(), callee_nef.checksum, callee_manifest.name)) 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_manifest = contracts.ContractManifest("contract2") caller_contract = contracts.ContractState( 2, caller_nef, caller_manifest, 0, contract_hash(types.UInt160.zero(), caller_nef.checksum, caller_manifest.name)) 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 test_transfer_from_empty_account(self): gas = contracts.GasToken() manifest = contracts.ContractManifest("test_contract2") nef = contracts.NEF(script=b'\x40') state = contracts.ContractState( 2, nef, manifest, 0, contract_hash(types.UInt160.zero(), nef.checksum, manifest.name)) engine = self.transfer_helper(gas, types.UInt160.zero(), state.hash, vm.BigInteger(1)) engine.snapshot.contracts.put(state) engine.execute() self.assertEqual(1, len(engine.result_stack)) result = engine.result_stack.pop() self.assertFalse(result)
def test_transfer_full_balance(self): gas = contracts.GasToken() manifest = contracts.ContractManifest("contract_name_to") nef = contracts.NEF(script=b'\x40') state_to = contracts.ContractState( 1, nef, manifest, 0, contract_hash(types.UInt160.zero(), nef.checksum, manifest.name)) account_to = state_to.hash account_from = types.UInt160(b'\x01' * 20) storage_key_from = gas.key_account + account_from account_from_state = gas._state() account_from_state.balance = vm.BigInteger(123) storage_item_from = storage.StorageItem(account_from_state.to_array()) amount = account_from_state.balance engine = self.transfer_helper(gas, account_from, account_to, amount) # ensure the source account has balance engine.snapshot.storages.put(storage_key_from, storage_item_from) transfer_event = () def notify_listener(contract_script_hash, event, state): nonlocal transfer_event transfer_event = (contract_script_hash, event, state) msgrouter.interop_notify += notify_listener engine.execute() self.assertEqual(1, len(engine.result_stack)) result = engine.result_stack.pop() self.assertTrue(result) self.assertEqual(gas.hash, transfer_event[0]) self.assertEqual("Transfer", transfer_event[1]) state_items = list(transfer_event[2]) self.assertEqual(account_from, types.UInt160(state_items[0].to_array())) self.assertEqual(account_to, types.UInt160(state_items[1].to_array())) self.assertEqual(amount, state_items[2].to_biginteger()) # test that the source account is no longer present in storage as the balance is zero self.assertIsNone(engine.snapshot.storages.try_get(storage_key_from))
def test_transfer_more_than_balance(self): gas = contracts.GasToken() account_from = types.UInt160.zero() storage_key_from = gas.key_account + account_from account_state = gas._state() account_state.balance = vm.BigInteger(123) storage_item_from = storage.StorageItem(account_state.to_array()) manifest_to = contracts.ContractManifest("source_contract") nef_to = contracts.NEF(script=b'\x40') state_to = contracts.ContractState( 1, nef_to, manifest_to, 0, contract_hash(types.UInt160.zero(), nef_to.checksum, manifest_to.name)) account_to = state_to.hash amount = account_state.balance + 1 engine = self.transfer_helper(gas, account_from, account_to, amount) # ensure the source account has balance engine.snapshot.storages.put(storage_key_from, storage_item_from) engine.execute() self.assertEqual(1, len(engine.result_stack)) result = engine.result_stack.pop() self.assertFalse(result)
def test_checkwitness_custom_groups(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, default_script=False) tx = test_tx() engine.script_container = tx ''' Create the callee contract, which does a checkwitness on its caller. Checkwitness shall only pass if the caller == "caller_contract" as defined by CustomGroup ''' sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetCallingScriptHash") ) # get script hash of "caller_contract" sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness")) 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(tx.sender, callee_nef.checksum, callee_contract_name) callee_contract = contracts.ContractState(1, callee_nef, callee_manifest, 0, callee_contract_hash) 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) keypair = cryptography.KeyPair(private_key=b'\x01' * 32) signature = cryptography.sign(caller_script, keypair.private_key) caller_manifest.groups = [ contracts.ContractGroup(public_key=keypair.public_key, signature=signature) ] caller_contract_hash = contract_hash(tx.sender, caller_nef.checksum, caller_contract_name) caller_contract = contracts.ContractState(2, caller_nef, caller_manifest, 0, caller_contract_hash) engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS tx.signers[0].allowed_groups = [keypair.public_key] 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()) # now try again but make sure it fails if the public key is not listed in the allowed groups engine = test_engine(has_snapshot=True, default_script=False) tx = test_tx() engine.script_container = tx engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS keypair = cryptography.KeyPair(private_key=b'\x02' * 32) tx.signers[0].allowed_groups = [keypair.public_key] engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertFalse(item.to_boolean())