def get_invoke_result(self, script, container=None): appengine = ApplicationEngine.Run(script=script, container=container) return { "script": script.decode('utf-8'), "state": VMStateStr(appengine.State), "gas_consumed": appengine.GasConsumed().ToString(), "stack": [ContractParameter.ToParameter(item).ToJson() for item in appengine.EvaluationStack.Items] }
def get_invoke_result(self, script): appengine = ApplicationEngine.Run(script=script) return { "script": script.hex(), "state": appengine.State, "gas_consumed": appengine.GasConsumed().ToString(), "stack": [ContractParameter.ToParameter(item).ToJson() for item in appengine.EvaluationStack.Items] }
def get_invoke_result(self, script): snapshot = GetBlockchain()._db.createSnapshot() appengine = ApplicationEngine.Run(snapshot, script=script) return { "script": script.decode('utf-8'), "state": VMStateStr(appengine.State), "gas_consumed": appengine.GasConsumed().ToString(), "stack": [ContractParameter.ToParameter(item).ToJson() for item in appengine.ResultStack.Items] }
def ExecutionCompleted(self, engine, success, error=None): height = Blockchain.Default().Height + 1 tx_hash = None if engine.ScriptContainer: tx_hash = engine.ScriptContainer.Hash if not tx_hash: tx_hash = UInt256(data=bytearray(32)) entry_script = None try: # get the first script that was executed # this is usually the script that sets up the script to be executed entry_script = UInt160(data=engine.ExecutedScriptHashes[0]) # ExecutedScriptHashes[1] will usually be the first contract executed if len(engine.ExecutedScriptHashes) > 1: entry_script = UInt160(data=engine.ExecutedScriptHashes[1]) except Exception as e: logger.error("Could not get entry script: %s " % e) payload = ContractParameter(ContractParameterType.Array, value=[]) for item in engine.EvaluationStack.Items: payload.Value.append(ContractParameter.ToParameter(item)) if success: # dispatch all notify events, along with the success of the contract execution for notify_event_args in self.notifications: self.events_to_dispatch.append(NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, notify_event_args.State, notify_event_args.ScriptHash, height, tx_hash, success, engine.testMode)) if engine.Trigger == Application: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.EXECUTION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.VERIFICATION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: payload.Value.append(ContractParameter(ContractParameterType.String, error)) payload.Value.append(ContractParameter(ContractParameterType.String, engine._VMState)) if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) self.notifications = []
def test_invoke_contract(self, args): if not self.Wallet: print("Please open a wallet") return args, from_addr = get_from_addr(args) args, invoke_attrs = get_tx_attr_from_args(args) args, owners = get_owners_from_params(args) if args and len(args) > 0: tx, fee, results, num_ops = TestInvokeContract( self.Wallet, args, from_addr=from_addr, invoke_attrs=invoke_attrs, owners=owners) if tx is not None and results is not None: parameterized_results = [ ContractParameter.ToParameter(item) for item in results ] print( "\n-------------------------------------------------------------------------------------------------------------------------------------" ) print("Test invoke successful") print("Total operations: %s" % num_ops) print("Results %s" % [item.ToJson() for item in parameterized_results]) print("Invoke TX GAS cost: %s" % (tx.Gas.value / Fixed8.D)) print("Invoke TX fee: %s" % (fee.value / Fixed8.D)) print( "-------------------------------------------------------------------------------------------------------------------------------------\n" ) print( "Enter your password to continue and invoke on the network\n" ) tx.Attributes = invoke_attrs passwd = prompt("[password]> ", is_password=True) if not self.Wallet.ValidatePassword(passwd): return print("Incorrect password") InvokeContract(self.Wallet, tx, fee, from_addr=from_addr, owners=owners) return else: print("Error testing contract invoke") return print("Please specify a contract to invoke")
def execute(self, arguments): wallet = PromptData.Wallet if not wallet: print("Please open a wallet") return False arguments, from_addr = PromptUtils.get_from_addr(arguments) arguments, invoke_attrs = PromptUtils.get_tx_attr_from_args(arguments) arguments, owners = PromptUtils.get_owners_from_params(arguments) if len(arguments) < 1: print("Please specify the required parameters") return False hash_string = arguments[0] try: script_hash = UInt160.ParseString(hash_string) except Exception: # because UInt160 throws a generic exception. Should be fixed in the future print("Invalid script hash") return False tx, fee, results, num_ops, engine_success = TestInvokeContract(wallet, arguments, from_addr=from_addr, invoke_attrs=invoke_attrs, owners=owners) if tx and results: parameterized_results = [ContractParameter.ToParameter(item).ToJson() for item in results] print( "\n-------------------------------------------------------------------------------------------------------------------------------------") print("Test invoke successful") print(f"Total operations: {num_ops}") print(f"Results {str(parameterized_results)}") print(f"Invoke TX GAS cost: {tx.Gas.value / Fixed8.D}") print(f"Invoke TX fee: {fee.value / Fixed8.D}") print( "-------------------------------------------------------------------------------------------------------------------------------------\n") print("Enter your password to continue and invoke on the network\n") tx.Attributes = invoke_attrs passwd = prompt("[password]> ", is_password=True) if not wallet.ValidatePassword(passwd): return print("Incorrect password") return InvokeContract(wallet, tx, fee, from_addr=from_addr, owners=owners) else: print("Error testing contract invoke") return False
def get_invoke_result_balance(self, script): appengine = ApplicationEngine.Run(script=script) val = appengine.EvaluationStack.Items[0].GetBigInteger() balance = Decimal(val) return { "script": script.decode('utf-8'), "state": VMStateStr(appengine.State), "gas_consumed": appengine.GasConsumed().ToString(), "stack": [ ContractParameter.ToParameter(item).ToJson() for item in appengine.EvaluationStack.Items ], "balance": str(balance) }
def Runtime_Notify(self, engine: ExecutionEngine): state = engine.CurrentContext.EvaluationStack.Pop() payload = ContractParameter.ToParameter(state) args = NotifyEventArgs( engine.ScriptContainer, UInt160(data=engine.CurrentContext.ScriptHash()), payload) self.notifications.append(args) if settings.emit_notify_events_on_sc_execution_error: # emit Notify events even if the SC execution might fail. tx_hash = engine.ScriptContainer.Hash height = GetBlockchain().Height + 1 success = None self.events_to_dispatch.append( NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, args.ScriptHash, height, tx_hash, success, engine.testMode)) return True
def start(self): self.continue_debug = True # pprint.pprint(self.debug_map) dbg_title = self.debug_map['avm']['name'] print("\n") print("======= debug engine enter =======") ctx = self.get_context() ctx.print() while self.continue_debug: try: result = prompt("[%s debug]> " % dbg_title) except EOFError: # Control-D pressed: quit self.continue_debug = False except KeyboardInterrupt: # Control-C pressed: do nothing self.continue_debug = False command, arguments = self.parser.parse_input(result) if command is not None and len(command) > 0: command = command.lower() if command in ['quit', 'exit', 'cont']: self.continue_debug = False elif command == 'estack': if self.engine._InvocationStack.Count > 0: # eval stack now only available via ExecutionContext objects in the istack if len(self.engine.CurrentContext.EvaluationStack.Items ): for item in self.engine.CurrentContext.EvaluationStack.Items: print( ContractParameter.ToParameter( item).ToJson()) else: print("Evaluation stack empty") else: print("Evaluation stack empty") elif command == 'istack': print("Invocation Stack:") for item in self.engine.InvocationStack.Items: pprint.pprint(item) print(vars(item)) elif command == 'astack': if len(self.engine.AltStack.Items): for item in self.engine.AltStack.Items: print(ContractParameter.ToParameter(item).ToJson()) else: print("Alt Stack Empty") elif command == 'rstack': items = self.engine.ResultStack.Items if len(items): for item in items: pprint.pprint(item) else: print("Result stack empty") elif command == 'ctx': ctx.print() elif command == 'file': ctx.print_file() elif command == 'ops': ctx.print_method_ops() elif command == 'pdb': pdb.set_trace() elif command == 'help': print( "Use one of [estack, istack, astack, exit, quit, ctx, file, ops, pdb, or any local variable]" ) elif command in ctx.method.scope: try: idx = ctx.method.scope[command] value = self.engine.AltStack.Items[-1].GetArray()[idx] param = ContractParameter.ToParameter(value) print("\n") print( '%s = %s [%s]' % (command, json.dumps(param.Value.ToJson(), indent=4) if param.Type == ContractParameterType.InteropInterface else param.Value, param.Type)) print("\n") except Exception as e: logger.error("Could not lookup item %s: %s " % (command, e)) else: print("unknown command: %s " % command) print("======= debug engine exit =======") print("\n")
def ExecutionCompleted(self, engine, success, error=None): height = Blockchain.Default().Height + 1 tx_hash = None if engine.ScriptContainer: tx_hash = engine.ScriptContainer.Hash if not tx_hash: tx_hash = UInt256(data=bytearray(32)) entry_script = None try: # get the first script that was executed # this is usually the script that sets up the script to be executed entry_script = UInt160(data=engine.ExecutedScriptHashes[0]) # ExecutedScriptHashes[1] will usually be the first contract executed if len(engine.ExecutedScriptHashes) > 1: entry_script = UInt160(data=engine.ExecutedScriptHashes[1]) except Exception as e: logger.error("Could not get entry script: %s " % e) payload = ContractParameter(ContractParameterType.Array, value=[]) for item in engine.ResultStack.Items: payload.Value.append(ContractParameter.ToParameter(item)) if success: # dispatch all notify events, along with the success of the contract execution for notify_event_args in self.notifications: self.events_to_dispatch.append(NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, notify_event_args.State, notify_event_args.ScriptHash, height, tx_hash, success, engine.testMode)) if engine.Trigger == Application: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.EXECUTION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.VERIFICATION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: # when a contract exits in a faulted state # we should display that in the notification if not error: error = 'Execution exited in a faulted state. Any payload besides this message contained in this event is the contents of the EvaluationStack of the current script context.' payload.Value.append(ContractParameter(ContractParameterType.String, error)) # If we do not add the eval stack, then exceptions that are raised in a contract # are not displayed to the event consumer [payload.Value.append(ContractParameter.ToParameter(item)) for item in engine.CurrentContext.EvaluationStack.Items] if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) self.notifications = []
def execute(self, arguments): wallet = PromptData.Wallet if not wallet: print("Please open a wallet") return False arguments, from_addr = PromptUtils.get_from_addr(arguments) arguments, priority_fee = PromptUtils.get_fee(arguments) arguments, invoke_attrs = PromptUtils.get_tx_attr_from_args(arguments) arguments, owners = PromptUtils.get_owners_from_params(arguments) arguments, return_type = PromptUtils.get_return_type_from_args(arguments) if len(arguments) < 1: print("Please specify the required parameters") return False hash_string = arguments[0] try: script_hash = UInt160.ParseString(hash_string) except Exception: # because UInt160 throws a generic exception. Should be fixed in the future print("Invalid script hash") return False p_fee = Fixed8.Zero() if priority_fee is not None: p_fee = priority_fee if p_fee is False: logger.debug("invalid fee") return False tx, fee, results, num_ops, engine_success = TestInvokeContract(wallet, arguments, from_addr=from_addr, invoke_attrs=invoke_attrs, owners=owners) if tx and results: if return_type is not None: try: parameterized_results = [ContractParameter.AsParameterType(ContractParameterType.FromString(return_type), item).ToJson() for item in results] except ValueError: logger.debug("invalid return type") return False else: parameterized_results = [ContractParameter.ToParameter(item).ToJson() for item in results] print( "\n-------------------------------------------------------------------------------------------------------------------------------------") print("Test invoke successful") print(f"Total operations: {num_ops}") print(f"Results {str(parameterized_results)}") print(f"Invoke TX GAS cost: {tx.Gas.value / Fixed8.D}") print(f"Invoke TX fee: {fee.value / Fixed8.D}") print( "-------------------------------------------------------------------------------------------------------------------------------------\n") comb_fee = p_fee + fee if comb_fee != fee: print(f"Priority Fee ({p_fee.value / Fixed8.D}) + Invoke TX Fee ({fee.value / Fixed8.D}) = {comb_fee.value / Fixed8.D}\n") print("Enter your password to send this invocation to the network") tx.Attributes = invoke_attrs try: passwd = prompt("[password]> ", is_password=True) except KeyboardInterrupt: print("Invocation cancelled") return False if not wallet.ValidatePassword(passwd): return print("Incorrect password") return InvokeContract(wallet, tx, comb_fee, from_addr=from_addr, owners=owners) else: print("Error testing contract invoke") return False