美文网首页以太坊源码学习笔记
ETH源码阅读(获得一个地址的余额getBalance)

ETH源码阅读(获得一个地址的余额getBalance)

作者: 坠叶飘香 | 来源:发表于2018-05-14 17:20 被阅读0次

    1. 执行

    命令:

    eth.getBalance("0xd4C3b95bf0bbF0Fd0087062125dD572114DeD44F")
    

    执行结果:

    0
    

    2. UML图

    UML

    3.流程图

    流程图

    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
    }
    

    相关文章

      网友评论

        本文标题:ETH源码阅读(获得一个地址的余额getBalance)

        本文链接:https://www.haomeiwen.com/subject/iohjdftx.html