def Run(snapshot, script, container=None, exit_on_error=False, gas=Fixed8.Zero(), test_mode=True, wb=None): """ 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 """ engine = ApplicationEngine(TriggerType.Application, container, snapshot, gas, test_mode) # maybe not the best solution # but one for now if not wb: _script = binascii.unhexlify(script) else: _script = script engine.LoadScript(_script) engine.Execute() for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) return engine
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, 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 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 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 EmitServiceEvents(state_reader): for event in state_reader.events_to_dispatch: events.emit(event.event_type, event)
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
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, enable_debugger=False, snapshot=None): if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBInterface(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): pass context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() 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 = [] if snapshot is None: snapshot = GetBlockchain()._db.createSnapshot().Clone() engine = ApplicationEngine( trigger_type=TriggerType.Application, container=dtx, snapshot=snapshot, gas=dtx.Gas, testMode=True ) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke if enable_debugger: debugger = Debugger(engine) d_success = debugger.Execute() else: d_success = engine.Execute() # the old setup provided the same StateMachine object to the ApplicationEngine for deploy and invoke # this allowed for a single dispatch of events at the end of the function. Now a new StateMachine is automatically # created when creating an ApplicationEngine, thus we have to dispatch events after the deploy to not lose them as # testcases expect them to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) to_dispatch = [] 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: process_params(sb, p, wallet, no_parse_addresses) 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): 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.") engine = ApplicationEngine( trigger_type=TriggerType.Application, container=itx, snapshot=snapshot, gas=itx.Gas, testMode=invocation_test_mode ) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) if enable_debugger: debugger = Debugger(engine) i_success = debugger.Execute() else: i_success = engine.Execute() engine._Service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: if len(engine._Service.notifications) > 0: for n in engine._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) # 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) 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) 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.") snapshot = GetBlockchain()._db.createSnapshot().Clone() engine = ApplicationEngine( trigger_type=TriggerType.Application, container=wallet_tx, snapshot=snapshot, gas=wallet_tx.Gas, testMode=True ) engine.LoadScript(wallet_tx.Script) try: success = engine.Execute() engine._Service.ExecutionCompleted(engine, success) for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) if success: # this will be removed in favor of neo.EventHub if len(engine._Service.notifications) > 0: for n in engine._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) 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: engine._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): 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() 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.LoadDebugInfoForScriptHash(debug_map, shash.Data) # 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 # this allows you to to test invocations that fail else: wallet_tx.outputs = outputs wallet_tx.Attributes = [] return wallet_tx, min_fee, [], engine.ops_processed except Exception as e: service.ExecutionCompleted(engine, False, e) # print("COULD NOT EXECUTE %s " % e) return None, None, None, None
def VerifyWitnesses(verifiable, snapshot): """ Verify the scripts of the provided `verifiable` object. Args: verifiable (neo.IO.Mixins.VerifiableMixin): Returns: bool: True if verification is successful. False otherwise. """ try: hashes = verifiable.GetScriptHashesForVerifying(snapshot) except Exception as e: logger.debug("couldn't get script hashes %s " % e) return False if len(hashes) != len(verifiable.Scripts): logger.debug(f"hash - verification script length mismatch ({len(hashes)}/{len(verifiable.Scripts)})") return False blockchain = GetBlockchain() for i in range(0, len(hashes)): verification = verifiable.Scripts[i].VerificationScript if len(verification) == 0: sb = ScriptBuilder() sb.EmitAppCall(hashes[i].Data) verification = sb.ms.getvalue() sb.ms.Cleanup() else: verification_hash = Crypto.ToScriptHash(verification, unhex=False) if hashes[i] != verification_hash: logger.debug(f"hash {hashes[i]} does not match verification hash {verification_hash}") return False engine = neo.SmartContract.ApplicationEngine.ApplicationEngine(TriggerType.Verification, verifiable, snapshot, Fixed8.Zero()) engine.LoadScript(verification) invocation = verifiable.Scripts[i].InvocationScript engine.LoadScript(invocation) try: success = engine.Execute() engine._Service.ExecutionCompleted(engine, success) except Exception as e: engine._Service.ExecutionCompleted(engine, False, e) if engine.ResultStack.Count != 1 or not engine.ResultStack.Pop().GetBoolean(): for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) if engine.ResultStack.Count > 0: logger.debug( f"Result stack failure! Count: {engine.ResultStack.Count} bool value: {engine.ResultStack.Pop().GetBoolean()}") else: logger.debug(f"Result stack failure! Count: {engine.ResultStack.Count}") return False for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) return True
async def Persist(self, block): self._persisting_block = block snapshot = self._db.createSnapshot() snapshot.PersistingBlock = block amount_sysfee = self.GetSysFeeAmount( block.PrevHash) + (block.TotalFees().value / Fixed8.D) amount_sysfee_bytes = struct.pack("<d", amount_sysfee) to_dispatch = [] with self._db.getBatch() as wb: wb.put(DBPrefix.DATA_Block + block.Hash.ToBytes(), amount_sysfee_bytes + block.Trim()) for tx_idx, tx in enumerate(block.Transactions): with self._db.getBatch() as tx_wb: tx_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) snapshot.UnspentCoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = snapshot.Accounts.GetAndChange( output.AddressBytes, lambda: 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: snapshot.UnspentCoins.GetAndChange( input.PrevHash.ToBytes()).Items[ input.PrevIndex] |= CoinState.Spent if prevTx.outputs[input.PrevIndex].AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): sc = snapshot.SpentCoins.GetAndChange( input.PrevHash.ToBytes(), lambda: SpentCoinState( input.PrevHash, height, [])) sc.Items.append( SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = snapshot.Accounts.GetAndChange( prevTx.outputs[input.PrevIndex].AddressBytes, lambda: 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) snapshot.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 = snapshot.Assets.GetAndChange( result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = snapshot.SpentCoins.TryGet( input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) snapshot.SpentCoins.GetAndChange( input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: snapshot.Validators.GetAndChange( tx.PublicKey.ToBytes(), lambda: ValidatorState(pub_key=tx.PublicKey)) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: def create_contract_state(): return ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) snapshot.Contracts.GetOrAdd( tx.Code.ScriptHash().ToBytes(), create_contract_state) elif tx.Type == TransactionType.InvocationTransaction: engine = ApplicationEngine(TriggerType.Application, tx, snapshot.Clone(), tx.Gas) engine.LoadScript(tx.Script) try: success = engine.Execute() if success: engine._Service.Commit() engine._Service.ExecutionCompleted( engine, success) else: engine._Service.ExecutionCompleted( engine, False) except Exception as e: traceback.print_exc() to_dispatch = to_dispatch + engine._Service.events_to_dispatch await asyncio.sleep(0.001) else: if tx.Type != b'\x00' and tx.Type != b'\x80': logger.info("TX Not Found %s " % tx.Type) snapshot.Commit() snapshot.Dispose() 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)