1. 执行
命令:
eth.getBalance("0xd4C3b95bf0bbF0Fd0087062125dD572114DeD44F")
执行结果:
0
2. UML图
UML3.流程图
流程图4. 代码流程
go-ethereum/internal/ethapi/api.go
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) //4.1
if state == nil || err != nil {
return nil, err
}
b := state.GetBalance(address) //4.2 state:StateDB
return b, state.Error()
}
4.1. StateAndHeaderByNumber
go-ethereum/eth/api_backend.go (blockNr: -1)
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner
if blockNr == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending()
return state, block.Header(), nil
}
// Otherwise resolve the block number and return its state
header, err := b.HeaderByNumber(ctx, blockNr) //3.1.1
if header == nil || err != nil {
return nil, nil, err
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root) //3.1.2
return stateDb, header, err
}
4.1.1 HeaderByNumber
Ethereum -> *core.BlockChain -> currentBlock -> Header
go-ethereum/eth/api_backend.go
func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
// Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber {
block := b.eth.miner.PendingBlock()
return block.Header(), nil
}
// Otherwise resolve and return the block
if blockNr == rpc.LatestBlockNumber { //blockNr: -1
return b.eth.blockchain.CurrentBlock().Header(), nil //获得 Header
}
return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)), nil
}
4.1.2 StateAt
go-ethereum/core/blockchain.go
// StateAt returns a new mutable state based on a particular point in time.
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
return state.New(root, bc.stateCache) //3.1.2.1
}
4.1.2.1 New
go-ethereum/core/state/statedb.go
// Create a new state from a given trie.
func New(root common.Hash, db Database) (*StateDB, error) {
tr, err := db.OpenTrie(root)
if err != nil {
return nil, err
}
return &StateDB{
db: db,
trie: tr,
stateObjects: make(map[common.Address]*stateObject),
stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
}, nil
}
4.2. GetBalance
获得stateObject,通过stateObject获得balance
go-ethereum/core/state/statedb.go
// Retrieve the balance from the given address or 0 if object not found
func (self *StateDB) GetBalance(addr common.Address) *big.Int {
stateObject := self.getStateObject(addr) //4.2.1
if stateObject != nil {
return stateObject.Balance() //4.2.2
}
return common.Big0
}
4.2.1. getStateObject
- 一级缓存:StateDB.stateObjects获取stateObject
- 缓存未命中,从StateDB.trie获取
go-ethereum/core/state/statedb.go
// Retrieve a state object given my the address. Returns nil if not found.
func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
// Prefer 'live' objects.
if obj := self.stateObjects[addr]; obj != nil { //StateDB.stateObjects获取stateObject
if obj.deleted {
return nil
}
return obj
}
// Load the object from the database.
enc, err := self.trie.TryGet(addr[:]) //从StateDB.trie获取
if len(enc) == 0 {
self.setError(err)
return nil
}
var data Account
if err := rlp.DecodeBytes(enc, &data); err != nil {
log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
// Insert into the live set.
obj := newObject(self, addr, data) //new
self.setStateObject(obj) //add to map 放入缓存
return obj
}
4.2.2. Balance
- 从stateObject的data获取Balance
go-ethereum/core/state/state_object.go
func (self *stateObject) Balance() *big.Int {
return self.data.Balance //data:Acount
}
网友评论