Skip to content

Commit ad03d98

Browse files
ryanschneiderfjl
authored andcommitted
internal/ethapi: support block number or hash on state-related methods (#19491)
This change adds support for EIP-1898.
1 parent 62391dd commit ad03d98

File tree

10 files changed

+408
-166
lines changed

10 files changed

+408
-166
lines changed

core/blockchain.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,11 @@ func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
21392139
return bc.hc.HasHeader(hash, number)
21402140
}
21412141

2142+
// GetCanonicalHash returns the canonical hash for a given block number
2143+
func (bc *BlockChain) GetCanonicalHash(number uint64) common.Hash {
2144+
return bc.hc.GetCanonicalHash(number)
2145+
}
2146+
21422147
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
21432148
// hash, fetching towards the genesis block.
21442149
func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash {

core/headerchain.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
448448
return hc.GetHeader(hash, number)
449449
}
450450

451+
func (hc *HeaderChain) GetCanonicalHash(number uint64) common.Hash {
452+
return rawdb.ReadCanonicalHash(hc.chainDb, number)
453+
}
454+
451455
// CurrentHeader retrieves the current head header of the canonical chain. The
452456
// header is retrieved from the HeaderChain's internal cache.
453457
func (hc *HeaderChain) CurrentHeader() *types.Header {

eth/api_backend.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
7272
return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil
7373
}
7474

75+
func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
76+
if blockNr, ok := blockNrOrHash.Number(); ok {
77+
return b.HeaderByNumber(ctx, blockNr)
78+
}
79+
if hash, ok := blockNrOrHash.Hash(); ok {
80+
header := b.eth.blockchain.GetHeaderByHash(hash)
81+
if header == nil {
82+
return nil, errors.New("header for hash not found")
83+
}
84+
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
85+
return nil, errors.New("hash is not currently canonical")
86+
}
87+
return header, nil
88+
}
89+
return nil, errors.New("invalid arguments; neither block nor hash specified")
90+
}
91+
7592
func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
7693
return b.eth.blockchain.GetHeaderByHash(hash), nil
7794
}
@@ -93,6 +110,27 @@ func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ
93110
return b.eth.blockchain.GetBlockByHash(hash), nil
94111
}
95112

113+
func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
114+
if blockNr, ok := blockNrOrHash.Number(); ok {
115+
return b.BlockByNumber(ctx, blockNr)
116+
}
117+
if hash, ok := blockNrOrHash.Hash(); ok {
118+
header := b.eth.blockchain.GetHeaderByHash(hash)
119+
if header == nil {
120+
return nil, errors.New("header for hash not found")
121+
}
122+
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
123+
return nil, errors.New("hash is not currently canonical")
124+
}
125+
block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64())
126+
if block == nil {
127+
return nil, errors.New("header found, but block body is missing")
128+
}
129+
return block, nil
130+
}
131+
return nil, errors.New("invalid arguments; neither block nor hash specified")
132+
}
133+
96134
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
97135
// Pending state is only known by the miner
98136
if number == rpc.PendingBlockNumber {
@@ -111,6 +149,27 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
111149
return stateDb, header, err
112150
}
113151

152+
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
153+
if blockNr, ok := blockNrOrHash.Number(); ok {
154+
return b.StateAndHeaderByNumber(ctx, blockNr)
155+
}
156+
if hash, ok := blockNrOrHash.Hash(); ok {
157+
header, err := b.HeaderByHash(ctx, hash)
158+
if err != nil {
159+
return nil, nil, err
160+
}
161+
if header == nil {
162+
return nil, nil, errors.New("header for hash not found")
163+
}
164+
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
165+
return nil, nil, errors.New("hash is not currently canonical")
166+
}
167+
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
168+
return stateDb, header, err
169+
}
170+
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
171+
}
172+
114173
func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
115174
return b.eth.blockchain.GetReceiptsByHash(hash), nil
116175
}

0 commit comments

Comments
 (0)