def _generate_tx(self): wallet = self.GetWallet1() output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, Value=Fixed8.One(), script_hash=LeaderTestCase.wallet_1_script_hash) contract_tx = ContractTransaction(outputs=[output]) wallet.MakeTransaction(contract_tx) ctx = ContractParametersContext(contract_tx) wallet.Sign(ctx) contract_tx.scripts = ctx.GetScripts() return contract_tx
def InvokeContract(wallet, tx, fee=Fixed8.Zero(), from_addr=None, owners=None): if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True, from_addr=from_addr) except ValueError: print("Insufficient funds") return False if wallet_tx: if owners: for owner in list(owners): wallet_tx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) wallet_tx.Attributes = make_unique_script_attr(tx.Attributes) context = ContractParametersContext(wallet_tx) wallet.Sign(context) if owners: gather_signatures(context, wallet_tx, list(owners)) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = False # print("SENDING TX: %s " % json.dumps(wallet_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(wallet_tx) if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) wallet.SaveTransaction(wallet_tx) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def InvokeWithTokenVerificationScript(wallet, tx, token, fee=Fixed8.Zero(), invoke_attrs=None): wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True) if wallet_tx: token_contract_state = Blockchain.Default().GetContract(token.ScriptHash.ToString()) print("token contract %s " % token_contract_state) tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=token.ScriptHash.Data) ] if invoke_attrs: tx.Attributes += invoke_attrs reedeem_script = token_contract_state.Code.Script.hex() # there has to be at least 1 param, and the first # one needs to be a signature param param_list = bytearray(b'\x00\x00') verification_contract = Contract.Create(reedeem_script, param_list, wallet.GetDefaultContract().PublicKeyHash) context = ContractParametersContext(wallet_tx) wallet.Sign(context) context.Add(verification_contract, 0, 0) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = NodeLeader.Instance().Relay(wallet_tx) if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) # if it was relayed, we save tx wallet.SaveTransaction(wallet_tx) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def example2(): source_address = "AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3" source_script_hash = address_to_scripthash(source_address) # start by creating a base InvocationTransaction # the inputs, outputs and Type do not have to be set anymore. invocation_tx = InvocationTransaction() # Since we are building a raw transaction, we will add the raw_tx flag invocation_tx.raw_tx = True # often times smart contract developers use the function ``CheckWitness`` to determine if the transaction is signed by somebody eligible of calling a certain method # in order to pass that check you want to add the corresponding script_hash as a transaction attribute (this is generally the script_hash of the public key you use for signing) # Note that for public functions like the NEP-5 'getBalance' and alike this would not be needed, but it doesn't hurt either invocation_tx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=source_script_hash)) # next we need to build a 'script' that gets executed against the smart contract. # this is basically the script that calls the entry point of the contract with the necessary parameters smartcontract_scripthash = UInt160.ParseString( "31730cc9a1844891a3bafd1aa929a4142860d8d3") sb = ScriptBuilder() # call the NEP-5 `name` method on the contract (assumes contract address is a NEP-5 token) sb.EmitAppCallWithOperation(smartcontract_scripthash, 'name') invocation_tx.Script = binascii.unhexlify(sb.ToArray()) # at this point we've build our unsigned transaction and it's time to sign it before we get the raw output that we can send to the network via RPC # we need to create a Wallet instance for helping us with signing wallet = UserWallet.Create('path', to_aes_key('mypassword'), generate_default_key=False) # if you have a WIF use the following # this WIF comes from the `neo-test1-w.wallet` fixture wallet private_key = KeyPair.PrivateKeyFromWIF( "Ky94Rq8rb1z8UzTthYmy1ApbZa9xsKTvQCiuGUZJZbaDJZdkvLRV") # if you have a NEP2 encrypted key use the following instead # private_key = KeyPair.PrivateKeyFromNEP2("NEP2 key string", "password string") # we add the key to our wallet wallet.CreateKey(private_key) # and now we're ready to sign context = ContractParametersContext(invocation_tx) wallet.Sign(context) invocation_tx.scripts = context.GetScripts() raw_tx = invocation_tx.ToArray() return raw_tx
def create_tx(contract_hash, address_from, address_to, tnc_amount, gas_change, input_txid, preIndex): nep5TokenId = get_nep5token_id(contract_hash) scripthash_from = ToScriptHash(address_from) scripthash_to = ToScriptHash(address_to) f8amount = amount_from_string(nep5TokenId, tnc_amount) f8amount_change = Fixed8.TryParse(gas_change, require_positive=True) assetId = get_asset_id("gas") preHash = UInt256(data=binascii.unhexlify(hex_reverse(input_txid))) input = TransactionInput(prevHash=preHash, prevIndex=preIndex) output = TransactionOutput(AssetId=assetId, Value=f8amount_change, script_hash=scripthash_from) tx = InvocationTransaction(outputs=[output], inputs=[input]) tx.Version = 1 context = ContractParametersContext(tx) tx.scripts = context.GetScripts() invoke_args = [ nep5TokenId.ScriptHash, 'transfer', [ bytearray.fromhex(hex_reverse(scripthash_from.ToString())), bytearray.fromhex(hex_reverse(scripthash_to.ToString())), BigInteger(f8amount) ] ] sb = ScriptBuilder() invoke_args.reverse() for item in invoke_args[:2]: if type(item) is list: item.reverse() listlength = len(item) for listitem in item: sb.push(listitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(binascii.hexlify(item.encode())) sb.EmitAppCall(nep5TokenId.ScriptHash.ToArray()) op_data = sb.ToArray().decode() tx.Script = binascii.unhexlify(op_data) tx_data = get_tx_data(tx)[:-2] print("tx_data:", tx_data) signstr = binascii.hexlify( Crypto.Sign(message=tx_data, private_key=private_key)).decode() rawtx_data = tx_data + "014140" + signstr + "2321" + public_key + "ac" return rawtx_data
def begin_send(wallet, arguments): to_send = arguments[0] address_to = arguments[1] amount = arguments[2] from_address = arguments[3] assetId = None if to_send == 'neo': assetId = Blockchain.Default().SystemShare().Hash else: assetId = Blockchain.Default().SystemCoin().Hash scripthash_to = wallet.ToScriptHash(address_to) scripthash_from = wallet.ToScriptHash(from_address) f8amount = Fixed8.TryParse(amount) if f8amount.value % pow( 10, 8 - Blockchain.Default().GetAssetState( assetId.ToBytes()).Precision) != 0: print("incorrect amount precision") return fee = Fixed8.Zero() output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to) tx = ContractTransaction(outputs=[output]) ttx = wallet.MakeTransaction(tx=tx, change_address=None, fee=fee, from_addr=scripthash_from) if ttx is None: print( "insufficient funds, were funds already moved from multi-sig contract?" ) return None context = ContractParametersContext(tx, isMultiSig=True) wallet.Sign(context) if context.Completed: print("Something went wrong, multi-sig transaction failed") return None else: print("Transaction initiated") return json.dumps(context.ToJson(), separators=(',', ':'))
def sign_context(binary_tx, private): wallet = Wallet(b'', b'0' * 32, True) wallet.CreateKey(binascii.unhexlify(private)) script_hash = WalletContract.CreateSignatureContract( list(wallet._keys.values())[0].PublicKey) wallet._contracts[script_hash.ScriptHash.ToBytes()] = script_hash tx = ContractTransaction.DeserializeFromBufer( binascii.unhexlify(binary_tx)) context = ContractParametersContext(tx, isMultiSig=False) context.ScriptHashes = [script_hash.ScriptHash] wallet.Sign(context) return [x.ToJson() for x in context.GetScripts()]
def InvokeContract(wallet, tx, fee=Fixed8.Zero(), from_addr=None, owners=None): if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True, from_addr=from_addr) except ValueError: print("Insufficient funds") return False if wallet_tx: if owners: for owner in list(owners): wallet_tx.Attributes.append(TransactionAttribute(usage=TransactionAttributeUsage.Script, data=owner)) wallet_tx.Attributes = make_unique_script_attr(tx.Attributes) context = ContractParametersContext(wallet_tx) wallet.Sign(context) if owners: gather_signatures(context, wallet_tx, list(owners)) if context.Completed: wallet_tx.scripts = context.GetScripts() passed, reason = validate_simple_policy(wallet_tx) if not passed: print(reason) return False nodemgr = NodeManager() relayed = nodemgr.relay(wallet_tx) if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) wallet.SaveTransaction(wallet_tx) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def test_9_send_neo_tx(self): wallet = self.GetWallet1() tx = ContractTransaction() tx.outputs = [TransactionOutput(Blockchain.SystemShare().Hash, Fixed8.FromDecimal(10.0), self.import_watch_addr)] tx = wallet.MakeTransaction(tx) cpc = ContractParametersContext(tx) wallet.Sign(cpc) tx.scripts = cpc.GetScripts() result = NodeLeader.Instance().Relay(tx) self.assertEqual(result, True)
def _generate_tx(self, amount): wallet = self.GetWallet1() output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=amount, script_hash=LeaderTestCase.wallet_1_script_hash) contract_tx = ContractTransaction(outputs=[output]) try: wallet.MakeTransaction(contract_tx) except ValueError: pass ctx = ContractParametersContext(contract_tx) wallet.Sign(ctx) contract_tx.scripts = ctx.GetScripts() return contract_tx
def _make_tx(self, addr_to): """ process transaction """ output1 = TransactionOutput( AssetId = Blockchain.SystemCoin().Hash, # hash of the Gas transaction Value = Fixed8.FromDecimal(2000), # this is how much gas each request will provide script_hash = addr_to # address to send the Gas to ) output2 = TransactionOutput( AssetId = Blockchain.SystemShare().Hash, # hash of the NEO token transaction Value = Fixed8.FromDecimal(100), # this is how much NEO each request will provide script_hash = addr_to # address to send the NEO tokens too ) contract_tx = ContractTransaction() # creates an instance of the transaction contract_tx.outputs = [output1, output2] # outputs the data from the transaction contract_tx = self.wallet.MakeTransaction(contract_tx) # processes transaction print("tx to json: %s " % json.dumps(contract_tx.ToJson(), indent=4)) context = ContractParametersContext(contract_tx, isMultiSig=False) # getting the contract context (listed above) self.wallet.Sign(context) # signs the contract if context.Completed: contract_tx.scripts = context.GetScripts() # gets the script hashes from the context self.wallet.SaveTransaction(contract_tx) # update the state of the coins in the wallet # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(contract_tx) # relay the transaction to this instance of the node leader if relayed: # if tx relay was successful, inform the user and return the contract transaction print("Relayed Tx: %s " % contract_tx.Hash.ToString()) return contract_tx else: print("Could not relay tx %s " % contract_tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False return False
def _make_tx(self, addr_to): output1 = TransactionOutput( AssetId = Blockchain.SystemCoin().Hash, Value = Fixed8.FromDecimal(2000), script_hash = addr_to ) output2 = TransactionOutput( AssetId = Blockchain.SystemShare().Hash, Value = Fixed8.FromDecimal(100), script_hash = addr_to ) contract_tx = ContractTransaction() contract_tx.outputs = [output1, output2] contract_tx = self.wallet.MakeTransaction(contract_tx) print("tx to json: %s " % json.dumps(contract_tx.ToJson(), indent=4)) context = ContractParametersContext(contract_tx, isMultiSig=False) self.wallet.Sign(context) if context.Completed: contract_tx.scripts = context.GetScripts() self.wallet.SaveTransaction(contract_tx) # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(contract_tx) if relayed: print("Relayed Tx: %s " % contract_tx.Hash.ToString()) return contract_tx else: print("Could not relay tx %s " % contract_tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False return False
def InvokeContract(wallet, tx, fee=Fixed8.Zero(), from_addr=None): if from_addr is not None: from_addr = lookup_addr_str(wallet, from_addr) wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True, from_addr=from_addr) # pdb.set_trace() if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = False # print("SENDING TX: %s " % json.dumps(wallet_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(wallet_tx) if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) wallet.SaveTransaction(wallet_tx) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def PerformWithdrawTx(wallet, tx, contract_hash): requestor_contract = wallet.GetDefaultContract() withdraw_contract_state = Blockchain.Default().GetContract( contract_hash.encode('utf-8')) reedeem_script = withdraw_contract_state.Code.Script.hex() # there has to be at least 1 param, and the first # one needs to be a signature param param_list = bytearray(b'\x00') # if there's more than one param # we set the first parameter to be the signature param if len(withdraw_contract_state.Code.ParameterList) > 1: param_list = bytearray(withdraw_contract_state.Code.ParameterList) param_list[0] = 0 verification_contract = Contract.Create(reedeem_script, param_list, requestor_contract.PublicKeyHash) context = ContractParametersContext(tx) context.Add(verification_contract, 0, bytearray(0)) if context.Completed: tx.scripts = context.GetScripts() print("withdraw tx %s " % json.dumps(tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(tx) if relayed: # wallet.SaveTransaction(tx) # dont save this tx print("Relayed Withdrawal Tx: %s " % tx.Hash.ToString()) return tx else: print("Could not relay witdrawal tx %s " % tx.Hash.ToString()) else: print("Incomplete signature") return False
def testNeoClient(): invocation_tx = InvocationTransaction() smartcontract_scripthash = UInt160.ParseString(CONTRACT_HASH) sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs( smartcontract_scripthash, 'onboard', [b'Munich', b'*****@*****.**', b'xxx']) invocation_tx.Script = binascii.unhexlify(sb.ToArray()) wallet = UserWallet.Create('neo-privnet.wallet', to_aes_key('coz'), generate_default_key=False) private_key = KeyPair.PrivateKeyFromWIF( "KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr") wallet.CreateKey(private_key) context = ContractParametersContext(invocation_tx) wallet.Sign(context) invocation_tx.scripts = context.GetScripts() raw_tx = invocation_tx.ToArray() payload = { "jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": [raw_tx.decode("ascii")] } res = requests.post("http://neo-nodes:30333/testNeoConnection", json=payload) print("received POST result") print(res.status_code) result = res.text print(result) return json.dumps({ "raw_tx": raw_tx.decode("ascii"), "result": result, "payload": payload, })
def SendBlog(wallet, tx, fee=Fixed8.Zero(), from_addr=None, privatekey=None): wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=False, from_addr=from_addr) # wallet_tx = tx if wallet_tx: context = ContractParametersContext(wallet_tx) if privatekey != None: prikey = KeyPair.PrivateKeyFromWIF(privatekey) kp = KeyPair(prikey) wallet.Sign(context, kp) else: wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = False # print("SENDING TX: %s " % json.dumps(wallet_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(wallet_tx) print("Tx: %s " % wallet_tx.ToJson()) if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) wallet.SaveTransaction(wallet_tx) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def InvokeContract(wallet, tx, fee=Fixed8.Zero()): wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True) # pdb.set_trace() if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = False # print("SENDING TX: %s " % json.dumps(wallet_tx.ToJson(), indent=4)) # check if we can save the tx first save_tx = wallet.SaveTransaction(wallet_tx) if save_tx: relayed = NodeLeader.Instance().Relay(wallet_tx) else: print("Could not save tx to wallet, will not send tx") if relayed: print("Relayed Tx: %s " % wallet_tx.Hash.ToString()) return wallet_tx else: print("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: print("Incomplete signature") else: print("Insufficient funds") return False
def test_9_send_neo_tx(self): with patch('neo.Network.node.NeoNode.relay', return_value=self.async_return(True)): wallet = self.GetWallet1() tx = ContractTransaction() tx.outputs = [TransactionOutput(Blockchain.SystemShare().Hash, Fixed8.FromDecimal(10.0), self.import_watch_addr)] try: tx = wallet.MakeTransaction(tx) except (ValueError): pass cpc = ContractParametersContext(tx) wallet.Sign(cpc) tx.scripts = cpc.GetScripts() nodemgr = NodeManager() # we need at least 1 node for relay to be mocked nodemgr.nodes = [NeoNode(object, object)] result = nodemgr.relay(tx) self.assertEqual(result, True)
def InvokeContract(wallet, tx, fee=Fixed8.Zero()): wallet_tx = wallet.MakeTransaction(tx=tx, fee=fee, use_standard=True) # pdb.set_trace() if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() relayed = False # print("SENDING TX: %s " % json.dumps(wallet_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(wallet_tx) if relayed: logger.info("Relayed Tx: %s " % wallet_tx.Hash.ToString()) wallet.SaveTransaction(wallet_tx) return wallet_tx else: logger.error("Could not relay tx %s " % wallet_tx.Hash.ToString()) raise RuntimeError("Could not relay tx %s " % wallet_tx.Hash.ToString()) else: logger.error("Incomplete signature") raise RuntimeError('Incomplete signature') else: logger.error("Insufficient funds") raise RuntimeError('Insufficient funds') return False
def process_transaction(self, contract_tx, fee=None, address_from=None, change_addr=None): standard_contract = self.wallet.GetStandardAddress() signer_contract = self.wallet.GetContract(standard_contract) try: tx = self.wallet.MakeTransaction(tx=contract_tx, change_address=change_addr, fee=fee, from_addr=address_from) except ValueError: # if not enough unspents while fully synced raise JsonRpcError(-300, "Insufficient funds") if tx is None: # if not enough unspents while not being fully synced raise JsonRpcError(-300, "Insufficient funds") data = standard_contract.Data tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data) ] context = ContractParametersContext( tx, isMultiSig=signer_contract.IsMultiSigContract ) self.wallet.Sign(context) if context.Completed: tx.scripts = context.GetScripts() passed, reason = validate_simple_policy(tx) if not passed: raise JsonRpcError(-32602, reason) relayed = self.nodemgr.relay(tx) if relayed: self.wallet.SaveTransaction(tx) return tx.ToJson() else: raise JsonRpcError(-32602, "Invalid params") else: return context.ToJson()
def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_change=None, fee=None, owners=None, user_tx_attributes=None): try: tx = wallet.MakeTransaction(tx=contract_tx, change_address=scripthash_change, fee=fee, from_addr=scripthash_from) if tx is None: logger.debug("insufficient funds") return False # password prompt passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("incorrect password") return False standard_contract = wallet.GetStandardAddress() if scripthash_from is not None: signer_contract = wallet.GetContract(scripthash_from) else: signer_contract = wallet.GetContract(standard_contract) if not signer_contract.IsMultiSigContract and owners is None: data = standard_contract.Data tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data) ] # insert any additional user specified tx attributes tx.Attributes = tx.Attributes + user_tx_attributes if owners: owners = list(owners) for owner in owners: tx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) context = ContractParametersContext( tx, isMultiSig=signer_contract.IsMultiSigContract) wallet.Sign(context) if owners: owners = list(owners) gather_signatures(context, tx, owners) print(context.ScriptHashes) for s in context.GetScripts(): print(s.ToJson()) print(tx.ToJson()) if context.Completed: tx.scripts = context.GetScripts() # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(tx) if relayed: wallet.SaveTransaction(tx) print("Relayed Tx: %s " % tx.Hash.ToString()) return tx else: print("Could not relay tx %s " % tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False except Exception as e: print("could not send: %s " % e) traceback.print_stack() traceback.print_exc() return False
def construct_invoke_tx(wallet, params): params = params[0] from_addr = params['from_addr'] BC = GetBlockchain() contract = BC.GetContract(params['addr']) if not contract: raise Exception('no such contract') neo_to_attach = params.get('neo_to_attach', 0) gas_to_attach = params.get('gas_to_attach', 0) sb = ScriptBuilder() contract_parameters = [ContractParameter.FromJson(p) for p in params['contract_params']] sb.EmitAppCallWithJsonArgs(contract.Code.ScriptHash(), contract_parameters) invoke_script = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(invoke_script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False).Data)] tx = wallet.MakeTransaction(tx=tx) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True ) engine.LoadScript(tx.Script, False) success = engine.Execute() if not success: raise Exception('exec failed') service.ExecutionCompleted(engine, success) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = Fixed8.FromDecimal(.0001) tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() tx.Gas = tx_gas tx.outputs = outputs tx.Attributes = [] # InvokeContract from_addr = lookup_addr_str(wallet, from_addr) tx = wallet.MakeTransaction(tx=tx, fee=net_fee, use_standard=True, from_addr=from_addr) if tx is None: raise Exception("no gas") context = ContractParametersContext(tx) ms = StreamManager.GetStream() writer = BinaryWriter(ms) tx.Serialize(writer) ms.flush() binary_tx = ms.ToArray() return {'context': context.ToJson(), 'tx': binary_tx.decode()}
def construct_deploy_tx(wallet, params): params = params[0] from_addr = params['from_addr'] # load_smart_contract contract_params = bytearray(binascii.unhexlify(params['contract_params'])) return_type = bytearray(binascii.unhexlify(params['return_type'])) contract_properties = 0 if params.get('needs_storage', True): contract_properties += ContractPropertyState.HasStorage if params.get('needs_dynamic_invoke', False): contract_properties += ContractPropertyState.HasDynamicInvoke script = binascii.unhexlify(params['bin']) function_code = FunctionCode( script = script, param_list = contract_params, return_type = return_type, contract_properties = contract_properties, ) if Blockchain.Default().GetContract(function_code.ScriptHash().To0xString()): raise Exception('contract already exists') # GatherContractDetails details = params['details'] name = details['name'] version = details['version'] author = details['author'] email = details['email'] description = details['description'] contract_script = generate_deploy_script( function_code.Script, name, version, author, email, description, function_code.ContractProperties, function_code.ReturnType, function_code.ParameterList, ) # test_invoke bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) tx = InvocationTransaction() tx.outputs = [] tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(contract_script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False).Data)] tx = wallet.MakeTransaction(tx=tx) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True ) engine.LoadScript(tx.Script, False) success = engine.Execute() if not success: raise Exception('exec failed') service.ExecutionCompleted(engine, success) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = Fixed8.FromDecimal(.0001) tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() tx.Gas = tx_gas tx.outputs = [] tx.Attributes = [] # InvokeContract from_addr = lookup_addr_str(wallet, from_addr) tx = wallet.MakeTransaction(tx=tx, fee=net_fee, use_standard=True, from_addr=from_addr) if tx is None: raise Exception("no gas") context = ContractParametersContext(tx) ms = StreamManager.GetStream() writer = BinaryWriter(ms) tx.Serialize(writer) ms.flush() binary_tx = ms.ToArray() return {'context': context.ToJson(), 'tx': binary_tx.decode(), 'hash': function_code.ScriptHash().To0xString()}
def construct_send_tx(wallet, arguments): from_address = arguments['from'] to_send = arguments['asset'] address_to = arguments['to'] amount = arguments['amount'] user_tx_attributes = arguments.get('attrs', []) assetId = get_asset_id(wallet, to_send) if assetId is None: raise Exception("Asset id not found") scripthash_to = lookup_addr_str(wallet, address_to) if scripthash_to is None: raise Exception("invalid address") scripthash_from = None if from_address is not None: scripthash_from = lookup_addr_str(wallet, from_address) if type(assetId) is NEP5Token: raise Exception("cannot transfer token in this version") f8amount = Fixed8.TryParse(amount, require_positive=True) if f8amount is None: raise Exception("invalid amount format") if type(assetId) is UInt256 and f8amount.value % pow(10, 8 - Blockchain.Default().GetAssetState(assetId.ToBytes()).Precision) != 0: raise Exception("incorrect amount precision") fee = Fixed8.Zero() output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to) tx = ContractTransaction(outputs=[output]) ttx = wallet.MakeTransaction(tx=tx, fee=fee, from_addr=scripthash_from) if ttx is None: raise Exception("no funds") standard_contract = wallet.GetStandardAddress() if scripthash_from is not None: signer_contract = wallet.GetContract(scripthash_from) else: signer_contract = wallet.GetContract(standard_contract) if not signer_contract.IsMultiSigContract: data = standard_contract.Data tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data)] # insert any additional user specified tx attributes tx.Attributes = tx.Attributes + user_tx_attributes context = ContractParametersContext(tx, isMultiSig=signer_contract.IsMultiSigContract) logger.info(context.ToJson()) logger.info('*'*60) logger.info(tx.ToJson()) # import pdb # pdb.set_trace() ms = StreamManager.GetStream() writer = BinaryWriter(ms) tx.Serialize(writer) ms.flush() binary_tx = ms.ToArray() print(tx) return {'context': context.ToJson(), 'tx': binary_tx.decode()}
def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, debug_map=None, invoke_attrs=None, owners=None): bc = GetBlockchain() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBCollection(debug_storage.db, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) except (ValueError, TXFeeError): pass context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() dtx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False)) ] dtx.Attributes = make_unique_script_attr(dtx.Attributes) to_dispatch = [] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=dtx, table=script_table, service=service, gas=dtx.Gas, testMode=True) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke d_success = engine.Execute() if d_success: items = engine.ResultStack.Items contract_state = None for i in items: if type(i) is ContractState: contract_state = i break elif type(i) is InteropInterface: item = i.GetInterface() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() invoke_args, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments( invoke_args) invoke_args, no_parse_addresses = PromptUtils.get_parse_addresses( invoke_args) invoke_args.reverse() if '--i' in invoke_args: invoke_args = [] for index, iarg in enumerate(contract_state.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, [], 0, None else: invoke_args.append(param) invoke_args.reverse() sb = ScriptBuilder() for p in invoke_args: item = PromptUtils.parse_param(p, wallet, parse_addr=no_parse_addresses) if type(item) is list: item.reverse() listlength = len(item) for listitem in item: subitem = PromptUtils.parse_param( listitem, wallet, parse_addr=no_parse_addresses) if type(subitem) is list: subitem.reverse() for listitem2 in subitem: subsub = PromptUtils.parse_param( listitem2, wallet, parse_addr=no_parse_addresses) sb.push(subsub) sb.push(len(subitem)) sb.Emit(PACK) else: sb.push(subitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(item) sb.EmitAppCall(shash.Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract_state.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract_state.Code.ScriptHash()) outputs.append(output) itx = InvocationTransaction() itx.Version = 1 itx.outputs = outputs itx.inputs = [] itx.scripts = [] itx.Attributes = deepcopy(invoke_attrs) if invoke_attrs else [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1 and not owners: contract = wallet.GetDefaultContract() itx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) itx.Attributes = make_unique_script_attr(itx.Attributes) try: itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) except (ValueError, TXFeeError): pass context = ContractParametersContext(itx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: itx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) itx.Attributes = make_unique_script_attr(itx.Attributes) context = ContractParametersContext(itx, isMultiSig=True) if context.Completed: itx.scripts = context.GetScripts() else: logger.warn( "Not gathering signatures for test build. For a non-test invoke that would occur here." ) # if not gather_signatures(context, itx, owners): # return None, [], 0, None # print("gathered signatures %s " % itx.scripts) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=itx, table=script_table, service=service, gas=itx.Gas, testMode=invocation_test_mode) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) i_success = engine.Execute() service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None
def test_invoke(script, wallet, outputs, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE, invoke_attrs=None, owners=None): # print("invoke script %s " % script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) bc = GetBlockchain() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) # if we are using a withdrawal tx, don't recreate the invocation tx # also, we don't want to reset the inputs / outputs # since those were already calculated if withdrawal_tx is not None: tx = withdrawal_tx else: tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(script) tx.Attributes = [] if invoke_attrs is None else deepcopy(invoke_attrs) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) if len(outputs) < 1: contract = wallet.GetDefaultContract() tx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) tx.Attributes = make_unique_script_attr(tx.Attributes) # same as above. we don't want to re-make the transaction if it is a withdrawal tx if withdrawal_tx is not None: wallet_tx = tx else: try: wallet_tx = wallet.MakeTransaction(tx=tx, from_addr=from_addr, skip_fee_calc=True) except ValueError: pass context = ContractParametersContext(wallet_tx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: # print("contract %s %s" % (wallet.GetDefaultContract().ScriptHash, owner)) if wallet.GetDefaultContract().ScriptHash != owner: wallet_tx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) wallet_tx.Attributes = make_unique_script_attr(tx.Attributes) context = ContractParametersContext(wallet_tx, isMultiSig=True) if context.Completed: wallet_tx.scripts = context.GetScripts() else: logger.warning( "Not gathering signatures for test build. For a non-test invoke that would occur here." ) # if not gather_signatures(context, wallet_tx, owners): # return None, [], 0, None engine = ApplicationEngine(trigger_type=TriggerType.Application, container=wallet_tx, table=script_table, service=service, gas=wallet_tx.Gas, testMode=True) engine.LoadScript(wallet_tx.Script) try: success = engine.Execute() service.ExecutionCompleted(engine, success) for event in service.events_to_dispatch: events.emit(event.event_type, event) if success: # this will be removed in favor of neo.EventHub if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) # print("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = min_fee tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() # set the amount of gas the tx will need wallet_tx.Gas = tx_gas # reset the wallet outputs wallet_tx.outputs = outputs wallet_tx.Attributes = [] if invoke_attrs is None else deepcopy( invoke_attrs) # calculate the required network fee for the tx and compare to fee if wallet_tx.Size() > settings.MAX_FREE_TX_SIZE: req_fee = Fixed8.FromDecimal( settings.FEE_PER_EXTRA_BYTE * (wallet_tx.Size() - settings.MAX_FREE_TX_SIZE)) if req_fee < settings.LOW_PRIORITY_THRESHOLD: req_fee = settings.LOW_PRIORITY_THRESHOLD if net_fee < req_fee: net_fee = req_fee return wallet_tx, net_fee, engine.ResultStack.Items, engine.ops_processed, success # this allows you to to test invocations that fail else: wallet_tx.outputs = outputs wallet_tx.Attributes = [] if invoke_attrs is None else deepcopy( invoke_attrs) return wallet_tx, min_fee, [], engine.ops_processed, success except Exception as e: service.ExecutionCompleted(engine, False, e) return None, None, None, None, False
def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_change=None, fee=None, owners=None, user_tx_attributes=None): try: tx = wallet.MakeTransaction(tx=contract_tx, change_address=scripthash_change, fee=fee, from_addr=scripthash_from) except ValueError: print( "Insufficient funds. No unspent outputs available for building the transaction.\n" "If you are trying to sent multiple transactions in 1 block, then make sure you have enough 'vouts'\n." "Use `wallet unspent` and `wallet address split`, or wait until the first transaction is processed before sending another." ) return except TXFeeError as e: print(e) return if tx is None: logger.debug("insufficient funds") return try: print("Validate your transaction details") print("-" * 33) input_coinref = wallet.FindCoinsByVins(tx.inputs)[0] source_addr = input_coinref.Address for order in tx.outputs: dest_addr = order.Address value = order.Value.ToString() # fixed8 if order.AssetId == Blockchain.Default().SystemShare().Hash: asset_name = 'NEO' else: asset_name = 'GAS' if source_addr != dest_addr: print( f"Sending {value} {asset_name} from {source_addr} to {dest_addr}" ) else: print( f"Returning {value} {asset_name} as change to {dest_addr}") print(" ") print("Enter your password to send to the network") try: passwd = prompt("[Password]> ", is_password=True) except KeyboardInterrupt: print("Transaction cancelled") return if not wallet.ValidatePassword(passwd): print("Incorrect password") return standard_contract = wallet.GetStandardAddress() if scripthash_from is not None: signer_contract = wallet.GetContract(scripthash_from) else: signer_contract = wallet.GetContract(standard_contract) if not signer_contract.IsMultiSigContract and owners is None: data = standard_contract.Data tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data) ] # insert any additional user specified tx attributes tx.Attributes = tx.Attributes + user_tx_attributes if owners: owners = list(owners) for owner in owners: tx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) context = ContractParametersContext( tx, isMultiSig=signer_contract.IsMultiSigContract) wallet.Sign(context) if owners: owners = list(owners) gather_signatures(context, tx, owners) if context.Completed: tx.scripts = context.GetScripts() relayed = NodeLeader.Instance().Relay(tx) if relayed: wallet.SaveTransaction(tx) print("Relayed Tx: %s " % tx.Hash.ToString()) return tx else: print("Could not relay tx %s " % tx.Hash.ToString()) else: print( "Transaction initiated, but the signature is incomplete. Use the `sign` command with the information below to complete signing." ) print(json.dumps(context.ToJson(), separators=(',', ':'))) return except Exception as e: print("Could not send: %s " % e) traceback.print_stack() traceback.print_exc() return
def construct_and_send(prompter, wallet, arguments, prompt_password=True): try: if not wallet: print("please open a wallet") return False if len(arguments) < 3: print("Not enough arguments") return False arguments, from_address = get_from_addr(arguments) arguments, user_tx_attributes = get_tx_attr_from_args(arguments) arguments, owners = get_owners_from_params(arguments) arguments, priority_fee = get_fee(arguments) to_send = get_arg(arguments) address_to = get_arg(arguments, 1) amount = get_arg(arguments, 2) assetId = get_asset_id(wallet, to_send) if assetId is None: print("Asset id not found") return False scripthash_to = lookup_addr_str(wallet, address_to) if scripthash_to is None: print("invalid address") return False scripthash_from = None if from_address is not None: scripthash_from = lookup_addr_str(wallet, from_address) # if this is a token, we will use a different # transfer mechanism if type(assetId) is NEP5Token: return do_token_transfer(assetId, wallet, from_address, address_to, amount_from_string(assetId, amount), prompt_passwd=prompt_password, tx_attributes=user_tx_attributes) f8amount = Fixed8.TryParse(amount, require_positive=True) if f8amount is None: print("invalid amount format") return False if type(assetId) is UInt256 and f8amount.value % pow(10, 8 - Blockchain.Default().GetAssetState(assetId.ToBytes()).Precision) != 0: print("incorrect amount precision") return False fee = Fixed8.Zero() if priority_fee is not None: fee = priority_fee print("sending with fee: %s " % fee.ToString()) output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to) tx = ContractTransaction(outputs=[output]) ttx = wallet.MakeTransaction(tx=tx, change_address=None, fee=fee, from_addr=scripthash_from) if ttx is None: print("insufficient funds") return False if prompt_password: passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("incorrect password") return False standard_contract = wallet.GetStandardAddress() if scripthash_from is not None: signer_contract = wallet.GetContract(scripthash_from) else: signer_contract = wallet.GetContract(standard_contract) if not signer_contract.IsMultiSigContract and owners is None: data = standard_contract.Data tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data)] # insert any additional user specified tx attributes tx.Attributes = tx.Attributes + user_tx_attributes if owners: owners = list(owners) for owner in owners: tx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=owner)) context = ContractParametersContext(tx, isMultiSig=signer_contract.IsMultiSigContract) wallet.Sign(context) if owners: owners = list(owners) gather_signatures(context, tx, owners) if context.Completed: tx.scripts = context.GetScripts() # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(tx) if relayed: wallet.SaveTransaction(tx) print("Relayed Tx: %s " % tx.Hash.ToString()) return tx else: print("Could not relay tx %s " % tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False except Exception as e: print("could not send: %s " % e) traceback.print_stack() traceback.print_exc() return False
def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, debug_map=None): bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, sn, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, sn, DBPrefix.ST_Storage, StorageItem) if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() debug_sn = debug_storage.db.snapshot() storages = DBCollection(debug_storage.db, debug_sn, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = lookup_addr_str(wallet, from_addr) dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() dtx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False)) ] to_dispatch = [] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=dtx, table=script_table, service=service, gas=dtx.Gas, testMode=True) engine.LoadScript(dtx.Script, False) # first we will execute the test deploy # then right after, we execute the test invoke d_success = engine.Execute() if d_success: items = engine.EvaluationStack.Items contract_state = None for i in items: if type(i) is ContractState: contract_state = i break elif type(i) is InteropInterface: item = i.GetInterface() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() invoke_args, neo_to_attach, gas_to_attach = get_asset_attachments( invoke_args) invoke_args.reverse() # print("neo, gas %s %s " % (neo_to_attach,gas_to_attach.ToString())) sb = ScriptBuilder() for p in invoke_args: item = parse_param(p, wallet) if type(item) is list: item.reverse() listlength = len(item) for listitem in item: subitem = parse_param(listitem, wallet) sb.push(subitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(item) sb.EmitAppCall(shash.Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract_state.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract_state.Code.ScriptHash()) outputs.append(output) itx = InvocationTransaction() itx.Version = 1 itx.outputs = outputs itx.inputs = [] itx.scripts = [] itx.Attributes = [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1: contract = wallet.GetDefaultContract() itx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash( contract.Script, unhex=False).Data) ] itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) context = ContractParametersContext(itx) wallet.Sign(context) itx.scripts = context.GetScripts() # print("tx: %s " % json.dumps(itx.ToJson(), indent=4)) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=itx, table=script_table, service=service, gas=itx.Gas, testMode=invocation_test_mode) engine.LoadScript(itx.Script, False) engine.LoadDebugInfo(debug_map) # call execute in its own blocking thread # reactor.stop() i_success = engine.Execute() service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: # print("NOTIFICATION : %s " % n) Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.EvaluationStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None
def test_invoke(script, wallet, outputs, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE): # print("invoke script %s " % script) if from_addr is not None: from_addr = lookup_addr_str(wallet, from_addr) bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, sn, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, sn, DBPrefix.ST_Storage, StorageItem) # if we are using a withdrawal tx, don't recreate the invocation tx # also, we don't want to reset the inputs / outputs # since those were already calculated if withdrawal_tx is not None: tx = withdrawal_tx else: tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) if len(outputs) < 1: contract = wallet.GetDefaultContract() tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False).Data) ] # same as above. we don't want to re-make the transaction if it is a withdrawal tx if withdrawal_tx is not None: wallet_tx = tx else: wallet_tx = wallet.MakeTransaction(tx=tx, from_addr=from_addr) if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() engine = ApplicationEngine(trigger_type=TriggerType.Application, container=wallet_tx, table=script_table, service=service, gas=wallet_tx.Gas, testMode=True) engine.LoadScript(wallet_tx.Script, False) try: # drum roll? success = engine.Execute() service.ExecutionCompleted(engine, success) for event in service.events_to_dispatch: events.emit(event.event_type, event) if success: # this will be removed in favor of neo.EventHub if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) print("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = min_fee tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() # set the amount of gas the tx will need wallet_tx.Gas = tx_gas # reset the wallet outputs wallet_tx.outputs = outputs wallet_tx.Attributes = [] return wallet_tx, net_fee, engine.EvaluationStack.Items, engine.ops_processed except Exception as e: service.ExecutionCompleted(engine, False, e) # print("COULD NOT EXECUTE %s " % e) return None, None, None, None