def get_fee(params): fee = None for item in params: if '--fee=' in item: params.remove(item) fee = get_asset_amount(item.replace('--fee=', ''), Blockchain.SystemCoin().Hash) return params, fee
def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE, invoke_attrs=None, owners=None): BC = GetBlockchain() contract = BC.GetContract(args[0]) if contract: # params = args[1:] if len(args) > 1 else [] params, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments(params) params, parse_addresses = PromptUtils.get_parse_addresses(params) params.reverse() if '--i' in params: params = [] for index, iarg in enumerate(contract.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, None, None, None, False params.append(param) params.reverse() sb = ScriptBuilder() for p in params: process_params(sb, p, wallet, parse_addresses) sb.EmitAppCall(contract.Code.ScriptHash().Data) out = 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) return test_invoke(out, wallet, outputs, withdrawal_tx, from_addr, min_fee, invoke_attrs=invoke_attrs, owners=owners) else: print("Contract %s not found" % args[0]) return None, None, None, None, False
def Verify(self, mempool): """ Verify the transaction. Args: mempool: Returns: bool: True if verified. False otherwise. """ if not super(ClaimTransaction, self).Verify(mempool): return False # wat does this do # get all claim transactinos from mempool list # that are not this claim # and gather all the claims of those claim transactions # and see if they intersect the claims of this transaction # and if that number is greater than zero that we do not verify # (now, to do that in python) # if (mempool.OfType < ClaimTransaction > ().Where(p => p != this).SelectMany(p= > p.Claims).Intersect(Claims).Count() > 0) # return false; # im sorry about the below otherclaimTxs = [ tx for tx in mempool if tx is ClaimTransaction and tx is not self ] for other in otherclaimTxs: # check to see if the length of the intersection between this objects claim's and the other txs claims is > 0 if len([ list(filter(lambda x: x in self.Claims, otherClaims)) for otherClaims in other.Claims ]): return False txResult = None for tx in self.GetTransactionResults(): if tx.AssetId == Blockchain.SystemCoin().Hash: txResult = tx break if txResult is None or txResult.Amount > Fixed8(0): return False try: return Blockchain.CalculateBonusIgnoreClaimed( self.Claims, False) == -txResult.Amount except Exception as e: logger.error('Could not calculate bonus: %s ' % e) return False
def get_fee(params): to_remove = [] fee = None for item in params: if '--fee=' in item: to_remove.append(item) try: fee = get_asset_amount(item.replace('--fee=', ''), Blockchain.SystemCoin().Hash) except Exception as e: pass for item in to_remove: params.remove(item) return params, fee
def _make_tx(self, addr_to): """ process transaction """ output1 = TransactionOutput( AssetId = Blockchain.SystemCoin().Hash, # hash of the Gas transaction Value = Fixed8.FromDecimal(2000), # this is how much gas each request will provide script_hash = addr_to # address to send the Gas to ) output2 = TransactionOutput( AssetId = Blockchain.SystemShare().Hash, # hash of the NEO token transaction Value = Fixed8.FromDecimal(100), # this is how much NEO each request will provide script_hash = addr_to # address to send the NEO tokens too ) contract_tx = ContractTransaction() # creates an instance of the transaction contract_tx.outputs = [output1, output2] # outputs the data from the transaction contract_tx = self.wallet.MakeTransaction(contract_tx) # processes transaction print("tx to json: %s " % json.dumps(contract_tx.ToJson(), indent=4)) context = ContractParametersContext(contract_tx, isMultiSig=False) # getting the contract context (listed above) self.wallet.Sign(context) # signs the contract if context.Completed: contract_tx.scripts = context.GetScripts() # gets the script hashes from the context self.wallet.SaveTransaction(contract_tx) # update the state of the coins in the wallet # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(contract_tx) # relay the transaction to this instance of the node leader if relayed: # if tx relay was successful, inform the user and return the contract transaction print("Relayed Tx: %s " % contract_tx.Hash.ToString()) return contract_tx else: print("Could not relay tx %s " % contract_tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False return False
def _get_context(self): neo_balance = Fixed8.Zero() for coin in self.wallet.FindUnspentCoinsByAsset(Blockchain.SystemShare().Hash): neo_balance += coin.Output.Value gas_balance = Fixed8.Zero() for coin in self.wallet.FindUnspentCoinsByAsset(Blockchain.SystemCoin().Hash): gas_balance += coin.Output.Value return { 'message':'Hello', 'height':Blockchain.Default().Height, 'neo': neo_balance.ToInt(), 'gas': gas_balance.ToInt(), 'wallet_height': self.wallet.WalletHeight }
def _make_tx(self, addr_to): output1 = TransactionOutput( AssetId = Blockchain.SystemCoin().Hash, Value = Fixed8.FromDecimal(2000), script_hash = addr_to ) output2 = TransactionOutput( AssetId = Blockchain.SystemShare().Hash, Value = Fixed8.FromDecimal(100), script_hash = addr_to ) contract_tx = ContractTransaction() contract_tx.outputs = [output1, output2] contract_tx = self.wallet.MakeTransaction(contract_tx) print("tx to json: %s " % json.dumps(contract_tx.ToJson(), indent=4)) context = ContractParametersContext(contract_tx, isMultiSig=False) self.wallet.Sign(context) if context.Completed: contract_tx.scripts = context.GetScripts() self.wallet.SaveTransaction(contract_tx) # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(contract_tx) if relayed: print("Relayed Tx: %s " % contract_tx.Hash.ToString()) return contract_tx else: print("Could not relay tx %s " % contract_tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False return False
def _get_context(self): """ function gets the current amount of neo and gas in the user's wallet then returns a json object stating those values """ neo_balance = Fixed8.Zero() # initializes NEO balance at 0 (to 8 decimal places) for coin in self.wallet.FindUnspentCoinsByAsset(Blockchain.SystemShare().Hash): neo_balance += coin.Output.Value gas_balance = Fixed8.Zero() # initializes NEOGas balance at 0 (to 8 decimal places) for coin in self.wallet.FindUnspentCoinsByAsset(Blockchain.SystemCoin().Hash): gas_balance += coin.Output.Value return { 'message': 'Hello', 'height': Blockchain.Default().Height, # current number of blocks on this instance of the blockchain 'neo': neo_balance.ToInt(), 'gas': gas_balance.ToInt(), 'wallet_height': self.wallet.WalletHeight # this is just the number of transactions that the wallet has had }
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 MakeTransaction(self, tx, change_address=None, fee=Fixed8(0), from_addr=None, use_standard=False, watch_only_val=0, exclude_vin=None, use_vins_for_asset=None): """ This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ). Args: tx (Transaction): The Transaction to be used. change_address (UInt160): The address any change for the transaction should be returned to. fee (Fixed8): A fee to be attached to the Transaction for network processing purposes. from_addr (UInt160): If present, all CoinReferences selected will only come from this address. use_standard (bool): If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used. watch_only_val (int): 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address. exclude_vin (list): A list of CoinReferences to NOT use in the making of this tx. use_vins_for_asset (list): A list of CoinReferences to use. Returns: tx: (Transaction) Returns the transaction with oupdated inputs and outputs. """ tx.ResetReferences() tx.ResetHashData() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + (tx.SystemFee() * Fixed8.FD()) paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value paytotal[key] = sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin().Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} self._vin_exclude = exclude_vin # import pdb # pdb.set_trace() for assetId, amount in paytotal.items(): if use_vins_for_asset is not None and len(use_vins_for_asset) > 0 and use_vins_for_asset[1] == assetId: paycoins[assetId] = self.FindCoinsByVins(use_vins_for_asset[0]) else: paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) self._vin_exclude = None for key, unspents in paycoins.items(): if unspents is None: if not self.IsSynced: logger.warning("Wait for your wallet to be synced before doing " "transactions. To check enter 'wallet' and look at " "'percent_synced', it should be 100. Also the blockchain " "should be up to the latest blocks (see Progress). Issuing " "'wallet rebuild' restarts the syncing process.") return None else: logger.error("insufficient funds for asset id: %s " % key) return None input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress(from_addr=from_addr) new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs return tx
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 TestInvokeContract(wallet, args, withdrawal_tx=None, parse_params=True, from_addr=None, min_fee=DEFAULT_MIN_FEE): BC = GetBlockchain() contract = BC.GetContract(args[0]) if contract: verbose = False if 'verbose' in args: descripe_contract(contract) verbose = True args.remove('verbose') # params = args[1:] if len(args) > 1 else [] if len(params) > 0 and params[0] == 'describe': return params, neo_to_attach, gas_to_attach = get_asset_attachments(params) params.reverse() sb = ScriptBuilder() for p in params: if parse_params: item = parse_param(p, wallet) else: item = 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(contract.Code.ScriptHash().Data) out = 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) return test_invoke(out, wallet, outputs, withdrawal_tx, from_addr, min_fee) else: print("Contract %s not found" % args[0]) return None, None, None, None
def ClaimGas(wallet, require_password=True): unclaimed_coins = wallet.GetUnclaimedCoins() unclaimed_coin_refs = [coin.Reference for coin in unclaimed_coins] if len(unclaimed_coin_refs) == 0: print("no claims to process") return False available_bonus = Blockchain.Default().CalculateBonusIgnoreClaimed( unclaimed_coin_refs) if available_bonus == Fixed8.Zero(): print("No gas to claim") return False claim_tx = ClaimTransaction() claim_tx.Claims = unclaimed_coin_refs claim_tx.Attributes = [] claim_tx.inputs = [] claim_tx.outputs = [ TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=available_bonus, script_hash=wallet.GetChangeAddress()) ] context = ContractParametersContext(claim_tx) wallet.Sign(context) print("\n---------------------------------------------------------------") print("Will make claim for %s GAS" % available_bonus.ToString()) print( "------------------------------------------------------------------\n") if require_password: print("Enter your password to complete this claim") passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("incorrect password") return if context.Completed: claim_tx.scripts = context.GetScripts() wallet.SaveTransaction(claim_tx) relayed = NodeLeader.Instance().Relay(claim_tx) if relayed: print("Relayed Tx: %s " % claim_tx.Hash.ToString()) else: print("Could not relay tx %s " % claim_tx.Hash.ToString()) return claim_tx, relayed else: print("could not sign tx") return None, False
def ClaimGas(wallet, require_password=True, args=None): unclaimed_coins = wallet.GetUnclaimedCoins() unclaimed_coin_refs = [coin.Reference for coin in unclaimed_coins] if len(unclaimed_coin_refs) == 0: print("no claims to process") return False available_bonus = Blockchain.Default().CalculateBonusIgnoreClaimed( unclaimed_coin_refs) if available_bonus == Fixed8.Zero(): print("No gas to claim") return False claim_tx = ClaimTransaction() claim_tx.Claims = unclaimed_coin_refs claim_tx.Attributes = [] claim_tx.inputs = [] script_hash = wallet.GetChangeAddress() # the following can be used to claim gas that is in an imported contract_addr # example, wallet claim --from-addr={smart contract addr} if args: params, from_addr_str = get_from_addr(args) if from_addr_str: script_hash = wallet.ToScriptHash(from_addr_str) standard_contract = wallet.GetStandardAddress() claim_tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=standard_contract.Data) ] claim_tx.outputs = [ TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=available_bonus, script_hash=script_hash) ] context = ContractParametersContext(claim_tx) wallet.Sign(context) print("\n---------------------------------------------------------------") print("Will make claim for %s GAS" % available_bonus.ToString()) print( "------------------------------------------------------------------\n") if require_password: print("Enter your password to complete this claim") passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("incorrect password") return if context.Completed: claim_tx.scripts = context.GetScripts() print("claim tx: %s " % json.dumps(claim_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(claim_tx) if relayed: print("Relayed Tx: %s " % claim_tx.Hash.ToString()) wallet.SaveTransaction(claim_tx) else: print("Could not relay tx %s " % claim_tx.Hash.ToString()) return claim_tx, relayed else: print("could not sign tx") return None, False
def TestInvokeContract(wallet, args, withdrawal_tx=None, parse_params=True, from_addr=None, min_fee=DEFAULT_MIN_FEE, invoke_attrs=None, owners=None): BC = GetBlockchain() contract = BC.GetContract(args[0]) if contract: # params = args[1:] if len(args) > 1 else [] params, neo_to_attach, gas_to_attach = get_asset_attachments(params) params, parse_addresses = get_parse_addresses(params) params.reverse() if '--i' in params: params = [] for index, iarg in enumerate(contract.Code.ParameterList): param, abort = gather_param(index, iarg) if abort: return None, None, None, None params.append(param) params.reverse() sb = ScriptBuilder() for p in params: if parse_params: item = parse_param(p, wallet, parse_addr=parse_addresses) else: item = p if type(item) is list: item.reverse() listlength = len(item) for listitem in item: subitem = parse_param(listitem, wallet, parse_addr=parse_addresses) if type(subitem) is list: subitem.reverse() for listitem2 in subitem: subsub = parse_param(listitem2, wallet, parse_addr=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(contract.Code.ScriptHash().Data) out = 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) return test_invoke(out, wallet, outputs, withdrawal_tx, from_addr, min_fee, invoke_attrs=invoke_attrs, owners=owners) else: print("Contract %s not found" % args[0]) return None, None, None, None
def ClaimGas(wallet, require_password=True, args=None): """ Args: wallet: require_password: args: Returns: (claim transaction, relayed status) if successful: (tx, True) if unsuccessful: (None, False) """ if args: params, from_addr_str = get_from_addr(args) else: params = None from_addr_str = None unclaimed_coins = wallet.GetUnclaimedCoins() unclaimed_count = len(unclaimed_coins) if unclaimed_count == 0: print("no claims to process") return None, False max_coins_per_claim = None if params: max_coins_per_claim = get_arg(params, 0, convert_to_int=True) if not max_coins_per_claim: print("max_coins_to_claim must be an integer") return None, False if max_coins_per_claim <= 0: print("max_coins_to_claim must be greater than zero") return None, False if max_coins_per_claim and unclaimed_count > max_coins_per_claim: unclaimed_coins = unclaimed_coins[:max_coins_per_claim] unclaimed_coin_refs = [coin.Reference for coin in unclaimed_coins] available_bonus = Blockchain.Default().CalculateBonusIgnoreClaimed( unclaimed_coin_refs) if available_bonus == Fixed8.Zero(): print("No gas to claim") return None, False claim_tx = ClaimTransaction() claim_tx.Claims = unclaimed_coin_refs claim_tx.Attributes = [] claim_tx.inputs = [] script_hash = wallet.GetChangeAddress() # the following can be used to claim gas that is in an imported contract_addr # example, wallet claim --from-addr={smart contract addr} if from_addr_str: script_hash = wallet.ToScriptHash(from_addr_str) standard_contract = wallet.GetStandardAddress() claim_tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=standard_contract.Data) ] claim_tx.outputs = [ TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=available_bonus, script_hash=script_hash) ] context = ContractParametersContext(claim_tx) wallet.Sign(context) print("\n---------------------------------------------------------------") print("Will make claim for %s GAS" % available_bonus.ToString()) if max_coins_per_claim and unclaimed_count > max_coins_per_claim: print( "NOTE: You are claiming GAS on %s unclaimed coins. %s additional claim transactions will be required to claim all available GAS." % (max_coins_per_claim, math.floor(unclaimed_count / max_coins_per_claim))) print( "------------------------------------------------------------------\n") if require_password: print("Enter your password to complete this claim") passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("incorrect password") return None, False if context.Completed: claim_tx.scripts = context.GetScripts() print("claim tx: %s " % json.dumps(claim_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(claim_tx) if relayed: print("Relayed Tx: %s " % claim_tx.Hash.ToString()) wallet.SaveTransaction(claim_tx) else: print("Could not relay tx %s " % claim_tx.Hash.ToString()) return claim_tx, relayed else: print("could not sign tx") return None, False
def MakeTransaction(self, tx, change_address=None, fee=Fixed8(0), from_addr=None, use_standard=False, watch_only_val=0, exclude_vin=None, use_vins_for_asset=None): """ This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ) Args: tx: (Transaction) The Transaction to be used change_address: (UInt160) The address any change for the transaction should be returned to fee: (Fixed8) A fee to be attached to the Transaction for network processing purposes from_addr: (UInt160) If present, all CoinReferences selected will only come from this address use_standard: (bool) If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used watch_only_val: (int) 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address exclude_vin: (list) A list of CoinReferences to NOT use in the making of this tx use_vins_for_asset: (list) A list of CoinReferences to use Returns: tx: (Transaction) Returns the transaction with oupdated inputs and outputs """ tx.ResetReferences() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + (tx.SystemFee() * Fixed8.FD()) # pdb.set_trace() paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value paytotal[key] = sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin(). Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} self._vin_exclude = exclude_vin for assetId, amount in paytotal.items(): if use_vins_for_asset is not None and len( use_vins_for_asset ) > 0 and use_vins_for_asset[1] == assetId: paycoins[assetId] = self.FindCoinsByVins(use_vins_for_asset[0]) else: paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) self._vin_exclude = None for key, unspents in paycoins.items(): if unspents is None: print("insufficient funds for asset id: %s " % key) return None input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress(from_addr=from_addr) new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs return tx
def MakeTransaction(self, tx, change_address=None, fee=Fixed8(0)): tx.ResetReferences() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + tx.SystemFee() paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value paytotal[key] = sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin(). Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} for assetId, amount in paytotal.items(): paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount) for key, unspents in paycoins.items(): if unspents == None: print("insufficient funds for asset id: %s " % key) return None input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress() new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs return tx
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 GetSystemCoin(): from neo.Core.Blockchain import Blockchain return Blockchain.SystemCoin()
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 ClaimGas(wallet, require_password=True, from_addr_str=None, to_addr_str=None): """ Args: wallet: require_password: from_addr_str: Returns: (claim transaction, relayed status) if successful: (tx, True) if unsuccessful: (None, False) """ if not wallet: print("Please open a wallet") return None, False unclaimed_coins = wallet.GetUnclaimedCoins() unclaimed_count = len(unclaimed_coins) if unclaimed_count == 0: print("No claims to process") return None, False unclaimed_coin_refs = [coin.Reference for coin in unclaimed_coins] available_bonus = Blockchain.Default().CalculateBonusIgnoreClaimed( unclaimed_coin_refs) if available_bonus == Fixed8.Zero(): print("No gas to claim") return None, False claim_tx = ClaimTransaction() claim_tx.Claims = unclaimed_coin_refs claim_tx.Attributes = [] claim_tx.inputs = [] script_hash = wallet.GetChangeAddress() # the following can be used to claim gas that is in an imported contract_addr # example, wallet claim --from-addr={smart contract addr} if from_addr_str: script_hash = None script_hash = PromptUtils.lookup_addr_str(wallet, from_addr_str) if script_hash is None: logger.debug("invalid source address") return None, False standard_contract = wallet.GetStandardAddress() claim_tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=standard_contract.Data) ] if to_addr_str: script_hash = None script_hash = PromptUtils.lookup_addr_str(wallet, to_addr_str) if script_hash is None: logger.debug("invalid destination address") return None, False claim_tx.outputs = [ TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=available_bonus, script_hash=script_hash) ] context = ContractParametersContext(claim_tx) wallet.Sign(context) print("\n---------------------------------------------------------------") print(f"Will make claim for {available_bonus.ToString()} GAS") print( "------------------------------------------------------------------\n") if require_password: print("Enter your password to complete this claim") passwd = prompt("[Password]> ", is_password=True) if not wallet.ValidatePassword(passwd): print("Incorrect password") return None, False if context.Completed: claim_tx.scripts = context.GetScripts() print("claim tx: %s " % json.dumps(claim_tx.ToJson(), indent=4)) relayed = NodeLeader.Instance().Relay(claim_tx) if relayed: print("Relayed Tx: %s " % claim_tx.Hash.ToString()) wallet.SaveTransaction(claim_tx) else: print("Could not relay tx %s " % claim_tx.Hash.ToString()) return claim_tx, relayed else: print("could not sign tx") return None, False
def construct_invoke_tx(wallet, params): params = params[0] from_addr = params['from_addr'] BC = GetBlockchain() contract = BC.GetContract(params['addr']) if not contract: raise Exception('no such contract') neo_to_attach = params.get('neo_to_attach', 0) gas_to_attach = params.get('gas_to_attach', 0) sb = ScriptBuilder() contract_parameters = [ContractParameter.FromJson(p) for p in params['contract_params']] sb.EmitAppCallWithJsonArgs(contract.Code.ScriptHash(), contract_parameters) invoke_script = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(invoke_script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False).Data)] tx = wallet.MakeTransaction(tx=tx) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True ) engine.LoadScript(tx.Script, False) success = engine.Execute() if not success: raise Exception('exec failed') service.ExecutionCompleted(engine, success) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = Fixed8.FromDecimal(.0001) tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() tx.Gas = tx_gas tx.outputs = outputs tx.Attributes = [] # InvokeContract from_addr = lookup_addr_str(wallet, from_addr) tx = wallet.MakeTransaction(tx=tx, fee=net_fee, use_standard=True, from_addr=from_addr) if tx is None: raise Exception("no gas") context = ContractParametersContext(tx) ms = StreamManager.GetStream() writer = BinaryWriter(ms) tx.Serialize(writer) ms.flush() binary_tx = ms.ToArray() return {'context': context.ToJson(), 'tx': binary_tx.decode()}
def MakeTransaction(self, tx, change_address=None, fee=Fixed8(0), from_addr=None, use_standard=False, watch_only_val=0, exclude_vin=None, use_vins_for_asset=None, skip_fee_calc=False): """ This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ). Args: tx (Transaction): The Transaction to be used. change_address (UInt160): The address any change for the transaction should be returned to. fee (Fixed8): A fee to be attached to the Transaction for network processing purposes. from_addr (UInt160): If present, all CoinReferences selected will only come from this address. use_standard (bool): If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used. watch_only_val (int): 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address. exclude_vin (list): A list of CoinReferences to NOT use in the making of this tx. use_vins_for_asset (list): A list of CoinReferences to use. skip_fee_calc (bool): If true, the network fee calculation and verification will be skipped. Returns: tx: (Transaction) Returns the transaction with oupdated inputs and outputs. """ tx.ResetReferences() tx.ResetHashData() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + tx.SystemFee() # pdb.set_trace() paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value cur_val = paytotal.get(key, Fixed8.Zero()) paytotal[key] = cur_val + sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin().Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} self._vin_exclude = exclude_vin for assetId, amount in paytotal.items(): if use_vins_for_asset is not None and len(use_vins_for_asset) > 0 and use_vins_for_asset[1] == assetId: paycoins[assetId] = self.FindCoinsByVins(use_vins_for_asset[0]) else: paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) self._vin_exclude = None for key, unspents in paycoins.items(): if unspents is None: if not self.IsSynced: logger.warning("Wait for your wallet to be synced before doing " "transactions. To check enter 'wallet' and look at " "'percent_synced', it should be 100. Also the blockchain " "should be up to the latest blocks (see Progress). Issuing " "'wallet rebuild' restarts the syncing process.") return None else: raise ValueError(f"insufficient funds for asset id: {key}") input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress(from_addr=from_addr) new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs # calculate and verify the required network fee for the tx if tx.Size() > settings.MAX_FREE_TX_SIZE and not skip_fee_calc: req_fee = Fixed8.FromDecimal(settings.FEE_PER_EXTRA_BYTE * (tx.Size() - settings.MAX_FREE_TX_SIZE)) if req_fee < settings.LOW_PRIORITY_THRESHOLD: req_fee = settings.LOW_PRIORITY_THRESHOLD if fee < req_fee: raise TXFeeError(f'Transaction cancelled. The tx size ({tx.Size()}) exceeds the max free tx size ({settings.MAX_FREE_TX_SIZE}).\nA network fee of {req_fee.ToString()} GAS is required.') return tx