def test_any_sequence_assignments(self): ok = String('ok').to_bytes() some_string = String('some_string').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x05' + b'\x00' + Opcode.PUSHDATA1 # any_list = [True, 1, 'ok'] + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.CONVERT + StackItemType.Boolean + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC0 + Opcode.PUSH3 # int_list = [1, 2, 3] + Opcode.PUSH2 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC1 + Opcode.PUSHDATA1 # any_tuple = (True, 1, 'ok') + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.CONVERT + StackItemType.Boolean + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC2 + Opcode.PUSH0 # bool_tuple = True, False + Opcode.CONVERT + StackItemType.Boolean + Opcode.PUSH1 + Opcode.CONVERT + StackItemType.Boolean + Opcode.PUSH2 + Opcode.PACK + Opcode.STLOC3 + Opcode.LDLOC0 # a = any_list + Opcode.STLOC4 + Opcode.LDLOC2 # a = any_tuple + Opcode.STLOC4 + Opcode.PUSHDATA1 # a = 'some_string' + Integer(len(some_string)).to_byte_array() + some_string + Opcode.STLOC4 + Opcode.LDLOC1 # a = int_list + Opcode.STLOC4 + Opcode.LDLOC3 # a = bool_tuple + Opcode.STLOC4 + Opcode.RET) path = self.get_contract_path('AnySequenceAssignments.py') output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_boa2_op_call_test(self): path = self.get_contract_path('OpCallBoa2Test.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'main', 'omin', 4, 4) self.assertEqual(4, result) result = self.run_smart_contract(engine, path, 'main', 'omin', -4, 4) self.assertEqual(-4, result) result = self.run_smart_contract(engine, path, 'main', 'omin', 16, 0) self.assertEqual(0, result) result = self.run_smart_contract(engine, path, 'main', 'omax', 4, 4) self.assertEqual(4, result) result = self.run_smart_contract(engine, path, 'main', 'omax', -4, 4) self.assertEqual(4, result) result = self.run_smart_contract(engine, path, 'main', 'omax', 16, 0) self.assertEqual(16, result) from boa3.neo.cryptography import sha256, hash160 from boa3.neo.vm.type.String import String result = self.run_smart_contract(engine, path, 'main', 'sha256', 'abc', 4) self.assertEqual(sha256(String('abc').to_bytes()), result) result = self.run_smart_contract(engine, path, 'main', 'hash160', 'abc', 4) self.assertEqual(hash160(String('abc').to_bytes()), result)
def test_multiple_list_expressions(self): one = String('1').to_bytes() four = String('4').to_bytes() expected_output = ( Opcode.INITSLOT # function signature + b'\x03' + b'\x01' + Opcode.PUSHDATA1 # items2 = [False, '1', 2, 3, '4'] + Integer(len(four)).to_byte_array() + four + Opcode.PUSH3 + Opcode.PUSH2 + Opcode.PUSHDATA1 + Integer(len(one)).to_byte_array() + one + Opcode.PUSH0 + Opcode.PUSH5 + Opcode.PACK + Opcode.STLOC0 # items2 = array + Opcode.LDARG0 # value = items1[0] + Opcode.PUSH0 + Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE + Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.OVER + Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.STLOC1 + Opcode.LDLOC1 # count = value + len(items2) + Opcode.LDLOC0 + Opcode.SIZE + Opcode.ADD + Opcode.STLOC2 + Opcode.LDLOC2 # return count + Opcode.RET) path = '%s/boa3_test/test_sc/list_test/MultipleExpressionsInLine.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine(self.dirname) result = self.run_smart_contract(engine, path, 'Main', [2, 1]) self.assertEqual(7, result) result = self.run_smart_contract(engine, path, 'Main', [-7, 5]) self.assertEqual(-2, result)
def test_notify_str(self): event_name = String('notify').to_bytes() message = 'str' string = String(message).to_bytes() expected_output = ( Opcode.PUSHDATA1 + Integer(len(string)).to_byte_array(min_length=1) + string + Opcode.PUSH1 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(event_name)).to_byte_array(min_length=1) + event_name + Opcode.SYSCALL + Interop.Notify.interop_method_hash + Opcode.PUSHNULL + Opcode.RET ) path = '%s/boa3_test/test_sc/interop_test/NotifyStr.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine(self.dirname) self.run_smart_contract(engine, path, 'Main') self.assertGreater(len(engine.notifications), 0) event_notifications = engine.get_events(event_name=Interop.Notify.name) self.assertEqual(1, len(event_notifications)) self.assertEqual((message,), event_notifications[0].arguments)
def test_check_multisig_with_ecdsa_secp256k1_byte(self): byte_input0 = String('123').to_bytes() byte_input1 = String('456').to_bytes() byte_input2 = String('098').to_bytes() byte_input3 = String('765').to_bytes() byte_input4 = b'\x00\x01\x02' expected_output = ( Opcode.INITSLOT + b'\x02' + b'\x00' + Opcode.PUSHDATA1 + Integer(len(byte_input1)).to_byte_array(min_length=1) + byte_input1 + Opcode.PUSHDATA1 + Integer(len(byte_input0)).to_byte_array(min_length=1) + byte_input0 + Opcode.PUSH2 + Opcode.PACK + Opcode.STLOC0 + Opcode.PUSHDATA1 + Integer(len(byte_input3)).to_byte_array(min_length=1) + byte_input3 + Opcode.PUSHDATA1 + Integer(len(byte_input2)).to_byte_array(min_length=1) + byte_input2 + Opcode.PUSH2 + Opcode.PACK + Opcode.STLOC1 + Opcode.LDLOC1 + Opcode.LDLOC0 + Opcode.PUSHDATA1 + Integer(len(byte_input4)).to_byte_array(min_length=1) + byte_input4 + Opcode.SYSCALL + Interop.CheckMultisigWithECDsaSecp256k1.interop_method_hash + Opcode.DROP + Opcode.RET) path = self.get_contract_path('CheckMultisigWithECDsaSecp256k1Byte.py') output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_base64_decode(self): import base64 path = self.get_contract_path('Base64Decode.py') engine = TestEngine() arg = String.from_bytes(base64.b64encode(b'unit test')) result = self.run_smart_contract(engine, path, 'Main', arg, expected_result_type=bytes) self.assertEqual(b'unit test', result) arg = String.from_bytes(base64.b64encode(b'')) result = self.run_smart_contract(engine, path, 'Main', arg, expected_result_type=bytes) self.assertEqual(b'', result) long_string = ('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam accumsan magna eu massa ' 'vulputate bibendum. Aliquam commodo euismod tristique. Sed purus erat, pretium ut interdum ' 'et, aliquet sed mauris. Curabitur vitae turpis euismod, hendrerit mi a, rhoncus justo. Mauris ' 'sollicitudin, nisl sit amet feugiat pharetra, odio ligula congue tellus, vel pellentesque ' 'libero leo id dui. Morbi vel risus vehicula, consectetur mauris eget, gravida ligula. ' 'Maecenas aliquam velit sit amet nisi ultricies, ac sollicitudin nisi mollis. Lorem ipsum ' 'dolor sit amet, consectetur adipiscing elit. Ut tincidunt, nisi in ullamcorper ornare, ' 'est enim dictum massa, id aliquet justo magna in purus.') arg = String.from_bytes(base64.b64encode(String(long_string).to_bytes())) result = self.run_smart_contract(engine, path, 'Main', arg, expected_result_type=bytes) self.assertEqual(String(long_string).to_bytes(), result)
def test_tuple_string_values(self): byte_input0 = String('1').to_bytes() byte_input1 = String('2').to_bytes() byte_input2 = String('3').to_bytes() expected_output = ( Opcode.INITSLOT # function signature + b'\x01' + b'\x00' + Opcode.PUSHDATA1 # a = ('1', '2', '3') + Integer(len(byte_input2)).to_byte_array() + byte_input2 + Opcode.PUSHDATA1 + Integer(len(byte_input1)).to_byte_array() + byte_input1 + Opcode.PUSHDATA1 + Integer(len(byte_input0)).to_byte_array() + byte_input0 + Opcode.PUSH3 # tuple length + Opcode.PACK + Opcode.STLOC0 + Opcode.PUSHNULL + Opcode.RET # return ) path = '%s/boa3_test/test_sc/tuple_test/StrTuple.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_multiple_tuple_expressions(self): a = String('a').to_bytes() b = String('b').to_bytes() c = String('c').to_bytes() d = String('d').to_bytes() expected_output = ( Opcode.INITSLOT # function signature + b'\x03' + b'\x01' + Opcode.PUSHDATA1 # items2 = ('a', 'b', 'c', 'd') + Integer(len(d)).to_byte_array() + d + Opcode.PUSHDATA1 + Integer(len(c)).to_byte_array() + c + Opcode.PUSHDATA1 + Integer(len(b)).to_byte_array() + b + Opcode.PUSHDATA1 + Integer(len(a)).to_byte_array() + a + Opcode.PUSH4 + Opcode.PACK + Opcode.STLOC0 # items2 = array + Opcode.LDARG0 # value = items1[0] + Opcode.PUSH0 + Opcode.DUP + Opcode.SIGN + Opcode.PUSHM1 + Opcode.JMPNE + Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.OVER + Opcode.SIZE + Opcode.ADD + Opcode.PICKITEM + Opcode.STLOC1 + Opcode.LDLOC1 # count = value + len(items2) + Opcode.LDLOC0 + Opcode.SIZE + Opcode.ADD + Opcode.STLOC2 + Opcode.LDLOC2 # return count + Opcode.RET) path = '%s/boa3_test/test_sc/tuple_test/MultipleExpressionsInLine.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine(self.dirname) result = self.run_smart_contract(engine, path, 'Main', [1, 2]) self.assertEqual(5, result) result = self.run_smart_contract(engine, path, 'Main', [-5, -7]) self.assertEqual(-1, result)
def test_concat_with_bytestring(self): path = self.get_contract_path('bytestring', 'ConcatWithByteString.py') engine = TestEngine() prefix = '12345' arg = 'a' result = self.run_smart_contract(engine, path, 'concat', prefix, arg) self.assertEqual(prefix + arg, result) arg = b'a' result = self.run_smart_contract(engine, path, 'concat', prefix, arg) self.assertEqual(prefix + String.from_bytes(arg), result) prefix = b'12345' arg = b'6789' result = self.run_smart_contract(engine, path, 'concat', prefix, arg, expected_result_type=bytes) self.assertEqual(prefix + arg, result) arg = '6789' result = self.run_smart_contract(engine, path, 'concat', prefix, arg, expected_result_type=bytes) self.assertEqual(prefix + String(arg).to_bytes(), result)
def test_dict_values(self): one = String('one').to_bytes() two = String('two').to_bytes() three = String('three').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x02' + b'\x00' + Opcode.NEWMAP # a = {'one': 1, 'two': 2, 'three': 3} + Opcode.DUP + Opcode.PUSHDATA1 # map['one'] = 1 + Integer(len(one)).to_byte_array(min_length=1) + one + Opcode.PUSH1 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['two'] = 2 + Integer(len(two)).to_byte_array(min_length=1) + two + Opcode.PUSH2 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['three'] = 3 + Integer(len(three)).to_byte_array(min_length=1) + three + Opcode.PUSH3 + Opcode.SETITEM + Opcode.STLOC0 + Opcode.LDLOC0 # b = a.values() + Opcode.VALUES + Opcode.STLOC1 + Opcode.LDLOC1 # return b + Opcode.RET) path = '%s/boa3_test/test_sc/dict_test/ValuesDict.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine(self.dirname) result = self.run_smart_contract(engine, path, 'Main') self.assertEqual([1, 2, 3], result)
def test_boa2_storage_test(self): path = self.get_contract_path('StorageBoa2Test.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'main', 'sget', 'something', 'blah') if isinstance(result, str): result = String(result).to_bytes() self.assertEqual(b'', result) result = self.run_smart_contract(engine, path, 'main', 'sput', 'something', 'blah') self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'main', 'sget', 'something', 'blah') if isinstance(result, str): result = String(result).to_bytes() self.assertEqual(b'blah', result) result = self.run_smart_contract(engine, path, 'main', 'sdel', 'something', 'blah') self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'main', 'sget', 'something', 'blah') if isinstance(result, str): result = String(result).to_bytes() self.assertEqual(b'', result)
def test_boa2_storage_test2(self): path = self.get_contract_path('StorageBoa2Test.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'main', 'sget', 100, 10000000000) if isinstance(result, str): result = String(result).to_bytes() self.assertEqual(b'', result) result = self.run_smart_contract(engine, path, 'main', 'sput', 100, 10000000000) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'main', 'sget', 100, 10000000000) if isinstance(result, bytes): result = Integer.from_bytes(result) self.assertEqual(10000000000, result) result = self.run_smart_contract(engine, path, 'main', 'sdel', 100, 10000000000) self.assertEqual(True, result) result = self.run_smart_contract(engine, path, 'main', 'sget', 100, 10000000000) if isinstance(result, str): result = String(result).to_bytes() self.assertEqual(b'', result)
def test_function_any_param(self): ok = String('ok').to_bytes() some_string = String('some_string').to_bytes() expected_output = ( Opcode.INITSLOT # Main + b'\x01' + b'\x00' + Opcode.PUSH0 # bool_tuple = True, False + Opcode.PUSH1 + Opcode.PUSH2 + Opcode.PACK + Opcode.STLOC0 + Opcode.LDLOC0 # SequenceFunction(bool_tuple) + Opcode.CALL + Integer(51).to_byte_array(min_length=1, signed=True) + Opcode.DROP + Opcode.PUSHDATA1 # SequenceFunction([True, 1, 'ok']) + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.CALL + Integer(40).to_byte_array(min_length=1, signed=True) + Opcode.DROP + Opcode.PUSHDATA1 # SequenceFunction('some_string') + Integer(len(some_string)).to_byte_array() + some_string + Opcode.CALL + Integer(24).to_byte_array(min_length=1, signed=True) + Opcode.DROP + Opcode.PUSHDATA1 # SequenceFunction((True, 1, 'ok')) + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.CALL + Integer(13).to_byte_array(min_length=1, signed=True) + Opcode.DROP + Opcode.PUSH3 # SequenceFunction([1, 2, 3]) + Opcode.PUSH2 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.CALL + Integer(5).to_byte_array(min_length=1, signed=True) + Opcode.DROP + Opcode.PUSHNULL + Opcode.RET # return + Opcode.INITSLOT # SequenceFunction + b'\x01' + b'\x01' + Opcode.LDARG0 # a = sequence + Opcode.STLOC0 + Opcode.PUSHNULL + Opcode.RET) path = '%s/boa3_test/test_sc/any_test/FunctionAnyParam.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_any_sequence_assignments(self): ok = String('ok').to_bytes() some_string = String('some_string').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x05' + b'\x00' + Opcode.PUSHDATA1 # any_list = [True, 1, 'ok'] + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC0 + Opcode.PUSH3 # int_list = [1, 2, 3] + Opcode.PUSH2 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC1 + Opcode.PUSHDATA1 # any_tuple = (True, 1, 'ok') + Integer(len(ok)).to_byte_array() + ok + Opcode.PUSH1 + Opcode.PUSH1 + Opcode.PUSH3 + Opcode.PACK + Opcode.STLOC2 + Opcode.PUSH0 # bool_tuple = True, False + Opcode.PUSH1 + Opcode.PUSH2 + Opcode.PACK + Opcode.STLOC3 + Opcode.LDLOC0 # a = any_list + Opcode.STLOC4 + Opcode.LDLOC2 # a = any_tuple + Opcode.STLOC4 + Opcode.PUSHDATA1 # a = 'some_string' + Integer(len(some_string)).to_byte_array() + some_string + Opcode.STLOC4 + Opcode.LDLOC1 # a = int_list + Opcode.STLOC4 + Opcode.LDLOC3 # a = bool_tuple + Opcode.STLOC4 + Opcode.PUSHNULL + Opcode.RET) path = '%s/boa3_test/test_sc/any_test/AnySequenceAssignments.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_update_contract(self): call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) expected_output = ( Opcode.INITSLOT + b'\00' + b'\02' + Opcode.LDARG1 + Opcode.LDARG0 + Opcode.PUSH2 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(Interop.UpdateContract.method_name)).to_byte_array( min_length=1) + String(Interop.UpdateContract.method_name).to_bytes() + Opcode.PUSHDATA1 + Integer(len( constants.MANAGEMENT_SCRIPT)).to_byte_array(min_length=1) + constants.MANAGEMENT_SCRIPT + Opcode.PUSHDATA1 + Integer(len(call_flag)).to_byte_array(min_length=1) + call_flag + Opcode.ROT + Opcode.ROT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.DROP + Opcode.RET) path = self.get_contract_path('UpdateContract.py') output, manifest = self.compile_and_save(path) self.assertEqual(expected_output, output) new_path = self.get_contract_path('test_sc/interop_test', 'UpdateContract.py') self.compile_and_save(new_path) new_nef, new_manifest = self.get_bytes_output(new_path) arg_manifest = String(json.dumps(new_manifest, separators=(',', ':'))).to_bytes() engine = TestEngine() result = self.run_smart_contract(engine, path, 'update', new_nef, arg_manifest) self.assertIsVoid(result)
def test_create_contract(self): call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) expected_output = ( Opcode.INITSLOT + b'\x00' + b'\x02' + Opcode.LDARG1 + Opcode.LDARG0 + Opcode.PUSH2 + Opcode.PACK + Opcode.DUP + Opcode.PUSHNULL + Opcode.APPEND + Opcode.PUSHDATA1 + Integer(len(Interop.CreateContract.method_name)).to_byte_array( min_length=1) + String(Interop.CreateContract.method_name).to_bytes() + Opcode.PUSHDATA1 + Integer(len( constants.MANAGEMENT_SCRIPT)).to_byte_array(min_length=1) + constants.MANAGEMENT_SCRIPT + Opcode.PUSHDATA1 + Integer(len(call_flag)).to_byte_array(min_length=1) + call_flag + Opcode.ROT + Opcode.ROT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.RET) path = self.get_contract_path('CreateContract.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) call_contract_path = self.get_contract_path('test_sc/arithmetic_test', 'Addition.py') Boa3.compile_and_save(call_contract_path) nef_file, manifest = self.get_bytes_output(call_contract_path) arg_manifest = String(json.dumps(manifest, separators=(',', ':'))).to_bytes() engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main', nef_file, arg_manifest) self.assertEqual(5, len(result)) self.assertEqual(nef_file, result[3])
def test_get_transaction_from_block_uint256(self): call_flags = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) method = String('getTransactionFromBlock').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x00\x02' + Opcode.LDARG1 + Opcode.LDARG0 + Opcode.PUSH2 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(call_flags)).to_byte_array() + call_flags + Opcode.PUSHDATA1 + Integer(len(method)).to_byte_array() + method + Opcode.PUSHDATA1 + Integer(len(constants.LEDGER_SCRIPT)).to_byte_array() + constants.LEDGER_SCRIPT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.RET ) path = self.get_contract_path('GetTransactionFromBlockUInt256.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) path_burn_gas = self.get_contract_path('../runtime', 'BurnGas.py') engine = TestEngine() engine.increase_block(10) sender = bytes(range(20)) self.run_smart_contract(engine, path_burn_gas, 'main', 100, signer_accounts=[sender]) block_10 = engine.current_block block_hash = block_10.hash self.assertIsNotNone(block_hash) txs = block_10.get_transactions() tx_hash = txs[0].hash tx_script = txs[0]._script engine.increase_block() result = self.run_smart_contract(engine, path, 'main', block_hash, 0) self.assertEqual(8, len(result)) if isinstance(result[0], str): result[0] = String(result[0]).to_bytes() self.assertEqual(UInt256(tx_hash), UInt256(result[0])) # hash self.assertIsInstance(result[1], int) # version self.assertIsInstance(result[2], int) # nonce if isinstance(result[3], str): result[3] = String(result[3]).to_bytes() self.assertEqual(UInt160(sender), UInt160(result[3])) # sender self.assertIsInstance(result[4], int) # system_fee self.assertIsInstance(result[5], int) # network_fee self.assertIsInstance(result[6], int) # valid_until_block if isinstance(result[7], str): result[7] = String(result[7]).to_bytes() self.assertEqual(tx_script, result[7]) # script
def test_dict_values_mismatched_type(self): one = String('one').to_bytes() two = String('two').to_bytes() three = String('three').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x02' + b'\x00' + Opcode.NEWMAP # a = {'one': 1, 'two': 2, 'three': 3} + Opcode.DUP + Opcode.PUSHDATA1 # map['one'] = 1 + Integer(len(one)).to_byte_array(min_length=1) + one + Opcode.PUSH1 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['two'] = 2 + Integer(len(two)).to_byte_array(min_length=1) + two + Opcode.PUSH2 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['three'] = 3 + Integer(len(three)).to_byte_array(min_length=1) + three + Opcode.PUSH3 + Opcode.SETITEM + Opcode.STLOC0 + Opcode.LDLOC0 # b = a.values() + Opcode.VALUES + Opcode.STLOC1 + Opcode.LDLOC1 # return b + Opcode.RET) path = self.get_contract_path('MismatchedTypeValuesDict.py') output = self.assertCompilerLogs(CompilerWarning.TypeCasting, path) self.assertEqual(expected_output, output) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertEqual([1, 2, 3], result)
def test_dict_keys(self): one = String('one').to_bytes() two = String('two').to_bytes() three = String('three').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x02' + b'\x00' + Opcode.NEWMAP # a = {'one': 1, 'two': 2, 'three': 3} + Opcode.DUP + Opcode.PUSHDATA1 # map['one'] = 1 + Integer(len(one)).to_byte_array(min_length=1) + one + Opcode.PUSH1 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['two'] = 2 + Integer(len(two)).to_byte_array(min_length=1) + two + Opcode.PUSH2 + Opcode.SETITEM + Opcode.DUP + Opcode.PUSHDATA1 # map['three'] = 3 + Integer(len(three)).to_byte_array(min_length=1) + three + Opcode.PUSH3 + Opcode.SETITEM + Opcode.STLOC0 + Opcode.LDLOC0 # b = a.keys() + Opcode.KEYS + Opcode.STLOC1 + Opcode.LDLOC1 # return b + Opcode.RET) path = self.get_contract_path('KeysDict.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertEqual(['one', 'two', 'three'], result)
def test_deserialize(self): path = self.get_contract_path('Deserialize.py') engine = TestEngine() expected_result = 42 value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value, expected_result_type=bytes) self.assertEqual(expected_result, result) expected_result = True value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) self.assertEqual(expected_result, result) value = StackItemType.Boolean + value[1:] result = self.run_smart_contract(engine, path, 'deserialize_arg', value) self.assertEqual(expected_result, result) expected_result = '42' value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) self.assertEqual(expected_result, result) expected_result = b'42' value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value, expected_result_type=bytes) self.assertEqual(expected_result, result) expected_result = [1, '2', b'3'] value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) expected_result[2] = String.from_bytes(expected_result[2]) self.assertEqual(expected_result, result) expected_result = {'int': 1, 'str': '2', 'bytes': b'3'} value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) expected_result['bytes'] = String.from_bytes(expected_result['bytes']) self.assertEqual(expected_result, result)
def test_storage_put_str_key_str_value(self): value = String('123').to_bytes() expected_output = ( Opcode.INITSLOT + b'\x01' + b'\x01' + Opcode.PUSHDATA1 + Integer(len(value)).to_byte_array(min_length=1, signed=True) + value + Opcode.STLOC0 + Opcode.PUSHDATA1 + Integer(len(value)).to_byte_array(min_length=1, signed=True) + value + Opcode.LDARG0 + Opcode.SYSCALL + Interop.StorageGetContext.interop_method_hash + Opcode.SYSCALL + Interop.StoragePut.interop_method_hash + Opcode.RET ) path = self.get_contract_path('StoragePutStrKeyStrValue.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine() stored_value = String('123').to_bytes() result = self.run_smart_contract(engine, path, 'Main', 'test1') self.assertIsVoid(result) storage_value = engine.storage_get(b'test1', path) self.assertIsNotNone(storage_value) self.assertEqual(stored_value, storage_value) result = self.run_smart_contract(engine, path, 'Main', 'test2') self.assertIsVoid(result) storage_value = engine.storage_get(b'test1', path) self.assertIsNotNone(storage_value) self.assertEqual(stored_value, storage_value) storage_value = engine.storage_get(b'test2', path) self.assertIsNotNone(storage_value) self.assertEqual(stored_value, storage_value) result = self.run_smart_contract(engine, path, 'Main', 'test2', fake_storage={}) self.assertIsVoid(result) storage_value = engine.storage_get(b'test1', path) self.assertIsNone(storage_value) storage_value = engine.storage_get(b'test2', path) self.assertIsNotNone(storage_value) self.assertEqual(stored_value, storage_value)
def test_deserialize(self): path = self.get_contract_path('Deserialize.py') self.compile_and_save(path) engine = TestEngine() expected_result = 42 value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value, expected_result_type=bytes) self.assertEqual(expected_result, result) expected_result = True value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) # it shouldn't be equal to the convertion, because it converts as an int instead of a boolean self.assertEqual(expected_result, result) self.assertNotEqual(type(expected_result), type(result)) value = StackItemType.Boolean + value[1:] result = self.run_smart_contract(engine, path, 'deserialize_arg', value, expected_result_type=bool) self.assertEqual(expected_result, result) self.assertEqual(type(expected_result), type(result)) expected_result = '42' value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) self.assertEqual(expected_result, result) expected_result = b'42' value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value, expected_result_type=bytes) self.assertEqual(expected_result, result) expected_result = [1, '2', b'3'] value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) expected_result[2] = String.from_bytes(expected_result[2]) self.assertEqual(expected_result, result) expected_result = {'int': 1, 'str': '2', 'bytes': b'3'} value = serialize(expected_result) result = self.run_smart_contract(engine, path, 'deserialize_arg', value) expected_result['bytes'] = String.from_bytes(expected_result['bytes']) self.assertEqual(expected_result, result)
def test_notify_int(self): event_name = String('notify').to_bytes() expected_output = ( Opcode.PUSH15 + Opcode.PUSH1 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(event_name)).to_byte_array(min_length=1) + event_name + Opcode.SYSCALL + Interop.Notify.interop_method_hash + Opcode.RET ) path = self.get_contract_path('NotifyInt.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertIsVoid(result) self.assertGreater(len(engine.notifications), 0) event_notifications = engine.get_events(event_name=Interop.Notify.name) self.assertEqual(1, len(event_notifications)) self.assertEqual((15,), event_notifications[0].arguments)
def test_len_of_str(self): input = 'just a test' byte_input = String(input).to_bytes() expected_output = ( Opcode.INITSLOT + b'\x01' + b'\x00' + Opcode.PUSHDATA1 # push the bytes + Integer(len(byte_input)).to_byte_array() + byte_input + Opcode.STLOC0 + Opcode.PUSHDATA1 # push the bytes + Integer(len(byte_input)).to_byte_array() + byte_input + Opcode.SIZE + Opcode.RET ) path = self.get_contract_path('LenString.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine() result = self.run_smart_contract(engine, path, 'Main') self.assertEqual(11, result)
def opcode(self) -> List[Tuple[Opcode, bytes]]: from boa3.neo.vm.type.Integer import Integer from boa3.neo.vm.type.String import String range_error_msg = String('range() arg 3 must not be zero').to_bytes() return [(Opcode.PUSH2, b''), (Opcode.PICK, b''), (Opcode.SIGN, b''), (Opcode.JMPIF, Integer(5 + len(range_error_msg)).to_byte_array(signed=True)), (Opcode.PUSHDATA1, Integer(len(range_error_msg)).to_byte_array(signed=True) + range_error_msg), (Opcode.THROW, b''), (Opcode.NEWARRAY0, b''), (Opcode.REVERSE4, b''), (Opcode.SWAP, b''), (Opcode.JMP, Integer(8).to_byte_array(signed=True, min_length=1)), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.OVER, b''), (Opcode.APPEND, b''), (Opcode.OVER, b''), (Opcode.ADD, b''), (Opcode.DUP, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.PUSH3, b''), (Opcode.PICK, b''), (Opcode.SIGN, b''), (Opcode.PUSH0, b''), (Opcode.JMPGT, Integer(5).to_byte_array(signed=True, min_length=1)), (Opcode.GT, b''), (Opcode.JMP, Integer(3).to_byte_array(signed=True, min_length=1)), (Opcode.LT, b''), (Opcode.JMPIF, Integer(-19).to_byte_array(signed=True, min_length=1)), (Opcode.DROP, b''), (Opcode.DROP, b''), (Opcode.DROP, b'')]
def test_verify_with_ecdsa_secp256k1_int(self): byte_input1 = b'publickey' byte_input2 = b'signature' function_id = String(Interop.VerifyWithECDsaSecp256k1._sys_call).to_bytes() call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) expected_output = ( Opcode.PUSHDATA1 + Integer(len(byte_input2)).to_byte_array(min_length=1) + byte_input2 + Opcode.PUSHDATA1 + Integer(len(byte_input1)).to_byte_array(min_length=1) + byte_input1 + Opcode.PUSH10 + Opcode.PUSH3 + Opcode.PACK + Opcode.DUP + Opcode.PUSHINT8 + Integer(NamedCurve.SECP256K1).to_byte_array(min_length=1) + Opcode.APPEND + Opcode.PUSHDATA1 + Integer(len(call_flag)).to_byte_array() + call_flag + Opcode.PUSHDATA1 + Integer(len(function_id)).to_byte_array() + function_id + Opcode.PUSHDATA1 + Integer(len(CRYPTO_SCRIPT)).to_byte_array() + CRYPTO_SCRIPT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.DROP + Opcode.RET ) path = self.get_contract_path('VerifyWithECDsaSecp256k1Int.py') output = Boa3.compile(path) self.assertEqual(expected_output, output)
def test_script_hash_variable_with_builtin(self): from boa3.neo3.contracts import CallFlags call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) twenty = Integer(20).to_byte_array() base58_identifier = String(Interop.Base58Decode.method_name).to_bytes() expected_output = ( Opcode.INITSLOT + b'\x00\x01' + Opcode.LDARG0 + Opcode.DUP + Opcode.SIZE + Opcode.JMPIFNOT + Integer(47).to_byte_array(min_length=1) + Opcode.DUP + Opcode.ISTYPE + Type.str.stack_item + Opcode.JMPIF + Integer(4).to_byte_array(min_length=1) + Opcode.CONVERT + Type.str.stack_item + Opcode.PUSH1 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(base58_identifier)).to_byte_array(min_length=1) + base58_identifier + Opcode.PUSHDATA1 + Integer(len(STD_LIB_SCRIPT)).to_byte_array(min_length=1) + STD_LIB_SCRIPT + Opcode.PUSHDATA1 + Integer(len(call_flag)).to_byte_array(min_length=1) + call_flag + Opcode.ROT + Opcode.ROT + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.DUP + Opcode.SIZE + Opcode.PUSHDATA1 + Integer(len(twenty)).to_byte_array(min_length=1) + twenty + Opcode.CONVERT + Type.int.stack_item + Opcode.JMPGT + Integer(8).to_byte_array(min_length=1) + Opcode.DUP + Opcode.SIZE + Opcode.DEC + Opcode.RIGHT + Opcode.JMP + Integer(9).to_byte_array(min_length=1) + Opcode.PUSH1 + Opcode.PUSHDATA1 + Integer(len(twenty)).to_byte_array(min_length=1) + twenty + Opcode.CONVERT + Type.int.stack_item + Opcode.SUBSTR + Opcode.CONVERT + Type.bytes.stack_item + Opcode.RET) path = self.get_contract_path('ScriptHashVariableBuiltinCall.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) from boa3.neo import to_script_hash from base58 import b58encode engine = TestEngine() script_hash = to_script_hash('123') result = self.run_smart_contract(engine, path, 'Main', '123', expected_result_type=bytes) self.assertEqual(script_hash, result) value = b58encode('123') if isinstance(value, int): value = Integer(value).to_byte_array() script_hash = to_script_hash(value) result = self.run_smart_contract(engine, path, 'Main', value, expected_result_type=bytes) self.assertEqual(script_hash, result)
def test_contract_interface_code_optimization(self): from boa3.model.builtin.interop.interop import Interop from boa3.neo.vm.opcode.Opcode import Opcode from boa3.neo.vm.type.Integer import Integer from boa3.neo.vm.type.String import String from boa3.neo3.core.types import UInt160 external_contract_name = 'symbol' function_name_bytes = String(external_contract_name).to_bytes() contract_script_bytes = UInt160.from_string( '21f19f84e144f91abe755efb21a6798ac95c2e70').to_array() expected_output = ( Opcode.NEWARRAY0 # arguments list + Opcode.PUSH15 # CallFlag + Opcode.PUSHDATA1 # function name + Integer(len(function_name_bytes)).to_byte_array() + function_name_bytes + Opcode.PUSHDATA1 # contract script + Integer(len(contract_script_bytes)).to_byte_array() + contract_script_bytes + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.RET) path = self.get_contract_path('ContractInterfaceCodeOptimization.py') output, manifest = self.compile_and_save(path) self.assertEqual(expected_output, output) nep17_path = self.get_contract_path('examples', 'nep17.py') engine = TestEngine() nep17_result = self.run_smart_contract(engine, nep17_path, 'symbol') result = self.run_smart_contract(engine, path, 'nep17_symbol') self.assertEqual(nep17_result, result)
def serialize(self, writer: serialization.BinaryWriter) -> None: version_str = "{0}.{1}.{2}.{3}".format(self.major, self.minor, self.build, self.revision) from boa3.neo.vm.type.String import String version_bytes = String(version_str).to_bytes() + bytes( s.uint64 * 4 - len(version_str)) writer.write_bytes(version_bytes)
def test_raise_exception_with_message(self): exception_message = String('raised an exception').to_bytes() expected_output = ( Opcode.INITSLOT # function signature + b'\x00' + b'\x01' + Opcode.LDARG0 # if arg0 < 0 + Opcode.PUSH0 + Opcode.LT + Opcode.JMPIFNOT + Integer(24).to_byte_array(signed=True, min_length=1) + Opcode.PUSHDATA1 # raise Exception('raised an exception') + Integer(len(exception_message)).to_byte_array(signed=True, min_length=1) + exception_message + Opcode.THROW + Opcode.PUSHNULL + Opcode.RET ) path = '%s/boa3_test/test_sc/exception_test/RaiseExceptionWithMessage.py' % self.dirname output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine(self.dirname) self.run_smart_contract(engine, path, 'test_raise', 10) with self.assertRaises(TestExecutionException, msg=self.EXCEPTION_EMPTY_MESSAGE): self.run_smart_contract(engine, path, 'test_raise', -10)