def test_getscriptcontainer(self): # first test against an invalid script container (IVerifiable, but not IOperable) engine = test_engine() container = payloads.Header._serializable_init() engine.script_container = container with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.GetScriptContainer") self.assertEqual("script container is not a valid IInteroperable type", str(context.exception)) tx = test_tx(1) engine = test_engine() engine.script_container = tx sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetScriptContainer")) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack._items)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.ArrayStackItem) # we now have a Block that has been serialized, let's check the hash self.assertEqual(vm.ByteStringStackItem(tx.hash().to_array()), item[0])
def test_itoa(self): engine = test_engine(has_snapshot=True) original_item = 100 base = 10 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "itoa", [original_item, base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.pop() self.assertEqual('100', item.to_array().decode('utf-8')) engine = test_engine(has_snapshot=True) base = 16 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "itoa", [original_item, base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.pop() self.assertEqual('64', item.to_array().decode('utf-8')) engine = test_engine(has_snapshot=True) invalid_base = 2 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "itoa", [original_item, invalid_base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.FAULT, engine.state) self.assertIn("Invalid base specified", engine.exception_message)
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_storage_find(self): # settings.storage.default_provider = 'leveldb' engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key1 = storage.StorageKey(self.contract.id, b'\x01') storage_item1 = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key1, storage_item1) storage_key2 = storage.StorageKey(self.contract.id, b'\x02') storage_item2 = storage.StorageItem(b'\x22') engine.snapshot.storages.put(storage_key2, storage_item2) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.IntegerStackItem(contracts.FindOptions.NONE)) engine.push(vm.ByteStringStackItem(storage_key1.key)) engine.push(vm.StackItem.from_interface(ctx)) it = engine.invoke_syscall_by_name("System.Storage.Find") self.assertIsInstance(it, interop.StorageIterator) with self.assertRaises(ValueError) as context: it.value() self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception)) self.assertTrue(it.next()) struct = it.value() # 0 key, 1 value self.assertEqual(storage_item1.value, struct[1].to_array())
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 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 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_checkwitness_invalid_data(self): engine = test_engine() engine.push(vm.ByteStringStackItem(b'')) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.CheckWitness") self.assertEqual("Supplied CheckWitness data is not a valid hash", str(context.exception))
def test_iterator_create_from_map(self): engine = test_engine() map_item = vm.MapStackItem(engine.reference_counter) key1 = vm.IntegerStackItem(1) key2 = vm.IntegerStackItem(3) item1 = vm.IntegerStackItem(2) item2 = vm.IntegerStackItem(4) map_item[key1] = item1 map_item[key2] = item2 engine.push(map_item) r = engine.invoke_syscall_by_name("System.Iterator.Create") self.assertIsInstance(r, MapWrapper) self.assertTrue(r.next()) value = r.value() self.assertIsInstance(value, vm.StructStackItem) self.assertEqual(2, len(value)) self.assertEqual(key1, value[0]) self.assertEqual(item1, value[1]) self.assertTrue(r.next()) value = r.value() self.assertIsInstance(value, vm.StructStackItem) self.assertEqual(2, len(value)) self.assertEqual(key2, value[0]) self.assertEqual(item2, value[1]) # exhausted the iterator self.assertFalse(r.next()) with self.assertRaises(ValueError) as context: r.value() self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception))
def test_gettrigger(self): engine = test_engine() engine.invoke_syscall_by_name("System.Runtime.GetTrigger") item = engine.pop() self.assertIsInstance(item, vm.IntegerStackItem) self.assertEqual( vm.IntegerStackItem(contracts.TriggerType.APPLICATION.value), item)
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 test_contract_call(self): engine = test_engine(has_snapshot=True, default_script=False) # current executing contract fake_hash = types.UInt160.deserialize_from_bytes(b'\x01' * 20) contract = contracts.ContractState(0, hello_world_nef, hello_world_manifest, 0, fake_hash) engine.snapshot.contracts.put(contract) # target contract fake_hash2 = types.UInt160.deserialize_from_bytes(b'\x02' * 20) target_contract = contracts.ContractState(1, contract3_nef, contract3_manifest, 0, fake_hash2) engine.snapshot.contracts.put(target_contract) engine.load_script(vm.Script(contract.script)) array = vm.ArrayStackItem(engine.reference_counter) array.append(vm.IntegerStackItem(3)) engine.push(array) # args engine.push(vm.IntegerStackItem(15)) # callflags engine.push(vm.ByteStringStackItem("test_func2")) # method engine.push(vm.ByteStringStackItem(target_contract.hash.to_array())) engine.invoke_syscall_by_name("System.Contract.Call") engine.execute() self.assertEqual(2, len(engine.result_stack)) main_contract_return_value = engine.result_stack.pop() syscall_called_contract_return_value = engine.result_stack.pop() self.assertEqual("hello world", main_contract_return_value.to_array().decode()) self.assertEqual(4, int(syscall_called_contract_return_value))
def test_gettime(self): engine = test_engine(has_container=False, has_snapshot=True) b = test_block() engine.snapshot.persisting_block = b engine.invoke_syscall_by_name("System.Runtime.GetTime") item = engine.pop() self.assertIsInstance(item, vm.IntegerStackItem) self.assertEqual(vm.IntegerStackItem(b.timestamp), item)
def test_as_readonly(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") self.assertFalse(ctx.is_read_only) engine.push(vm.StackItem.from_interface(ctx)) ctx = engine.invoke_syscall_by_name("System.Storage.AsReadOnly") self.assertTrue(ctx.is_read_only)
def test_checkwitness_helper_other_verifiable(self): engine = test_engine(has_snapshot=True, has_container=False, default_script=True) engine.script_container = TestIVerifiable() self.assertFalse(engine.checkwitness(types.UInt160(b'\x01' * 20))) # our test verifiable has 1 verifiable with a UInt160.zero() hash self.assertTrue(engine.checkwitness(types.UInt160.zero()))
def test_iterator_create_invalid_type(self): engine = test_engine() item = vm.NullStackItem() engine.push(item) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Iterator.Create") self.assertEqual( f"Cannot create iterator from unsupported type: {type(item)}", str(context.exception))
def test_validate_sample_contract(self): engine = test_engine() engine.load_script(vm.Script(hello_world_nef.script)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack._items)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.ByteStringStackItem) self.assertEqual(vm.ByteStringStackItem(b'hello world'), item)
def test_runtime_notify_exceed_size(self): engine = test_engine() engine.push(vm.ArrayStackItem(engine.reference_counter)) # state engine.push( vm.ByteStringStackItem( b'\x01' * (engine.MAX_EVENT_SIZE + 1))) # event messasge with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.Notify") self.assertEqual( "Notify event name length (33) exceeds maximum allowed (32)", str(context.exception))
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 test_base58_encode(self): engine = test_engine(has_snapshot=True) original_item = 100 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "base58Encode", [original_item]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.peek() self.assertEqual('2j', item.to_array().decode())
def test_checkwitness_helper(self): engine = test_engine() tx = test_tx() engine.script_container = tx bad_hash = types.UInt160.zero() self.assertFalse(engine.checkwitness(bad_hash)) # if scope is GLOBAL then checkwitness should always return true good_hash = tx.sender tx.signers[0].scope = payloads.WitnessScope.GLOBAL self.assertTrue(engine.checkwitness(good_hash))
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_binary_serialization(self): engine = test_engine(has_snapshot=True) original_item = 100 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "serialize", [original_item]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.pop() self.assertIsInstance(item, vm.ByteStringStackItem) self.assertEqual(b'\x21\x01\x64', item.to_array())
def test_total_supply(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 gas = contracts.GasToken() neo = contracts.NeoToken() # this is now the initial stored value + the result of the post_persist event (=committee reward added) expected_total_gas_supply = vm.BigInteger(3000000050000000) self.assertEqual(expected_total_gas_supply, gas.total_supply(engine.snapshot)) self.assertEqual(100_000_000, neo.total_supply(engine.snapshot))
def test_iterator_create_from_primitive_type(self): engine = test_engine() buffer = vm.ByteStringStackItem(b'\x03\x04') engine.push(buffer) r = engine.invoke_syscall_by_name("System.Iterator.Create") self.assertIsInstance(r, ByteArrayWrapper) self.assertTrue(r.next()) self.assertEqual(vm.IntegerStackItem(3), r.value()) self.assertTrue(r.next()) self.assertEqual(vm.IntegerStackItem(4), r.value()) self.assertFalse(r.next()) self.assertEqual(vm.IntegerStackItem(4), r.value())
def test_storage_get_ok(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key = storage.StorageKey(self.contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.ByteStringStackItem(storage_key.key)) engine.push(vm.StackItem.from_interface(ctx)) returned_value = engine.invoke_syscall_by_name("System.Storage.Get") self.assertEqual(storage_item.value, returned_value)
def test_policy_setters_fail_without_signatures(self): # cover set functions where check_committee fails policy = contracts.PolicyContract() engine = test_engine(has_snapshot=True) block = test_block(0) engine.snapshot.persisting_block = block engine.script_container = TestIVerifiable() with self.assertRaises(ValueError) as context: policy._set_fee_per_byte(engine, 0) self.assertEqual("Check committee failed", str(context.exception)) self.assertFalse(policy._block_account(engine, None)) self.assertFalse(policy._unblock_account(engine, None))
def test_bytearray_value_exception(self): """ calling `value` on an ByteArray iterator without having called `next` should fail """ engine = test_engine() item = vm.IntegerStackItem(123) engine.push(item) engine.invoke_syscall_by_name("System.Iterator.Create") with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Iterator.Value") self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception))
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_runtime_log(self): message = '' def runtime_log(script_container: payloads.IVerifiable, msg: str): nonlocal message message = msg msgrouter.interop_log += runtime_log engine = test_engine() engine.push(vm.ByteStringStackItem('hello world')) engine.invoke_syscall_by_name("System.Runtime.Log") self.assertEqual('hello world', message) # try with too long message engine = test_engine() engine.push( vm.ByteStringStackItem(b'a' * (engine.MAX_NOTIFICATION_SIZE + 1))) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.Log") self.assertEqual( "Log message length (1025) exceeds maximum allowed (1024)", str(context.exception))