def _verify_is_valid_contract_hash(contract_hash: str) -> bool: """ Verifies if a given contract hash is valid. :return: whether the given contract hash is valid or not """ if contract_hash.startswith('0x'): try: from boa3.neo3.core.types import UInt160 # if contract_hash is not a valid UInt160, it will raise a ValueError UInt160.from_string(contract_hash[2:]) return True except ValueError: pass return False
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 _get_script_hash(self) -> Optional[bytes]: try: return UInt160.from_string( self._contract_hash[2:] if self._contract_hash. startswith('0x') else self._contract_hash).to_array() except BaseException: return None
def _get_script_from_str(cls, script: str) -> bytes: if isinstance(script, str): if script.startswith('0x'): str_script = script[2:] else: str_script = script script = UInt160.from_string(str_script).to_array() return script
def test_contract_manual_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 = ( # start public method Opcode.LDSFLD0 # generated cls arg + Opcode.CALL + Integer(35).to_byte_array() + Opcode.RET # end public method # start initialize method + Opcode.INITSSLOT + b'\x01' + Opcode.PUSH1 + Opcode.NEWARRAY + Opcode.STSFLD0 + Opcode.PUSHDATA1 + Integer(len(contract_script_bytes)).to_byte_array() + contract_script_bytes + Opcode.PUSH0 + Opcode.LDSFLD0 + Opcode.REVERSE3 + Opcode.SETITEM + Opcode.RET # end initialize method # start 'symbol' class method + Opcode.INITSLOT + b'\x00\x01' + Opcode.NEWARRAY0 # arguments list + Opcode.PUSH15 # CallFlag + Opcode.PUSHDATA1 # function name + Integer(len(function_name_bytes)).to_byte_array() + function_name_bytes + Opcode.LDARG0 # contract script + Opcode.PUSH0 + Opcode.PICKITEM + Opcode.SYSCALL + Interop.CallContract.interop_method_hash + Opcode.RET # start class method ) path = self.get_contract_path( 'ContractManualInterfaceCodeOptimization.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 from_json(cls, json: Dict[str, Any]) -> TestRunnerLog: """ Creates a Log object from a json. :param json: json that contains the log data :return: a Log object :rtype: TestRunnerLog """ keys = set(json.keys()) if not keys.issubset([cls._contract_key, cls._message_key]): return None script: bytes = json[ cls._contract_key] if cls._contract_key in json else b'' message: str = json[ cls._message_key] if cls._message_key in json else "" if isinstance(script, str): script = UInt160.from_string( script[2:] if script.startswith('0x') else script).to_array() return cls(script, message)
def _get_contract_hash_or_name( self, contract_id: Union[str, bytes]) -> Union[str, UInt160]: if isinstance(contract_id, str): if contract_id in self._contracts: contract = self._contracts[contract_id] return contract.name if hasattr( contract, 'name') else contract.script_hash try: return UInt160.from_string(contract_id) except BaseException as e: if not contract_id.endswith('.nef'): raise e manifest_file = contract_id.replace('.nef', '.manifest.json') if os.path.exists(manifest_file): with open(manifest_file) as manifest_output: import json manifest = json.loads(manifest_output.read()) return manifest['name'] raise e else: return UInt160(contract_id)
def run(self, contract_id: Union[str, UInt160], method: str, *arguments: Any, reset_engine: bool = False, rollback_on_fault: bool = True) -> Any: import json import subprocess if isinstance(contract_id, str) and contract_id not in self.contracts: self.add_contract(contract_id) # build an UInt160 value if the contract_id is not a path if isinstance(contract_id, bytes) and not isinstance(contract_id, UInt160): contract_id = UInt160(contract_id) test_engine_args = self.to_json(contract_id, method, *arguments) param_json = json.dumps(test_engine_args, separators=(',', ':')) try: process = subprocess.Popen(['dotnet', self._test_engine_path, param_json], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) except BaseException: json_path = '{0}/test-engine-test.json'.format(path.curdir) with open(json_path, 'wb+') as json_file: json_file.write(String(param_json).to_bytes()) json_file.close() process = subprocess.Popen(['dotnet', self._test_engine_path, json_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) stdout, stderr = process.communicate() if reset_engine: self.reset_engine() else: self.reset_state() stdout = stdout.splitlines()[-1] try: result = json.loads(stdout) self._error_message = result['error'] if 'error' in result else None if 'vmstate' in result: self._vm_state = VMState.get_vm_state(result['vmstate']) if 'executedscripthash' in result: self._executed_script_hash = UInt160.from_string(result['executedscripthash']) if 'gasconsumed' in result: self._gas_consumed = int(result['gasconsumed']) if 'resultstack' in result: if isinstance(result['resultstack'], list): self._result_stack = [stack_item_from_json(value) for value in result['resultstack']] else: self._result_stack = [stack_item_from_json(result['resultstack'])] if self._vm_state is VMState.HALT or not rollback_on_fault: if 'notifications' in result: json_storage = result['notifications'] if not isinstance(json_storage, list): json_storage = [json_storage] notifications = [] for n in json_storage: new = Notification.from_json(n) if new is not None: notifications.append(new) self._notifications.extend(notifications) if 'storage' in result: json_storage = result['storage'] self._storage = Storage.from_json(json_storage) for contract in self._contract_paths.copy(): if (not isinstance(contract, TestContract) or contract.script_hash is None or not self._storage.has_contract(contract.script_hash)): self.remove_contract(contract.path) if 'currentblock' in result: current_block = Block.from_json(result['currentblock']) existing_block = next((block for block in self._blocks if block.index == current_block.index), None) if existing_block is not None: self._blocks.remove(existing_block) self._blocks.append(current_block) if 'transaction' in result and self._vm_state is VMState.HALT: block = self.current_block if block is None: block = self.increase_block(self.height) tx = Transaction.from_json(result['transaction']) block.add_transaction(tx) except BaseException as e: self._error_message = str(e) # TODO: convert the result to the return type of the function in the manifest return self._result_stack[-1] if len(self._result_stack) > 0 else VoidType