api: Fetch pending state from txpool

This commit changes the source of the state when asking for the
*pending* state.  Instead of consulting the miner of the node, it uses
teh pending state of the transaction pool.

Two reasons for this change:

1. Introduction of the consensus package + BFT algorithms

With the introduction of the consensus package and the potential BFT
algorithms being built with it, the concept of the "pending block/state"
changes its definition.  In some of these algorithms, pending block can
mean a block that is in the process of validation, but that can no
longer be updated.  This conflicts with the traditional meaning of
"pending state", being the latest block plus all known pending
transactions.

Most notably, the Istanbul implementation has this problem.  This also
results in the values for the pending state being different for a node
that has the miner enabled and the miner disabled.

2. General principle that the miner package should be disabled for
non-mining nodes

So considering the previous point, the use of the miner package for
something else than mining should be evaluated.  I think it makes sense
to try working towards not using it at all when a node does not
participate in the mining/validating process.
Currently, the miner's pending state is used (a.o.) for executing new
incoming transactions (because the EVM needs a "current block" for the
global getters).  I think this should be fairly easy to work around and
this is a first step.
This commit is contained in:
Steven Roose 2018-01-24 15:41:59 +01:00
parent 302c17c36a
commit cff5803b27
6 changed files with 33 additions and 18 deletions

View file

@ -1348,6 +1348,11 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com
return bc.hc.GetBlockHashesFromHash(hash, max) return bc.hc.GetBlockHashesFromHash(hash, max)
} }
// GetBlockHashByNumber retrieves the block hash from the database by number.
func (bc *BlockChain) GetBlockHashByNumber(number uint64) common.Hash {
return bc.hc.GetBlockHashByNumber(number)
}
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {

View file

@ -370,10 +370,15 @@ func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
return ok return ok
} }
// GetBlockHashByNumber retrieves the block hash from the database by number.
func (hc *HeaderChain) GetBlockHashByNumber(number uint64) common.Hash {
return GetCanonicalHash(hc.chainDb, number)
}
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
hash := GetCanonicalHash(hc.chainDb, number) hash := hc.GetBlockHashByNumber(number)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
return nil return nil
} }

View file

@ -81,19 +81,19 @@ func (b *EthApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
} }
func (b *EthApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) { func (b *EthApiBackend) StateByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, error) {
// Pending state is only known by the miner // Pending state is only known by the miner
if blockNr == rpc.PendingBlockNumber { if blockNr == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending() return b.eth.TxPool().State().StateDB, nil
return state, block.Header(), nil
} }
// Otherwise resolve the block number and return its state // Otherwise resolve the block number and return its state
header, err := b.HeaderByNumber(ctx, blockNr) if blockNr == rpc.LatestBlockNumber {
if header == nil || err != nil { return b.eth.BlockChain().State()
return nil, nil, err
} }
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err blockHash := b.eth.BlockChain().GetBlockHashByNumber(uint64(blockNr))
return b.eth.BlockChain().StateAt(blockHash)
} }
func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) { func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {

View file

@ -463,7 +463,7 @@ func (s *PublicBlockChainAPI) BlockNumber() *big.Int {
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed. // block numbers are also allowed.
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, err := s.b.StateByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -550,7 +550,7 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, bloc
// GetCode returns the code stored at the given address in the state for the given block number. // GetCode returns the code stored at the given address in the state for the given block number.
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, err := s.b.StateByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -562,7 +562,7 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Addres
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
// numbers are also allowed. // numbers are also allowed.
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, err := s.b.StateByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
@ -583,10 +583,15 @@ type CallArgs struct {
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, uint64, bool, error) { func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, uint64, bool, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, err := s.b.StateByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, 0, false, err return nil, 0, false, err
} }
header, err := s.b.HeaderByNumber(ctx, blockNr)
if header == nil || err != nil {
return nil, 0, false, err
}
// Set sender address or use a default if none specified // Set sender address or use a default if none specified
addr := args.From addr := args.From
if addr == (common.Address{}) { if addr == (common.Address{}) {
@ -963,7 +968,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx cont
// GetTransactionCount returns the number of transactions the given address has sent for the given block number // GetTransactionCount returns the number of transactions the given address has sent for the given block number
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, err := s.b.StateByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }

View file

@ -49,7 +49,7 @@ type Backend interface {
SetHead(number uint64) SetHead(number uint64)
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetTd(blockHash common.Hash) *big.Int GetTd(blockHash common.Hash) *big.Int

View file

@ -71,12 +71,12 @@ func (b *LesApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb
return b.GetBlock(ctx, header.Hash()) return b.GetBlock(ctx, header.Hash())
} }
func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) { func (b *LesApiBackend) StateByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, error) {
header, err := b.HeaderByNumber(ctx, blockNr) header, err := b.HeaderByNumber(ctx, blockNr)
if header == nil || err != nil { if header == nil || err != nil {
return nil, nil, err return nil, err
} }
return light.NewState(ctx, header, b.eth.odr), header, nil return light.NewState(ctx, header, b.eth.odr), nil
} }
func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) { func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {