def test_call_contract_without_args(self): call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) expected_output = ( Opcode.INITSLOT + b'\x00' + b'\x02' + Opcode.NEWARRAY0 + Opcode.LDARG1 + Opcode.LDARG0 + 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('CallScriptHashWithoutArgs.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) call_contract_path = self.get_contract_path('test_sc/list_test', 'IntList.py') Boa3.compile_and_save(call_contract_path) contract, manifest = self.get_output(call_contract_path) call_hash = hash160(contract) call_contract_path = call_contract_path.replace('.py', '.nef') engine = TestEngine() with self.assertRaises(TestExecutionException, msg=self.CALLED_CONTRACT_DOES_NOT_EXIST_MSG): self.run_smart_contract(engine, path, 'Main', call_hash, 'Main') engine.add_contract(call_contract_path) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'Main') self.assertEqual([1, 2, 3], result)
def test_call_contract(self): path = self.get_contract_path('CallScriptHash.py') call_contract_path = self.get_contract_path('test_sc/arithmetic_test', 'Addition.py') Boa3.compile_and_save(call_contract_path) contract, manifest = self.get_output(call_contract_path) call_hash = hash160(contract) call_contract_path = call_contract_path.replace('.py', '.nef') engine = TestEngine() with self.assertRaises(TestExecutionException, msg=self.CALLED_CONTRACT_DOES_NOT_EXIST_MSG): self.run_smart_contract(engine, path, 'Main', call_hash, 'add', [1, 2]) engine.add_contract(call_contract_path) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'add', [1, 2]) self.assertEqual(3, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'add', [-42, -24]) self.assertEqual(-66, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'add', [-42, 24]) self.assertEqual(-18, result)
def test_create_contract_data_deploy(self): path = self.get_contract_path('CreateContract.py') call_contract_path = self.get_contract_path('NewContract.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() data = 'some sort of data' result = self.run_smart_contract(engine, path, 'Main', nef_file, arg_manifest, data) self.assertEqual(5, len(result)) self.assertEqual(nef_file, result[3]) manifest_struct = NeoManifestStruct.from_json(manifest) self.assertEqual(manifest_struct, result[4]) notifies = engine.get_events('notify') self.assertEqual(2, len(notifies)) self.assertEqual(False, notifies[0].arguments[0]) # not updated self.assertEqual(data, notifies[1].arguments[0]) # data result = self.run_smart_contract(engine, call_contract_path, 'main') self.assertEqual(data, result)
def test_generate_nef_file(self): path = self.get_contract_path('GenerationWithDecorator.py') expected_nef_output = path.replace('.py', '.nef') Boa3.compile_and_save(path) self.assertTrue(os.path.exists(expected_nef_output)) with open(expected_nef_output, 'rb') as nef_output: magic = nef_output.read(constants.SIZE_OF_INT32) compiler_with_version = nef_output.read(64) compiler, version = compiler_with_version.rsplit(b'-', maxsplit=1) version = version[:32] nef_output.read(2) # reserved nef_output.read(1) # TODO: method tokens nef_output.read(2) # reserved script_size = nef_output.read(1) script = nef_output.read(int.from_bytes(script_size, BYTEORDER)) check_sum = nef_output.read(constants.SIZE_OF_INT32) self.assertEqual(int.from_bytes(script_size, BYTEORDER), len(script)) nef = NefFile(script)._nef self.assertEqual(compiler.decode(ENCODING), nef.compiler) self.assertEqual(check_sum, nef.checksum) self.assertEqual(version, nef.version.to_array())
def test_dict_any_key_and_value(self): path = self.get_contract_path('DictAnyKeyAndValue.py') Boa3.compile_and_save(path) engine = TestEngine() result = self.run_smart_contract(engine, path, 'main') self.assertEqual(66, 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_generate_files(self): path = self.get_contract_path('GenerationWithDecorator.py') expected_nef_output = path.replace('.py', '.nef') expected_manifest_output = path.replace('.py', '.manifest.json') Boa3.compile_and_save(path) self.assertTrue(os.path.exists(expected_nef_output)) self.assertTrue(os.path.exists(expected_manifest_output))
def test_compare_same_value_argument(self): path = self.get_contract_path('CompareSameValueArgument.py') Boa3.compile_and_save(path) engine = TestEngine() result = self.run_smart_contract(engine, path, 'testing_something', bytes(20), expected_result_type=bool) self.assertEqual(True, result)
def test_generate_files(self): path = '%s/boa3_test/test_sc/generation_test/GenerationWithDecorator.py' % self.dirname expected_nef_output = path.replace('.py', '.nef') expected_manifest_output = path.replace('.py', '.manifest.json') expected_debug_info_output = path.replace('.py', '.nefdbgnfo') Boa3.compile_and_save(path) self.assertTrue(os.path.exists(expected_nef_output)) self.assertTrue(os.path.exists(expected_manifest_output)) self.assertTrue(os.path.exists(expected_debug_info_output))
def test_compiler_error(self): path = self.get_contract_path('test_sc/built_in_methods_test', 'ClearTooManyParameters.py') with self.assertRaises(NotLoadedException): Boa3.compile(path) with self.assertRaises(NotLoadedException): Boa3.compile_and_save(path) with self.assertRaises(NotLoadedException): self.compile_and_save(path)
def setUpClass(cls): folders = os.path.abspath(__file__).split(os.sep) cls.dirname = '/'.join(folders[:-2]) test_engine_installation_folder = cls.dirname # Change this to your test engine installation folder cls.engine = TestEngine(test_engine_installation_folder) path = f'{cls.dirname}/src/BetOnFlyby.py' cls.nef_path = path.replace('.py', '.nef') if not os.path.isfile(cls.nef_path): Boa3.compile_and_save(path, output_path=cls.nef_path)
def test_deploy_contract(self): path = self.get_contract_path('DeployContract.py') 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, None) self.assertEqual(5, len(result)) self.assertEqual(nef_file, result[3]) manifest_struct = NeoManifestStruct.from_json(manifest) self.assertEqual(manifest_struct, result[4])
def test_get_contract(self): from boa3.neo3.contracts import CallFlags call_flag = Integer(CallFlags.ALL).to_byte_array(signed=True, min_length=1) expected_output = ( Opcode.INITSLOT + b'\x00\x01' + Opcode.LDARG0 + Opcode.PUSH1 + Opcode.PACK + Opcode.PUSHDATA1 + Integer(len(Interop.GetContract.method_name)).to_byte_array(min_length=1) + String(Interop.GetContract.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('GetContract.py') output = Boa3.compile(path) self.assertEqual(expected_output, output) engine = TestEngine() result = self.run_smart_contract(engine, path, 'main', bytes(20)) self.assertIsNone(result) call_contract_path = self.get_contract_path('test_sc/arithmetic_test', 'Addition.py') Boa3.compile_and_save(call_contract_path) script, manifest = self.get_output(call_contract_path) nef, manifest = self.get_bytes_output(call_contract_path) call_hash = hash160(script) call_contract_path = call_contract_path.replace('.py', '.nef') engine.add_contract(call_contract_path) arg_manifest = json.dumps(manifest, separators=(',', ':')) result = self.run_smart_contract(engine, path, 'main', call_hash) self.assertEqual(5, len(result)) self.assertEqual(call_hash, result[2]) self.assertEqual(nef, result[3])
def compile_and_save(self, path: str, log: bool = True) -> Tuple[bytes, Dict[str, Any]]: nef_output = path.replace('.py', '.nef') manifest_output = path.replace('.py', '.manifest.json') from boa3.boa3 import Boa3 from boa3.neo.contracts.neffile import NefFile Boa3.compile_and_save(path, show_errors=log) with open(nef_output, mode='rb') as nef: file = nef.read() output = NefFile.deserialize(file).script with open(manifest_output) as manifest_output: import json manifest = json.loads(manifest_output.read()) return output, manifest
def main(): parser = argparse.ArgumentParser() parser.add_argument("input", help=".py smart contract to compile") args = parser.parse_args() if not args.input.endswith(".py") or not os.path.isfile(args.input): logging.error("Input file is not .py") sys.exit(1) fullpath = os.path.realpath(args.input) path, filename = os.path.split(fullpath) try: Boa3.compile_and_save(args.input) logging.info(f"Wrote {filename.replace('.py', '.nef')} to {path}") except NotLoadedException as e: logging.error("Could not compile") except Exception as e: logging.exception(e)
def test_call_contract_without_args(self): path = self.get_contract_path('CallScriptHashWithoutArgs.py') call_contract_path = self.get_contract_path('test_sc/list_test', 'IntList.py') Boa3.compile_and_save(call_contract_path) contract, manifest = self.get_output(call_contract_path) call_hash = hash160(contract) call_contract_path = call_contract_path.replace('.py', '.nef') engine = TestEngine() with self.assertRaises(TestExecutionException, msg=self.CALLED_CONTRACT_DOES_NOT_EXIST_MSG): self.run_smart_contract(engine, path, 'Main', call_hash, 'Main') engine.add_contract(call_contract_path) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'Main') self.assertEqual([1, 2, 3], result)
def test_get_call_flags(self): path = self.get_contract_path('CallScriptHashWithFlags.py') call_contract_path = self.get_contract_path('GetCallFlags.py') Boa3.compile_and_save(call_contract_path) engine = TestEngine() self.run_smart_contract(engine, call_contract_path, 'main') call_hash = engine.executed_script_hash.to_array() engine = TestEngine() call_contract_path = call_contract_path.replace('.py', '.nef') with self.assertRaises(TestExecutionException, msg=self.CALLED_CONTRACT_DOES_NOT_EXIST_MSG): self.run_smart_contract(engine, path, 'Main', call_hash, 'main') engine.add_contract(call_contract_path) from boa3.neo3.contracts import CallFlags result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.ALL) self.assertEqual(CallFlags.ALL, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.READ_ONLY) self.assertEqual(CallFlags.READ_ONLY, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.STATES) self.assertEqual(CallFlags.STATES, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.NONE) self.assertEqual(CallFlags.NONE, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.READ_STATES) self.assertEqual(CallFlags.READ_STATES, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.WRITE_STATES) self.assertEqual(CallFlags.WRITE_STATES, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.ALLOW_CALL) self.assertEqual(CallFlags.ALLOW_CALL, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'main', [], CallFlags.ALLOW_NOTIFY) self.assertEqual(CallFlags.ALLOW_NOTIFY, result)
def test_generate_nef_file(self): path = '%s/boa3_test/test_sc/generation_test/GenerationWithDecorator.py' % self.dirname expected_nef_output = path.replace('.py', '.nef') Boa3.compile_and_save(path) self.assertTrue(os.path.exists(expected_nef_output)) with open(expected_nef_output, 'rb') as nef_output: magic = nef_output.read(constants.SIZE_OF_INT32) compiler = nef_output.read(32) version = nef_output.read(16) hash = nef_output.read(constants.SIZE_OF_INT160) check_sum = nef_output.read(constants.SIZE_OF_INT32) script_size = nef_output.read(1) script = nef_output.read() self.assertEqual(int.from_bytes(script_size, BYTEORDER), len(script)) nef = NefFile(script)._nef self.assertEqual(compiler.decode(ENCODING), nef.compiler) self.assertEqual(hash, nef.script_hash.to_array()) self.assertEqual(check_sum, nef.checksum) self.assertEqual(version, nef.version.to_array())
def test_get_contract(self): path = self.get_contract_path('GetContract.py') engine = TestEngine() result = self.run_smart_contract(engine, path, 'main', bytes(20)) self.assertIsNone(result) call_contract_path = self.get_contract_path('test_sc/arithmetic_test', 'Addition.py') Boa3.compile_and_save(call_contract_path) script, manifest = self.get_output(call_contract_path) nef, manifest = self.get_bytes_output(call_contract_path) call_hash = hash160(script) call_contract_path = call_contract_path.replace('.py', '.nef') engine.add_contract(call_contract_path) result = self.run_smart_contract(engine, path, 'main', call_hash) self.assertEqual(5, len(result)) self.assertEqual(call_hash, result[2]) self.assertEqual(nef, result[3]) manifest_struct = NeoManifestStruct.from_json(manifest) self.assertEqual(manifest_struct, result[4])
def main(): parser = argparse.ArgumentParser() parser.add_argument("input", help=".py smart contract to compile") parser.add_argument("-db", "--debug", action='store_true', help="generates a .nefdbgnfo file") parser.add_argument( "--project-path", help="Project root path. Path of the contract by default.", type=str) args = parser.parse_args() if not args.input.endswith(".py") or not os.path.isfile(args.input): logging.error("Input file is not .py") sys.exit(1) fullpath = os.path.realpath(args.input) path, filename = os.path.split(fullpath) if not args.project_path: args.project_path = os.path.dirname(path) try: Boa3.compile_and_save(args.input, debug=args.debug, root_folder=args.project_path) logging.info(f"Wrote {filename.replace('.py', '.nef')} to {path}") except NotLoadedException as e: error_message = e.message log_error = 'Could not compile' if len(error_message) > 0: log_error += f': {error_message}' logging.error(log_error) except Exception as e: logging.exception(e)
def build_contract(path): Boa3.compile_and_save(path)
def test_call_contract_with_flags(self): path = self.get_contract_path('CallScriptHashWithFlags.py') call_contract_path = self.get_contract_path('CallFlagsUsage.py') Boa3.compile_and_save(call_contract_path) contract, manifest = self.get_output(call_contract_path) call_hash = hash160(contract) call_contract_path = call_contract_path.replace('.py', '.nef') engine = TestEngine() with self.assertRaises(TestExecutionException, msg=self.CALLED_CONTRACT_DOES_NOT_EXIST_MSG): self.run_smart_contract(engine, path, 'Main', call_hash, 'Main') engine.add_contract(call_contract_path) from boa3.neo3.contracts import CallFlags with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'Main', call_hash, 'get_value', ['num'], CallFlags.NONE) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'get_value', ['num'], CallFlags.READ_ONLY) self.assertEqual(0, result) with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'Main', call_hash, 'put_value', ['num', 10], CallFlags.READ_ONLY) self.run_smart_contract(engine, path, 'Main', call_hash, 'put_value', ['num', 10], CallFlags.NONE) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'put_value', ['num', 10], CallFlags.STATES) self.assertEqual(None, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'get_value', ['num'], CallFlags.READ_ONLY) self.assertEqual(10, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'put_value', ['num', 99], CallFlags.ALL) self.assertEqual(None, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'get_value', ['num'], CallFlags.READ_ONLY) self.assertEqual(99, result) with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'Main', call_hash, 'notify_user', [], CallFlags.READ_ONLY) self.run_smart_contract(engine, path, 'Main', call_hash, 'notify_user', [], CallFlags.STATES) self.run_smart_contract(engine, path, 'Main', call_hash, 'notify_user', [], CallFlags.NONE) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'notify_user', [], CallFlags.ALL) self.assertEqual(None, result) notify = engine.notifications self.assertEqual(1, len(notify)) self.assertEqual('Notify was called', notify[0].arguments[0]) with self.assertRaises(TestExecutionException): self.run_smart_contract(engine, path, 'Main', call_hash, 'call_another_contract', [], CallFlags.STATES) self.run_smart_contract(engine, path, 'Main', call_hash, 'call_another_contract', [], CallFlags.NONE) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'call_another_contract', [], CallFlags.ALL) self.assertEqual(0, result) result = self.run_smart_contract(engine, path, 'Main', call_hash, 'call_another_contract', [], CallFlags.READ_ONLY) self.assertEqual(0, result)