Skip to content

Commit 9fc677c

Browse files
islishudelightclient
authored andcommitted
ethclient: fix retrieval of pending block (ethereum#31504)
Since the block hash is not returned for pending blocks, ethclient cannot unmarshal into RPC block. This makes hash optional on rpc block and compute the hash locally for pending blocks to correctly key the tx sender cache. https://github.com/ethereum/go-ethereum/blob/a82303f4e3cedcebe31540a53dde4f24fc93da80/internal/ethapi/api.go#L500-L504 --------- Co-authored-by: lightclient <lightclient@protonmail.com>
1 parent 9fdc0eb commit 9fc677c

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

ethclient/ethclient.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
131131
}
132132

133133
type rpcBlock struct {
134-
Hash common.Hash `json:"hash"`
134+
Hash *common.Hash `json:"hash"`
135135
Transactions []rpcTransaction `json:"transactions"`
136136
UncleHashes []common.Hash `json:"uncles"`
137137
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
@@ -158,6 +158,12 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
158158
if err := json.Unmarshal(raw, &body); err != nil {
159159
return nil, err
160160
}
161+
// Pending blocks don't return a block hash, compute it for sender caching.
162+
if body.Hash == nil {
163+
tmp := head.Hash()
164+
body.Hash = &tmp
165+
}
166+
161167
// Quick-verify transaction and uncle lists. This mostly helps with debugging the server.
162168
if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 {
163169
return nil, errors.New("server returned non-empty uncle list but block header indicates no uncles")
@@ -199,7 +205,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
199205
txs := make([]*types.Transaction, len(body.Transactions))
200206
for i, tx := range body.Transactions {
201207
if tx.From != nil {
202-
setSenderFromServer(tx.tx, *tx.From, body.Hash)
208+
setSenderFromServer(tx.tx, *tx.From, *body.Hash)
203209
}
204210
txs[i] = tx.tx
205211
}

ethclient/ethclient_test.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,12 @@ func testTransactionInBlock(t *testing.T, client *rpc.Client) {
307307
if tx.Hash() != testTx2.Hash() {
308308
t.Fatalf("unexpected transaction: %v", tx)
309309
}
310+
311+
// Test pending block
312+
_, err = ec.BlockByNumber(context.Background(), big.NewInt(int64(rpc.PendingBlockNumber)))
313+
if err != nil {
314+
t.Fatalf("unexpected error: %v", err)
315+
}
310316
}
311317

312318
func testChainID(t *testing.T, client *rpc.Client) {
@@ -619,6 +625,21 @@ func testAtFunctions(t *testing.T, client *rpc.Client) {
619625
if gas != 21000 {
620626
t.Fatalf("unexpected gas limit: %v", gas)
621627
}
628+
629+
// Verify that sender address of pending transaction is saved in cache.
630+
pendingBlock, err := ec.BlockByNumber(context.Background(), big.NewInt(int64(rpc.PendingBlockNumber)))
631+
if err != nil {
632+
t.Fatalf("unexpected error: %v", err)
633+
}
634+
// No additional RPC should be required, ensure the server is not asked by
635+
// canceling the context.
636+
sender, err := ec.TransactionSender(newCanceledContext(), pendingBlock.Transactions()[0], pendingBlock.Hash(), 0)
637+
if err != nil {
638+
t.Fatal("unable to recover sender:", err)
639+
}
640+
if sender != testAddr {
641+
t.Fatal("wrong sender:", sender)
642+
}
622643
}
623644

624645
func testTransactionSender(t *testing.T, client *rpc.Client) {
@@ -640,10 +661,7 @@ func testTransactionSender(t *testing.T, client *rpc.Client) {
640661

641662
// The sender address is cached in tx1, so no additional RPC should be required in
642663
// TransactionSender. Ensure the server is not asked by canceling the context here.
643-
canceledCtx, cancel := context.WithCancel(context.Background())
644-
cancel()
645-
<-canceledCtx.Done() // Ensure the close of the Done channel
646-
sender1, err := ec.TransactionSender(canceledCtx, tx1, block2.Hash(), 0)
664+
sender1, err := ec.TransactionSender(newCanceledContext(), tx1, block2.Hash(), 0)
647665
if err != nil {
648666
t.Fatal(err)
649667
}
@@ -662,6 +680,13 @@ func testTransactionSender(t *testing.T, client *rpc.Client) {
662680
}
663681
}
664682

683+
func newCanceledContext() context.Context {
684+
ctx, cancel := context.WithCancel(context.Background())
685+
cancel()
686+
<-ctx.Done() // Ensure the close of the Done channel
687+
return ctx
688+
}
689+
665690
func sendTransaction(ec *ethclient.Client) error {
666691
chainID, err := ec.ChainID(context.Background())
667692
if err != nil {

0 commit comments

Comments
 (0)