def get_accountstate(self, request, key_wallet): request.setHeader('Content-Type', 'application/json') try: print(key_wallet) acct = Blockchain.Default().GetAccountState(key_wallet) print(acct.ToJson()) if acct is None: try: acct = AccountState( script_hash=Helper.AddrStrToScriptHash(key_wallet)) except Exception as e: self.format_message( "Could not get contract with hash %s because test" % (key_wallet)) acctString = json.dumps(acct.ToJson()) acctString = acctString.replace( "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", "NEO") acctString = acctString.replace( "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7", "GAS") return json.dumps({'response': json.loads(acctString)}) except Exception as e: return self.format_message( "Could not get contract with hash %s because %s " % (acct.ToJson(), e)) return self.format_message( "Could not get contract with hash %s because test" % (key_wallet))
def test_accountstate_ToJson(self): hash = UInt160(data=self.ac2_h) account = AccountState(script_hash=hash) res = account.ToJson() self.assertEqual(res['address'], account.Address) self.assertEqual(res['script_hash'], str(hash))
def Blockchain_GetAccount(self, engine: ExecutionEngine): hash = UInt160(data=engine.CurrentContext.EvaluationStack.Pop().GetByteArray()) address = Crypto.ToAddress(hash).encode('utf-8') account = self.Accounts.GetOrAdd(address, new_instance=AccountState(script_hash=hash)) engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(account)) return True
def test_account_2(self): hash = UInt160(data=self.ac2_h) account2 = AccountState(script_hash=hash) addr = account2.Address self.assertEqual(addr, self.ac2_a) input = binascii.unhexlify(self.assset) asset = AssetState.DeserializeFromDB(input) account2.AddToBalance(asset.AssetId, Fixed8(97800000000)) # print("account 2 %s " % json.dumps(account2.ToJson(), indent=4)) self.assertEqual(account2.BalanceFor(asset.AssetId), Fixed8(97800000000)) input = binascii.unhexlify(self.ac1_out) account1 = AccountState.DeserializeFromDB(input)
def json_rpc_method_handler(self, method, params): if method == "getaccountstate": acct = Blockchain.Default().GetAccountState(params[0]) if acct is None: try: acct = AccountState( script_hash=Helper.AddrStrToScriptHash(params[0])) except Exception as e: raise JsonRpcError( -2146233033, "One of the identified items was in an invalid format." ) return acct.ToJson() elif method == "getassetstate": asset_id = UInt256.ParseString(params[0]) asset = Blockchain.Default().GetAssetState(asset_id.ToBytes()) if asset: return asset.ToJson() raise JsonRpcError(-100, "Unknown asset") elif method == "getbestblockhash": return '0x%s' % Blockchain.Default().CurrentHeaderHash.decode( 'utf-8') elif method == "getblock": # this should work for either str or int block = Blockchain.Default().GetBlock(params[0]) if not block: raise JsonRpcError(-100, "Unknown block") return self.get_block_output(block, params) elif method == "getblockcount": return Blockchain.Default().Height + 1 elif method == "getblockhash": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return '0x%s' % Blockchain.Default().GetBlockHash( height).decode('utf-8') else: raise JsonRpcError(-100, "Invalid Height") elif method == "getblocksysfee": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return Blockchain.Default().GetSysFeeAmountByHeight(height) else: raise JsonRpcError(-100, "Invalid Height") elif method == "getconnectioncount": return len(NodeLeader.Instance().Peers) elif method == "getcontractstate": script_hash = UInt160.ParseString(params[0]) contract = Blockchain.Default().GetContract(script_hash.ToBytes()) if contract is None: raise JsonRpcError(-100, "Unknown contract") return contract.ToJson() elif method == "getrawmempool": return list( map(lambda hash: "0x%s" % hash.decode('utf-8'), NodeLeader.Instance().MemPool.keys())) elif method == "getversion": return { "port": self.port, "nonce": NodeLeader.Instance().NodeId, "useragent": settings.VERSION_NAME } elif method == "getrawtransaction": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") return self.get_tx_output(tx, height, params) elif method == "getstorage": script_hash = UInt160.ParseString(params[0]) key = binascii.unhexlify(params[1].encode('utf-8')) storage_key = StorageKey(script_hash=script_hash, key=key) storage_item = Blockchain.Default().GetStorageItem(storage_key) if storage_item: return storage_item.Value.hex() return None elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "invoke": shash = UInt160.ParseString(params[0]) contract_parameters = [ ContractParameter.FromJson(p) for p in params[1] ] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(shash, contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokefunction": contract_parameters = [] if len(params) > 2: contract_parameters = [ ContractParameter.FromJson(p).ToVM() for p in params[2] ] sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs(UInt160.ParseString(params[0]), params[1], contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokescript": script = params[0].encode('utf-8') return self.get_invoke_result(script) elif method == "sendrawtransaction": tx_script = binascii.unhexlify(params[0].encode('utf-8')) transaction = Transaction.DeserializeFromBufer(tx_script) result = NodeLeader.Instance().Relay(transaction) return result elif method == "validateaddress": return self.validateaddress(params) elif method == "getpeers": return self.get_peers() elif method == "getbalance": if self.wallet: return self.get_balance(params) else: raise JsonRpcError(-400, "Access denied.") elif method == "getwalletheight": if self.wallet: return self.wallet.WalletHeight else: raise JsonRpcError(-400, "Access denied.") elif method == "listaddress": if self.wallet: return self.list_address() else: raise JsonRpcError(-400, "Access denied.") elif method == "getnewaddress": if self.wallet: keys = self.wallet.CreateKey() account = Account.get( PublicKeyHash=keys.PublicKeyHash.ToBytes()) return account.contract_set[0].Address.ToString() else: raise JsonRpcError(-400, "Access denied.") raise JsonRpcError.methodNotFound()
def json_rpc_method_handler(self, method, params): if method == "getaccountstate": acct = Blockchain.Default().GetAccountState(params[0]) if acct is None: try: acct = AccountState(script_hash=Helper.AddrStrToScriptHash(params[0])) except Exception as e: raise JsonRpcError(-2146233033, "One of the identified items was in an invalid format.") return acct.ToJson() elif method == "getassetstate": asset_id = UInt256.ParseString(params[0]) asset = Blockchain.Default().GetAssetState(asset_id.ToBytes()) if asset: return asset.ToJson() raise JsonRpcError(-100, "Unknown asset") elif method == "getbestblockhash": return '0x%s' % Blockchain.Default().CurrentHeaderHash.decode('utf-8') elif method == "getblock": # this should work for either str or int block = Blockchain.Default().GetBlock(params[0]) if not block: raise JsonRpcError(-100, "Unknown block") return self.get_block_output(block, params) elif method == "getblockcount": return Blockchain.Default().Height + 1 elif method == "getblockhash": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return '0x%s' % Blockchain.Default().GetBlockHash(height).decode('utf-8') else: raise JsonRpcError(-100, "Invalid Height") elif method == "getblocksysfee": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return Blockchain.Default().GetSysFeeAmountByHeight(height) else: raise JsonRpcError(-100, "Invalid Height") elif method == "getconnectioncount": return len(NodeLeader.Instance().Peers) elif method == "getcontractstate": script_hash = UInt160.ParseString(params[0]) contract = Blockchain.Default().GetContract(script_hash.ToBytes()) if contract is None: raise JsonRpcError(-100, "Unknown contract") return contract.ToJson() elif method == "getrawmempool": return list(map(lambda hash: "0x%s" % hash.decode('utf-8'), NodeLeader.Instance().MemPool.keys())) elif method == "getversion": return { "port": self.port, "nonce": NodeLeader.Instance().NodeId, "useragent": settings.VERSION_NAME } elif method == "getrawtransaction": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") return self.get_tx_output(tx, height, params) elif method == "getstorage": script_hash = UInt160.ParseString(params[0]) key = binascii.unhexlify(params[1].encode('utf-8')) storage_key = StorageKey(script_hash=script_hash, key=key) storage_item = Blockchain.Default().GetStorageItem(storage_key) if storage_item: return storage_item.Value.hex() return None elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "invoke": shash = UInt160.ParseString(params[0]) contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(shash, contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokefunction": contract_parameters = [] if len(params) > 2: contract_parameters = [ContractParameter.FromJson(p).ToVM() for p in params[2]] sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs(UInt160.ParseString(params[0]), params[1], contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokescript": script = params[0].encode('utf-8') return self.get_invoke_result(script) elif method == "sendrawtransaction": tx_script = binascii.unhexlify(params[0].encode('utf-8')) transaction = Transaction.DeserializeFromBufer(tx_script) result = NodeLeader.Instance().Relay(transaction) return result elif method == "mw_construct_send_tx": return MyWishMethods.construct_send_tx(self.wallet, params) elif method == "mw_construct_deploy_tx": return MyWishMethods.construct_deploy_tx(self.wallet, params) elif method == "mw_construct_invoke_tx": return MyWishMethods.construct_invoke_tx(self.wallet, params) elif method == "getapplicationlog": assert(all([x in '1234567890abcdefABCDEFxX' for x in params[0]])) # prevent traversal try: with open('/home/neo/neo-python/notis/' + params[0]) as f: res = [json.loads(x) for x in f.read().split('\n') if x] return [{'name': x['notify_type'], 'contract': x['contract'], 'args': x['payload']} for x in res] except FileNotFoundError: return ([]) elif method == "submitblock": raise NotImplementedError() elif method == "validateaddress": return self.validateaddress(params) elif method == "getpeers": return self.get_peers() raise JsonRpcError.methodNotFound()
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 Persist(self, block): accounts = DBCollection(self._db, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount( block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') with self._db.write_batch() as wb: for tx in block.Transactions: unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed( tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange( output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [ coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes() ] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange( input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange( input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append( SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange( prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance( assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [ result for result in tx.GetTransactionResults() if result.Amount.value < 0 ] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: validator = validators.GetAndChange( tx.PublicKey, ValidatorState(pub_key=tx.PublicKey)) # logger.info("VALIDATOR %s " % validator.ToJson()) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb=wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=True) engine.LoadScript(tx.Script) # normally, this function does not return true/false # for testing purposes, we try to execute and if an exception is raised # we will return false, otherwise if success return true # this is different than the 'success' bool returned by engine.Execute() # the 'success' bool returned by engine.Execute() is a value indicating # wether or not the invocation was successful, and if so, we then commit # the changes made by the contract to the database try: success = engine.Execute() # service.ExecutionCompleted(engine, success) return True except Exception as e: # service.ExecutionCompleted(self, False, e) return False
def test_account_state(self): hash = UInt160(data=self.shash) account = AccountState(script_hash=hash) addr = account.Address self.assertEqual(addr, self.saddr) input = binascii.unhexlify(self.assset) asset = AssetState.DeserializeFromDB(input) account.AddToBalance(asset.AssetId, Fixed8(2440000000)) self.assertEqual(account.BalanceFor(asset.AssetId), Fixed8(2440000000)) account.SubtractFromBalance(asset.AssetId, Fixed8(1220000000)) self.assertEqual(account.BalanceFor(asset.AssetId), Fixed8(1220000000)) self.assertEqual(account.HasBalance(asset.AssetId), True) sshare_hash = Blockchain.SystemShare().Hash account.SubtractFromBalance(sshare_hash, Fixed8(800000000)) self.assertFalse(account.AllBalancesZeroOrLess()) acct_json = account.ToJson() stream = StreamManager.GetStream() writer = BinaryWriter(stream) account.Serialize(writer) out = stream.ToArray() StreamManager.ReleaseStream(stream) input = binascii.unhexlify(out) newaccount = AccountState.DeserializeFromDB(input) self.assertEqual(acct_json, newaccount.ToJson())
def Persist(self, block): start = time.clock() sn = self._db.snapshot() accounts = DBCollection(self._db, sn, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, sn, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, sn, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, sn, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount(block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') self.__log.debug("[BlockFee] : %s %s " % (block.Index, amount_sysfee)) try: with self._db.write_batch() as wb: wb.put(DBPrefix.DATA_Block + block.Hash.ToBytes(), amount_sysfee_bytes + block.Trim()) for tx in block.Transactions: wb.put(DBPrefix.DATA_Transaction + tx.Hash.ToBytes(), block.IndexBytes() + tx.ToArray()) # go through all outputs and add unspent coins to them unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed(tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange(output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes()] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange(input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes() == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange(input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append(SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange(prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance(assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [result for result in tx.GetTransactionResults() if result.Amount.value < 0] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: newvalidator = ValidatorState(pub_key=tx.PublicKey) validators.GetAndChange(tx.PublicKey.ToBytes(), newvalidator) elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: # print("RUNNING INVOCATION TRASACTION!!!!!! %s %s " % (block.Index, tx.Hash.ToBytes())) print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: Invoke tx] -> index, tx hash %s %s " % (block.Index, tx.Hash.ToBytes())) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=False ) engine.LoadScript(tx.Script, False) try: # drum roll? success = engine.Execute() print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute] -> Success") if success: service.Commit() if len(service.notifications) > 0: for n in service.notifications: self.OnNotify(n) for item in engine.EvaluationStack.Items: print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute result] -> %s " % item) except Exception as e: print("[neo.Implementations.Blockchains.LevelDBBlockchain.PersistBlock: engine execute result] Could not execute smart contract. See logs for more details. %s " % e) else: if tx.Type != b'\x00' and tx.Type != 128: self.__log.debug("TX Not Found %s " % tx.Type) # do save all the accounts, unspent, coins, validators, assets, etc # now sawe the current sys block # filter out accounts to delete then commit for key, account in accounts.Current.items(): if not account.IsFrozen and len(account.Votes) == 0 and account.AllBalancesZeroOrLess(): accounts.Remove(key) accounts.Commit(wb) # filte out unspent coins to delete then commit for key, unspent in unspentcoins.Current.items(): unspentcoins.Remove(key) unspentcoins.Commit(wb) # filter out spent coins to delete then commit to db for key, spent in spentcoins.Current.items(): if len(spent.Items) == 0: spentcoins.Remove(key) spentcoins.Commit(wb) # commit validators validators.Commit(wb) # commit assets assets.Commit(wb) # commit contracts contracts.Commit(wb) # commit storages ( not implemented ) storages.Commit(wb) sn.close() wb.put(DBPrefix.SYS_CurrentBlock, block.Hash.ToBytes() + block.IndexBytes()) self._current_block_height = block.Index end = time.clock() self.__log.debug("PERSISTING BLOCK %s (cache) %s %s " % (block.Index, len(self._block_cache), end - start)) except Exception as e: print("couldnt persist block %s " % e)
def MonkeyPatchPersist(self, block, snapshot=None): if snapshot is None: 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) with self._db.getBatch() as wb: for tx in block.Transactions: 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)) # logger.info("VALIDATOR %s " % validator.ToJson()) 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.GetAndChange(tx.Code.ScriptHash().ToBytes(), create_contract_state) elif tx.Type == TransactionType.InvocationTransaction: return ApplicationEngine.Run(TriggerType.Application, tx, snapshot.Clone(), tx.Gas, True, wb)
def json_rpc_method_handler(self, method, params): if method == "getaccountstate": acct = Blockchain.Default().GetAccountState(params[0]) if acct is None: try: acct = AccountState(script_hash=Helper.AddrStrToScriptHash(params[0])) except Exception as e: raise JsonRpcError(-2146233033, "One of the identified items was in an invalid format.") return acct.ToJson() elif method == "getassetstate": asset_id = UInt256.ParseString(params[0]) asset = Blockchain.Default().GetAssetState(asset_id.ToBytes()) if asset: return asset.ToJson() raise JsonRpcError(-100, "Unknown asset") elif method == "getbestblockhash": return '0x%s' % Blockchain.Default().CurrentHeaderHash.decode('utf-8') elif method == "getblock": # this should work for either str or int block = Blockchain.Default().GetBlock(params[0]) if not block: raise JsonRpcError(-100, "Unknown block") return self.get_block_output(block, params) elif method == "getblockcount": return Blockchain.Default().Height + 1 elif method == "getblockhash": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return '0x%s' % Blockchain.Default().GetBlockHash(height).decode('utf-8') else: raise JsonRpcError(-100, "Invalid Height") elif method == "getblocksysfee": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return Blockchain.Default().GetSysFeeAmountByHeight(height) else: raise JsonRpcError(-100, "Invalid Height") elif method == "getconnectioncount": return len(NodeLeader.Instance().Peers) elif method == "getcontractstate": script_hash = UInt160.ParseString(params[0]) contract = Blockchain.Default().GetContract(script_hash.ToBytes()) if contract is None: raise JsonRpcError(-100, "Unknown contract") return contract.ToJson() elif method == "getrawmempool": return list(map(lambda hash: "0x%s" % hash.decode('utf-8'), NodeLeader.Instance().MemPool.keys())) elif method == "getversion": return { "port": self.port, "nonce": NodeLeader.Instance().NodeId, "useragent": settings.VERSION_NAME } elif method == "getrawtransaction": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") return self.get_tx_output(tx, height, params) elif method == "getLastBlog": if len(params) > 0: height = params[0] else: height = Blockchain.Default().Height + 1 data = self.get_blog_content(height, "") return data; elif method == "getLastBlogByTag": if len(params) > 1: height = params[1] tag = params[0] elif len(params) > 0: tag = params[0] height = Blockchain.Default().Height + 1 else: raise JsonRpcError(-100, "no enough param") data = self.get_blog_content(height, tag) return data; elif method == "getLastBlogBySender": if len(params) > 1: height = params[1] sender = params[0] elif len(params) > 0: sender = params[0] height = Blockchain.Default().Height + 1 else: raise JsonRpcError(-100, "no enough param") data = self.get_blog_content(height, "", sender) return data; elif method == "getBlogContent": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") for attr in tx.Attributes: item = attr.ToJson; if item['usage'] == 240: item['content'] = binascii.a2b_hex(item['data']).decode("utf8") return item; raise JsonRpcError(-100, "no blog content") elif method == "getstorage": script_hash = UInt160.ParseString(params[0]) key = binascii.unhexlify(params[1].encode('utf-8')) storage_key = StorageKey(script_hash=script_hash, key=key) storage_item = Blockchain.Default().GetStorageItem(storage_key) if storage_item: return storage_item.Value.hex() return None elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "createAddress": private_key = bytes(Random.get_random_bytes(32)) key = KeyPair(priv_key=private_key) self.wallet._keys[key.PublicKeyHash.ToBytes()] = key self.wallet.OnCreateAccount(key) contract = WalletContract.CreateSignatureContract(key.PublicKey) self.wallet.AddContract(contract) if key : result = {'privateKey': key.Export(),'address':contract.Address} return result; else: return None elif method == "invoke": shash = UInt160.ParseString(params[0]) contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(shash, contract_parameters) return self.get_invoke_result(sb.ToArray()) # elif method == "sendBlog": # shash = UInt160.ParseString(params[0]) # contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] # sb = ScriptBuilder() # sb.EmitAppCallWithJsonArgs(shash, contract_parameters) # script = sb.ToArray(); # tx = ContractTransaction() # tx.inputs = [] # tx.outputs = [] # attribute = TransactionAttribute(240, params[2].encode('utf-8')) # standard_contract = self.wallet.GetStandardAddress() # data = standard_contract.Data # tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, # data=data)] # # tx.Attributes.append(attribute) # tx.Version = 1 # tx.scripts = [] # BC = GetBlockchain() # contract = BC.GetContract(params[0]) # output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, # Value=Fixed8.FromDecimal(float(1)), # script_hash=contract.Code.ScriptHash(), # ) # tx.outputs.append(output) # logger.info("output %s" % output.ToJson(0)) # tx.Script = binascii.unhexlify(script) # print("percentage %s %s" % (self.wallet.WalletHeight, Blockchain.Default().Height)) # scripthash_from = None # if not self.wallet.IsSynced: # raise JsonRpcError.invalidRequest("wallet not synced") # private_key = None # if len(params) > 3: # from_address = params[3] # if from_address is not None: # scripthash_from = lookup_addr_str(self.wallet, from_address) # if len(params) > 4: # private_key = params[4] # wallet_tx = SendBlog(self.wallet, tx, from_addr=scripthash_from, privatekey=private_key) # if wallet_tx != False: # return wallet_tx.ToJson(); # self.wallet.Rebuild() # raise JsonRpcError.invalidRequest("Field 'no enough asset") elif method == 'postblog': try: if len(params) > 3: from_address = params[3] assetId =Blockchain.SystemShare().Hash if len(params) > 4: private_key = params[4] if assetId is None: print("Asset id not found") return False contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(UInt160.ParseString(params[0]), contract_parameters) script = sb.ToArray(); scripthash_from = None if from_address is not None: scripthash_from = lookup_addr_str(self.wallet, from_address) # f8amount = Fixed8.TryParse(0, require_positive=True) # if f8amount is None: # print("invalid amount format") # return False # # if type(assetId) is UInt256 and f8amount.value % pow(10, 8 - Blockchain.Default().GetAssetState( # assetId.ToBytes()).Precision) != 0: # print("incorrect amount precision") # return False # fee = Fixed8.Zero() # # output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=contract.Code.ScriptHash()) tx = InvocationTransaction() ttx = self.wallet.MakeTransaction(tx=tx, change_address=None, fee=fee, from_addr=scripthash_from) if ttx is None: print("insufficient funds") return False standard_contract = self.wallet.GetStandardAddress() if scripthash_from is not None: signer_contract = self.wallet.GetContract(scripthash_from) else: signer_contract = self.wallet.GetContract(standard_contract) if not signer_contract.IsMultiSigContract: data = scripthash_from.Data print(data) tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=data),TransactionAttribute(usage=TransactionAttributeUsage.Remark1, data=from_address.encode('utf-8'))] # insert any additional user specified tx attributes tx.Attributes.append(TransactionAttribute(240, params[2].encode('utf-8'))) tx.Script = binascii.unhexlify(script) context = ContractParametersContext(tx, isMultiSig=signer_contract.IsMultiSigContract) if private_key is not None: prikey = KeyPair.PrivateKeyFromWIF(private_key) kp = KeyPair(prikey) self.wallet.Sign(context,kp) attributes = [attr.ToJson() for attr in tx.Attributes] print("attributes %s" %attributes) if context.Completed: tx.scripts = context.GetScripts() # print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4)) relayed = NodeLeader.Instance().Relay(tx) if relayed: self.wallet.SaveTransaction(tx) print("Relayed Tx: %s " % tx.Hash.ToString()) return tx.ToJson() else: print("Could not relay tx %s " % tx.Hash.ToString()) else: print("Transaction initiated, but the signature is incomplete") print(json.dumps(context.ToJson(), separators=(',', ':'))) return False except Exception as e: print("could not send: %s " % e) return False elif method == "invokefunction": contract_parameters = [] if len(params) > 2: contract_parameters = [ContractParameter.FromJson(p).ToVM() for p in params[2]] sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs(UInt160.ParseString(params[0]), params[1], contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokescript": script = params[0].encode('utf-8') return self.get_invoke_result(script) elif method == "sendrawtransaction": tx_script = binascii.unhexlify(params[0].encode('utf-8')) transaction = Transaction.DeserializeFromBufer(tx_script) result = NodeLeader.Instance().Relay(transaction) return result elif method == "submitblock": raise NotImplementedError() elif method == "validateaddress": return self.validateaddress(params) elif method == "getpeers": raise NotImplementedError() raise JsonRpcError.methodNotFound()
def json_rpc_method_handler(self, method, params): if method == "getaccountstate": acct = Blockchain.Default().GetAccountState(params[0]) if acct is None: try: acct = AccountState(script_hash=Helper.AddrStrToScriptHash(params[0])) except Exception as e: raise JsonRpcError(-2146233033, "One of the identified items was in an invalid format.") return acct.ToJson() elif method == "getassetstate": asset_str = params[0] if asset_str.lower() == 'neo': assetId = Blockchain.Default().SystemShare().Hash elif asset_str.lower() == 'gas': assetId = Blockchain.Default().SystemCoin().Hash else: assetId = UInt256.ParseString(params[0]) asset = Blockchain.Default().GetAssetState(assetId.ToBytes()) if asset: return asset.ToJson() raise JsonRpcError(-100, "Unknown asset") elif method == "getbestblockhash": return '0x%s' % Blockchain.Default().CurrentHeaderHash.decode('utf-8') elif method == "getblock": # this should work for either str or int block = Blockchain.Default().GetBlock(params[0]) if not block: raise JsonRpcError(-100, "Unknown block") return self.get_block_output(block, params) elif method == "getblockcount": return Blockchain.Default().Height + 1 elif method == "getblockhash": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return '0x%s' % Blockchain.Default().GetBlockHash(height).decode('utf-8') else: raise JsonRpcError(-100, "Invalid Height") elif method == "getblocksysfee": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return Blockchain.Default().GetSysFeeAmountByHeight(height) else: raise JsonRpcError(-100, "Invalid Height") elif method == "getconnectioncount": return len(self.nodemgr.nodes) elif method == "getcontractstate": script_hash = UInt160.ParseString(params[0]) contract = Blockchain.Default().GetContract(script_hash.ToBytes()) if contract is None: raise JsonRpcError(-100, "Unknown contract") return contract.ToJson() elif method == "getrawmempool": raise JsonRpcError(-100, "Not supported") # return list(map(lambda hash: f"{hash.To0xString()}", self.nodemgr.mempool.pool.keys())) elif method == "getversion": return { "port": self.port, "nonce": self.nodemgr.id, "useragent": settings.VERSION_NAME } elif method == "getrawtransaction": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") return self.get_tx_output(tx, height, params) elif method == "getstorage": script_hash = UInt160.ParseString(params[0]) key = binascii.unhexlify(params[1].encode('utf-8')) storage_key = StorageKey(script_hash=script_hash, key=key) storage_item = Blockchain.Default().GetStorageItem(storage_key) if storage_item: return storage_item.Value.hex() return None elif method == "gettransactionheight": try: hash = UInt256.ParseString(params[0]) except Exception: # throws exception, not anything more specific raise JsonRpcError(-100, "Unknown transaction") tx, height = Blockchain.Default().GetTransaction(hash) if tx: return height else: raise JsonRpcError(-100, "Unknown transaction") elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "invoke": shash = UInt160.ParseString(params[0]) contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(shash, contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokefunction": contract_parameters = [] if len(params) > 2: contract_parameters = [ContractParameter.FromJson(p).ToVM() for p in params[2]] sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs(UInt160.ParseString(params[0]), params[1], contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokescript": script = params[0].encode('utf-8') return self.get_invoke_result(script) elif method == "sendrawtransaction": tx_script = binascii.unhexlify(params[0].encode('utf-8')) transaction = Transaction.DeserializeFromBufer(tx_script) # TODO: relay blocks, change to await in the future result = self.nodemgr.relay(transaction) return result elif method == "validateaddress": return self.validateaddress(params) elif method == "getpeers": return self.get_peers() elif method == "getbalance": if self.wallet: return self.get_balance(params) else: raise JsonRpcError(-400, "Access denied.") elif method == "getwalletheight": if self.wallet: return self.wallet.WalletHeight else: raise JsonRpcError(-400, "Access denied.") elif method == "listaddress": if self.wallet: return self.list_address() else: raise JsonRpcError(-400, "Access denied.") elif method == "getnewaddress": if self.wallet: keys = self.wallet.CreateKey() account = Account.get( PublicKeyHash=keys.PublicKeyHash.ToBytes() ) return account.contract_set[0].Address.ToString() else: raise JsonRpcError(-400, "Access denied.") elif method == "sendtoaddress": if self.wallet: contract_tx, fee = self.parse_send_to_address_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee) else: raise JsonRpcError(-400, "Access denied.") elif method == "sendfrom": if self.wallet: contract_tx, address_from, fee, change_addr = self.parse_send_from_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee, address_from=address_from, change_addr=change_addr) else: raise JsonRpcError(-400, "Access denied.") elif method == "sendmany": if self.wallet: contract_tx, fee, change_addr = self.parse_send_many_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee, change_addr=change_addr) else: raise JsonRpcError(-400, "Access denied.") elif method == "getblockheader": # this should work for either str or int blockheader = Blockchain.Default().GetHeaderBy(params[0]) if not blockheader: raise JsonRpcError(-100, "Unknown block") return self.get_blockheader_output(blockheader, params) raise JsonRpcError.methodNotFound()
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)