mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
ethclient/lightclient: TransactionReader implemented
This commit is contained in:
parent
ef80de057a
commit
b31680fb19
3 changed files with 80 additions and 4 deletions
|
|
@ -265,6 +265,7 @@ func (c *canonicalChain) blockNumberOrHashToHash(ctx context.Context, blockNrOrH
|
||||||
|
|
||||||
type blocksAndHeaders struct {
|
type blocksAndHeaders struct {
|
||||||
client *rpc.Client
|
client *rpc.Client
|
||||||
|
txAndReceipts *txAndReceipts
|
||||||
headerCache *lru.Cache[common.Hash, *types.Header]
|
headerCache *lru.Cache[common.Hash, *types.Header]
|
||||||
headerRequests *requestMap[common.Hash, *types.Header]
|
headerRequests *requestMap[common.Hash, *types.Header]
|
||||||
payloadHeaderCache *lru.Cache[common.Hash, *btypes.ExecutionHeader]
|
payloadHeaderCache *lru.Cache[common.Hash, *btypes.ExecutionHeader]
|
||||||
|
|
@ -358,6 +359,7 @@ func (b *blocksAndHeaders) getBlock(ctx context.Context, hash common.Hash) (*typ
|
||||||
b.headerCache.Add(hash, header)
|
b.headerCache.Add(hash, header)
|
||||||
b.headerRequests.tryDeliver(hash, header)
|
b.headerRequests.tryDeliver(hash, header)
|
||||||
b.blockCache.Add(hash, block)
|
b.blockCache.Add(hash, block)
|
||||||
|
b.txAndReceipts.cacheBlockTxPositions(block)
|
||||||
}
|
}
|
||||||
req.release()
|
req.release()
|
||||||
return block, err
|
return block, err
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ func NewClient(clConfig config.LightClientConfig, elConfig *params.ChainConfig,
|
||||||
blocksAndHeaders := newBlocksAndHeaders(rpcClient)
|
blocksAndHeaders := newBlocksAndHeaders(rpcClient)
|
||||||
canonicalChain := newCanonicalChain(headTracker, blocksAndHeaders, client.newHead)
|
canonicalChain := newCanonicalChain(headTracker, blocksAndHeaders, client.newHead)
|
||||||
txAndReceipts := newTxAndReceipts(rpcClient, canonicalChain, blocksAndHeaders, elConfig)
|
txAndReceipts := newTxAndReceipts(rpcClient, canonicalChain, blocksAndHeaders, elConfig)
|
||||||
|
blocksAndHeaders.txAndReceipts = txAndReceipts
|
||||||
client.blocksAndHeaders = blocksAndHeaders
|
client.blocksAndHeaders = blocksAndHeaders
|
||||||
client.txAndReceipts = txAndReceipts
|
client.txAndReceipts = txAndReceipts
|
||||||
client.canonicalChain = canonicalChain
|
client.canonicalChain = canonicalChain
|
||||||
|
|
@ -100,6 +101,8 @@ func (c *Client) Stop() {
|
||||||
c.scheduler.Stop()
|
c.scheduler.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChainReader interface
|
||||||
|
|
||||||
func (c *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
func (c *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||||
return c.blocksAndHeaders.getBlock(ctx, hash)
|
return c.blocksAndHeaders.getBlock(ctx, hash)
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +207,18 @@ func (h *headSub) Err() <-chan error {
|
||||||
return h.errCh
|
return h.errCh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransactionReader interface
|
||||||
|
|
||||||
|
func (c *Client) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) {
|
||||||
|
return c.txAndReceipts.getTxByHash(ctx, txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||||
|
return c.txAndReceipts.getReceiptByTxHash(ctx, txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainStateReader interface {
|
||||||
|
|
||||||
func (c *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
|
func (c *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||||
proof, _, err := c.state.getProof(ctx, blockNumber, account, nil, false)
|
proof, _, err := c.state.getProof(ctx, blockNumber, account, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,22 @@ func (t *txAndReceipts) getTxByHash(ctx context.Context, txHash common.Hash) (tx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t.requestTxByHash(ctx, txHash)
|
tx, isPending, err = t.requestTxByHash(ctx, txHash)
|
||||||
|
if err == nil && !isPending {
|
||||||
|
receipt, err := t.requestReceiptByTxHash(ctx, txHash)
|
||||||
|
if err == ethereum.NotFound {
|
||||||
|
return tx, false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if head := t.canonicalChain.getHead(); head == nil ||
|
||||||
|
!receipt.BlockNumber.IsUint64() || head.BlockNumber() < receipt.BlockNumber.Uint64() {
|
||||||
|
// consider it pending if it's reported to be included higher than the light chain head
|
||||||
|
isPending = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *txAndReceipts) getReceiptByTxHash(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
func (t *txAndReceipts) getReceiptByTxHash(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||||
|
|
@ -81,8 +96,52 @@ func (t *txAndReceipts) getReceiptByTxHash(ctx context.Context, txHash common.Ha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t.requestReceiptByTxHash(ctx, txHash)
|
receipt, err := t.requestReceiptByTxHash(ctx, txHash)
|
||||||
//TODO validate position
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// check if it indeed belongs to the requested transaction
|
||||||
|
if receipt.TxHash != txHash {
|
||||||
|
return nil, errors.New("receipt references another transaction")
|
||||||
|
}
|
||||||
|
// check if its inclusion position is canonical
|
||||||
|
if !receipt.BlockNumber.IsUint64() {
|
||||||
|
return nil, errors.New("receipt references non-canonical block")
|
||||||
|
}
|
||||||
|
blockNumber := receipt.BlockNumber.Uint64()
|
||||||
|
if head := t.canonicalChain.getHead(); head == nil || head.BlockNumber() < blockNumber {
|
||||||
|
// consider it pending if it's reported to be included higher than the light chain head
|
||||||
|
return nil, ethereum.NotFound
|
||||||
|
}
|
||||||
|
canonicalHash, err := t.canonicalChain.getHash(ctx, blockNumber)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if receipt.BlockHash != canonicalHash {
|
||||||
|
return nil, errors.New("receipt references non-canonical block")
|
||||||
|
}
|
||||||
|
// check if it is the actual canonical receipt at the given position
|
||||||
|
receipts, err := t.getBlockReceipts(ctx, receipt.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if receipt.TransactionIndex >= uint(len(receipts)) {
|
||||||
|
return nil, errors.New("receipt references out-of-range transaction index")
|
||||||
|
}
|
||||||
|
// compare the JSON encoding of received and canonical versions
|
||||||
|
jsonReceived, err := json.Marshal(receipt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
jsonCanonical, err := json.Marshal(receipts[receipt.TransactionIndex])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(jsonReceived, jsonCanonical) {
|
||||||
|
return nil, errors.New("received and derived receipts do not match")
|
||||||
|
}
|
||||||
|
t.txPosCache.Add(receipt.TxHash, txInBlock{blockNumber: blockNumber, blockHash: receipt.BlockHash, index: receipt.TransactionIndex})
|
||||||
|
return receipt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *txAndReceipts) getBlockReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
func (t *txAndReceipts) getBlockReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
||||||
|
|
@ -186,7 +245,7 @@ func (t *txAndReceipts) requestBlockReceipts(ctx context.Context, blockHash comm
|
||||||
return types.Receipts(r), err
|
return types.Receipts(r), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *txAndReceipts) addBlockTxs(block *types.Block) {
|
func (t *txAndReceipts) cacheBlockTxPositions(block *types.Block) {
|
||||||
blockNumber, blockHash := block.NumberU64(), block.Hash()
|
blockNumber, blockHash := block.NumberU64(), block.Hash()
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
t.txPosCache.Add(tx.Hash(), txInBlock{blockNumber: blockNumber, blockHash: blockHash, index: uint(i)})
|
t.txPosCache.Add(tx.Hash(), txInBlock{blockNumber: blockNumber, blockHash: blockHash, index: uint(i)})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue