From bbe08ac6e6da32408e15d738cd34b43ca8e9a505 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Wed, 6 Mar 2024 14:10:08 +0800 Subject: [PATCH 1/2] core/state: add function GetStorageRoot --- core/state/state_object.go | 4 ++++ core/state/statedb.go | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/core/state/state_object.go b/core/state/state_object.go index 6d50461f15..a5c7ce0bc9 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -393,6 +393,10 @@ func (self *stateObject) Nonce() uint64 { return self.data.Nonce } +func (self *stateObject) Root() common.Hash { + return self.data.Root +} + // Never called, but must be present to allow stateObject to be used // as a vm.Account interface that also satisfies the vm.ContractRef // interface. Interfaces are awesome. diff --git a/core/state/statedb.go b/core/state/statedb.go index 07bcf7596b..8b374fda65 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -221,6 +221,16 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 { return 0 } +// GetStorageRoot retrieves the storage root from the given address or empty +// if object not found. +func (self *StateDB) GetStorageRoot(addr common.Address) common.Hash { + stateObject := self.getStateObject(addr) + if stateObject != nil { + return stateObject.Root() + } + return common.Hash{} +} + func (self *StateDB) GetCode(addr common.Address) []byte { stateObject := self.getStateObject(addr) if stateObject != nil { From ece58f00b51fa31d76e934d468ab7e42a86db518 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Wed, 6 Mar 2024 14:11:15 +0800 Subject: [PATCH 2/2] ethapi: add method eth_getAccountInfo --- core/state/statedb.go | 30 ++++++++++++++++++++++++++++++ internal/ethapi/api.go | 18 ++++++++++++++++++ internal/jsre/deps/web3.js | 8 ++++++++ 3 files changed, 56 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 8b374fda65..4bedebe8b3 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -83,6 +83,14 @@ type StateDB struct { lock sync.Mutex } +type AccountInfo struct { + CodeSize int + Nonce uint64 + Balance *big.Int + CodeHash common.Hash + StorageHash common.Hash +} + func (self *StateDB) SubRefund(gas uint64) { self.journal = append(self.journal, refundChange{ prev: self.refund}) @@ -262,6 +270,28 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash { return common.BytesToHash(stateObject.CodeHash()) } +func (self *StateDB) GetAccountInfo(addr common.Address) *AccountInfo { + result := AccountInfo{} + + stateObject := self.getStateObject(addr) + if stateObject == nil { + result.Balance = common.Big0 + return &result + } + + if stateObject.code != nil { + result.CodeSize = len(stateObject.code) + } else { + result.CodeSize, _ = self.db.ContractCodeSize(stateObject.addrHash, common.BytesToHash(stateObject.CodeHash())) + } + result.Nonce = stateObject.Nonce() + result.Balance = stateObject.Balance() + result.CodeHash = common.BytesToHash(stateObject.CodeHash()) + result.StorageHash = stateObject.Root() + + return &result +} + func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash { stateObject := self.getStateObject(addr) if stateObject != nil { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 242584e863..519d4490ab 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -623,6 +623,24 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Addres return code, state.Error() } +// GetAccountInfo returns the information at the given address in the state for the given block number. +func (s *PublicBlockChainAPI) GetAccountInfo(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[string]interface{}, error) { + state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) + if state == nil || err != nil { + return nil, err + } + info := state.GetAccountInfo(address) + result := map[string]interface{}{ + "address": address, + "balance": (*hexutil.Big)(info.Balance), + "codeSize": info.CodeSize, + "codeHash": info.CodeHash, + "nonce": info.Nonce, + "storageHash": info.StorageHash, + } + return result, nil +} + // GetStorageAt returns the storage from the state at the given address, key and // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 95b0d1aaf7..5c7236ed14 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -5329,6 +5329,13 @@ var methods = function () { inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter] }); + var getAccountInfo = new Method({ + name: 'getAccountInfo', + call: 'eth_getAccountInfo', + params: 2, + inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter] + }); + var getBlock = new Method({ name: 'getBlock', call: blockCall, @@ -5513,6 +5520,7 @@ var methods = function () { getBalance, getStorageAt, getCode, + getAccountInfo, getBlock, getBlockSigners, getStakerROI,