def Run(script, container=None, exit_on_error=False, gas=Fixed8.Zero(), test_mode=True): """ Runs a script in a test invoke environment Args: script (bytes): The script to run container (neo.Core.TX.Transaction): [optional] the transaction to use as the script container Returns: ApplicationEngine """ from neo.Core.Blockchain import Blockchain from neo.SmartContract.StateMachine import StateMachine from neo.EventHub import events bc = Blockchain.Default() 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) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=container, table=script_table, service=service, gas=gas, testMode=test_mode, exit_on_error=exit_on_error) script = binascii.unhexlify(script) engine.LoadScript(script, False) try: success = engine.Execute() engine.testMode = True service.ExecutionCompleted(engine, success) except Exception as e: engine.testMode = True service.ExecutionCompleted(engine, False, e) for event in service.events_to_dispatch: events.emit(event.event_type, event) return engine
def Run(script, container=None): from neo.Core.Blockchain import Blockchain from neo.SmartContract.StateMachine import StateMachine bc = Blockchain.Default() 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) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=container, table=script_table, service=service, gas=Fixed8.Zero(), testMode=True ) engine.LoadScript(script, False) engine.Execute() return engine
def GetStateMachine(): from neo.SmartContract.StateMachine import StateMachine from neo.Storage.Interface.DBInterface import DBInterface from neo.Storage.Common.DBPrefix import DBPrefix from neo.Core.State.AccountState import AccountState from neo.Core.State.AssetState import AssetState from neo.Core.State.ValidatorState import ValidatorState from neo.Core.State.ContractState import ContractState from neo.Core.State.StorageItem import StorageItem bc = GetBlockchain() accounts = DBInterface(bc._db, DBPrefix.ST_Account, AccountState) assets = DBInterface(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBInterface(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBInterface(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBInterface(bc._db, DBPrefix.ST_Storage, StorageItem) return StateMachine(accounts, validators, assets, contracts, storages, None, bc)
def __init__(self, trigger_type, container, snapshot, gas, testMode=False, exit_on_error=True): super(ApplicationEngine, self).__init__(container=container, crypto=Crypto.Default(), table=snapshot, service=StateMachine(trigger_type, snapshot), exit_on_error=exit_on_error) self.gas_amount = self.gas_free + gas.value self.testMode = testMode self.snapshot = snapshot self._is_stackitem_count_strict = True self.debugger = None self.gas_consumed = 0 self.invocation_args = None
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 Persist(self, block): self._persisting_block = block sn = self._db.snapshot() accounts = DBCollection(self._db, sn, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, sn, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, sn, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, sn, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount(block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') to_dispatch = [] with self._db.write_batch() as wb: wb.put(DBPrefix.DATA_Block + block.Hash.ToBytes(), amount_sysfee_bytes + block.Trim()) for tx in block.Transactions: wb.put(DBPrefix.DATA_Transaction + tx.Hash.ToBytes(), block.IndexBytes() + tx.ToArray()) # go through all outputs and add unspent coins to them unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed(tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange(output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes()] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange(input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes() == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange(input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append(SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange(prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance(assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [result for result in tx.GetTransactionResults() if result.Amount.value < 0] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: newvalidator = ValidatorState(pub_key=tx.PublicKey) validators.GetAndChange(tx.PublicKey.ToBytes(), newvalidator) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=False ) engine.LoadScript(tx.Script, False) try: success = engine.Execute() service.ExecutionCompleted(engine, success) except Exception as e: service.ExecutionCompleted(engine, False, e) to_dispatch = to_dispatch + service.events_to_dispatch else: if tx.Type != b'\x00' and tx.Type != 128: logger.info("TX Not Found %s " % tx.Type) # do save all the accounts, unspent, coins, validators, assets, etc # now sawe the current sys block # filter out accounts to delete then commit for key, account in accounts.Current.items(): if not account.IsFrozen and len(account.Votes) == 0 and account.AllBalancesZeroOrLess(): accounts.Remove(key) accounts.Commit(wb) # filte out unspent coins to delete then commit for key, unspent in unspentcoins.Current.items(): if unspent.IsAllSpent: unspentcoins.Remove(key) unspentcoins.Commit(wb) # filter out spent coins to delete then commit to db for key, spent in spentcoins.Current.items(): if len(spent.Items) == 0: spentcoins.Remove(key) spentcoins.Commit(wb) # commit validators validators.Commit(wb) # commit assets assets.Commit(wb) # commit contracts contracts.Commit(wb) sn.close() wb.put(DBPrefix.SYS_CurrentBlock, block.Hash.ToBytes() + block.IndexBytes()) self._current_block_height = block.Index self._persisting_block = None self.TXProcessed += len(block.Transactions) for event in to_dispatch: events.emit(event.event_type, event)
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 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 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): # 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
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): # print("invoke script %s " % script) 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) tx = InvocationTransaction() tx.Version = 1 tx.outputs = outputs tx.inputs = [] 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).Data) ] wallet_tx = wallet.MakeTransaction(tx=tx) 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() if success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed.value = int(consumed.value) net_fee = None tx_gas = None if consumed < Fixed8.One(): net_fee = Fixed8.FromDecimal(.001) 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 else: print("error executing contract.....") # tx.Gas = Fixed8.One() # tx.Attributes = [] # return tx, [] return None, [] except Exception as e: print("COULD NOT EXECUTE %s " % e) return None, []
def Persist(self, block): accounts = DBCollection(self._db, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount( block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') with self._db.write_batch() as wb: for tx in block.Transactions: unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed( tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange( output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [ coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes() ] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange( input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange( input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append( SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange( prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance( assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [ result for result in tx.GetTransactionResults() if result.Amount.value < 0 ] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: validator = validators.GetAndChange( tx.PublicKey, ValidatorState(pub_key=tx.PublicKey)) # logger.info("VALIDATOR %s " % validator.ToJson()) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb=wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True) engine.LoadScript(tx.Script) # normally, this function does not return true/false # for testing purposes, we try to execute and if an exception is raised # we will return false, otherwise if success return true # this is different than the 'success' bool returned by engine.Execute() # the 'success' bool returned by engine.Execute() is a value indicating # wether or not the invocation was successful, and if so, we then commit # the changes made by the contract to the database try: success = engine.Execute() # service.ExecutionCompleted(engine, success) return True except Exception as e: # service.ExecutionCompleted(self, False, e) return False
def Persist(self, block): start = time.clock() sn = self._db.snapshot() accounts = DBCollection(self._db, sn, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, sn, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, sn, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, sn, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount(block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') self.__log.debug("[BlockFee] : %s %s " % (block.Index, amount_sysfee)) try: with self._db.write_batch() as wb: wb.put(DBPrefix.DATA_Block + block.Hash.ToBytes(), amount_sysfee_bytes + block.Trim()) for tx in block.Transactions: wb.put(DBPrefix.DATA_Transaction + tx.Hash.ToBytes(), block.IndexBytes() + tx.ToArray()) # go through all outputs and add unspent coins to them unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed(tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange(output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes()] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange(input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes() == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange(input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append(SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange(prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance(assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [result for result in tx.GetTransactionResults() if result.Amount.value < 0] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: newvalidator = ValidatorState(pub_key=tx.PublicKey) validators.GetAndChange(tx.PublicKey.ToBytes(), newvalidator) elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: # print("RUNNING INVOCATION TRASACTION!!!!!! %s %s " % (block.Index, tx.Hash.ToBytes())) print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: Invoke tx] -> index, tx hash %s %s " % (block.Index, tx.Hash.ToBytes())) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=False ) engine.LoadScript(tx.Script, False) try: # drum roll? success = engine.Execute() print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute] -> Success") if success: service.Commit() if len(service.notifications) > 0: for n in service.notifications: self.OnNotify(n) for item in engine.EvaluationStack.Items: print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute result] -> %s " % item) except Exception as e: print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute result] Could not execute smart contract. See logs for more details. %s " % e) else: if tx.Type != b'\x00' and tx.Type != 128: self.__log.debug("TX Not Found %s " % tx.Type) # do save all the accounts, unspent, coins, validators, assets, etc # now sawe the current sys block # filter out accounts to delete then commit for key, account in accounts.Current.items(): if not account.IsFrozen and len(account.Votes) == 0 and account.AllBalancesZeroOrLess(): accounts.Remove(key) accounts.Commit(wb) # filte out unspent coins to delete then commit for key, unspent in unspentcoins.Current.items(): unspentcoins.Remove(key) unspentcoins.Commit(wb) # filter out spent coins to delete then commit to db for key, spent in spentcoins.Current.items(): if len(spent.Items) == 0: spentcoins.Remove(key) spentcoins.Commit(wb) # commit validators validators.Commit(wb) # commit assets assets.Commit(wb) # commit contracts contracts.Commit(wb) # commit storages ( not implemented ) storages.Commit(wb) sn.close() wb.put(DBPrefix.SYS_CurrentBlock, block.Hash.ToBytes() + block.IndexBytes()) self._current_block_height = block.Index end = time.clock() self.__log.debug("PERSISTING BLOCK %s (cache) %s %s " % (block.Index, len(self._block_cache), end - start)) except Exception as e: print("couldnt persist block %s " % e)
def test_deploy_and_invoke(deploy_script, invoke_args, wallet): 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) dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) dtx = wallet.MakeTransaction(tx=dtx) 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)) ] 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 try: 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('neo.whatever') 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() sb = ScriptBuilder() # print("neo, gas %s %s " % (neo_to_attach,gas_to_attach.ToString())) sb = ScriptBuilder() for p in invoke_args: item = parse_param(p) 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(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).Data) ] itx = wallet.MakeTransaction(tx=itx) 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=True) engine.LoadScript(itx.Script, False) i_success = engine.Execute() if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed.value = int(consumed.value) if consumed < Fixed8.One(): consumed = Fixed8.FromDecimal(.001) total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultsForCode(contract_state.Code) return itx, result, total_ops else: print("error executing invoke contract...") else: print("error executing deploy contract.....") except Exception as e: print("COULD NOT EXECUTE %s " % e) traceback.print_stack() traceback.print_exc() return None, [], 0
def test_invoke(script, wallet): 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) tx = InvocationTransaction() tx.Version = 0 tx.scripts = [] tx.Script = binascii.unhexlify(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)) ] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True) engine.LoadScript(tx.Script, False) try: # drum roll? success = engine.Execute() if success: service.TestCommit() consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) if consumed < Fixed8.One(): consumed = Fixed8.One() #set the amount of gas the tx will need tx.Gas = consumed #remove the attributes that are used to add a verification script to the tx tx.Attributes = [] return tx, engine.EvaluationStack.Items except Exception as e: print("COULD NOT EXECUTE %s " % e) return None, []
def setUp(self): self.engine = ExecutionEngine() self.econtext = ExecutionContext(Script(self.engine.Crypto, b''), 0) self.engine.InvocationStack.PushT(self.econtext) self.service = StateMachine(None, None)
class InteropSerializeDeserializeTestCase(TestCase): def setUp(self): self.engine = ExecutionEngine() self.econtext = ExecutionContext(Script(self.engine.Crypto, b''), 0) self.engine.InvocationStack.PushT(self.econtext) self.service = StateMachine(None, None) def test_iter_array(self): my_array = Array([ StackItem.New(12), StackItem.New(b'Hello World'), StackItem.New(True), Array([StackItem.New(113442), StackItem.New(2), StackItem.New(3)]) ]) self.econtext.EvaluationStack.PushT(my_array) self.engine.InvocationStack.PushT(self.econtext) self.service.Enumerator_Create(self.engine) iterable = self.econtext.EvaluationStack.Peek(0).GetInterface() self.assertIsInstance(iterable, ArrayWrapper) keys = [] values = [] while iterable.Next(): currentKey = iterable.Key() keys.append(currentKey.GetBigInteger()) values.append(iterable.Value()) self.assertEqual(keys, [0, 1, 2, 3]) self.assertEqual(values, my_array.GetArray()) def test_iter_map(self): my_map = Map({ StackItem.New('a'): StackItem.New(1), StackItem.New('b'): StackItem.New(3), StackItem.New('d'): StackItem.New(432) }) self.econtext.EvaluationStack.PushT(my_map) self.engine.InvocationStack.PushT(self.econtext) self.service.Iterator_Create(self.engine) iterable = self.econtext.EvaluationStack.Peek(0).GetInterface() self.assertIsInstance(iterable, MapWrapper) keys = [] values = [] while iterable.Next(): keys.append(iterable.Key()) values.append(iterable.Value()) self.assertEqual( keys, [StackItem.New('a'), StackItem.New('b'), StackItem.New('d')]) self.assertEqual(keys, my_map.Keys) self.assertEqual( values, [StackItem.New(1), StackItem.New(3), StackItem.New(432)]) self.assertEqual(values, my_map.Values) def test_iter_array_keys(self): my_array = Array([ StackItem.New(12), StackItem.New(b'Hello World'), StackItem.New(True), Array([StackItem.New(113442), StackItem.New(2), StackItem.New(3)]) ]) self.econtext.EvaluationStack.PushT(my_array) self.engine.InvocationStack.PushT(self.econtext) self.service.Enumerator_Create(self.engine) create_iterkeys = self.service.Iterator_Keys(self.engine) self.assertEqual(create_iterkeys, True) iterkeys = self.econtext.EvaluationStack.Peek(0).GetInterface() self.assertIsInstance(iterkeys, KeysWrapper) keys = [] while iterkeys.Next(): keys.append(iterkeys.Value().GetBigInteger()) self.assertEqual(keys, [0, 1, 2, 3]) def test_iter_array_values(self): my_array = Array([ StackItem.New(12), StackItem.New(b'Hello World'), StackItem.New(True), Array([StackItem.New(113442), StackItem.New(2), StackItem.New(3)]) ]) self.econtext.EvaluationStack.PushT(my_array) self.engine.InvocationStack.PushT(self.econtext) self.service.Enumerator_Create(self.engine) create_itervalues = self.service.Iterator_Values(self.engine) self.assertEqual(create_itervalues, True) itervals = self.econtext.EvaluationStack.Peek(0).GetInterface() self.assertIsInstance(itervals, ValuesWrapper) values = [] while itervals.Next(): values.append(itervals.Value()) self.assertEqual(values, my_array.GetArray()) def test_iter_concat(self): my_array = Array([ StackItem.New(12), StackItem.New(b'Hello World'), StackItem.New(True), Array([StackItem.New(113442), StackItem.New(2), StackItem.New(3)]) ]) my_array2 = Array([ StackItem.New(b'a'), StackItem.New(b'b'), StackItem.New(4), StackItem.New(100) ]) self.econtext.EvaluationStack.PushT(my_array2) self.engine.InvocationStack.PushT(self.econtext) self.service.Enumerator_Create(self.engine) self.econtext.EvaluationStack.PushT(my_array) self.service.Enumerator_Create(self.engine) result = self.service.Enumerator_Concat(self.engine) self.assertEqual(result, True) concatted_enum = self.econtext.EvaluationStack.Peek().GetInterface() self.assertIsInstance(concatted_enum, ConcatenatedEnumerator) values = [] count = 0 while concatted_enum.Next(): count += 1 values.append(concatted_enum.Value()) self.assertEqual(count, 8) self.assertEqual(values, my_array.GetArray() + my_array2.GetArray()) def test_iter_array_bad(self): my_item = StackItem.New(12) self.econtext.EvaluationStack.PushT(my_item) self.engine.InvocationStack.PushT(self.econtext) result = self.service.Enumerator_Create(self.engine) self.assertEqual(result, False) self.assertEqual(self.econtext.EvaluationStack.Count, 0) def test_iter_map_bad(self): my_item = StackItem.New(12) self.econtext.EvaluationStack.PushT(my_item) self.engine.InvocationStack.PushT(self.econtext) result = self.service.Iterator_Create(self.engine) self.assertEqual(result, False) self.assertEqual(self.econtext.EvaluationStack.Count, 0) def test_iter_array_key_bad(self): my_item = StackItem.New(12) self.econtext.EvaluationStack.PushT(my_item) self.engine.InvocationStack.PushT(self.econtext) result = self.service.Iterator_Key(self.engine) self.assertEqual(result, False) self.assertEqual(self.econtext.EvaluationStack.Count, 0) def test_iter_array_values_bad(self): my_item = StackItem.New(12) self.econtext.EvaluationStack.PushT(my_item) self.engine.InvocationStack.PushT(self.econtext) result = self.service.Iterator_Values(self.engine) self.assertEqual(result, False) self.assertEqual(self.econtext.EvaluationStack.Count, 0) def test_iter_array_keys_bad(self): my_item = StackItem.New(12) self.econtext.EvaluationStack.PushT(my_item) self.engine.InvocationStack.PushT(self.econtext) result = self.service.Iterator_Keys(self.engine) self.assertEqual(result, False) self.assertEqual(self.econtext.EvaluationStack.Count, 0)