forked from cerc-io/plugeth
		
	ethclient: fix tx sender cache miss detection (#23877)
This fixes a bug in TransactionSender where it would return the zero address for transactions where the sender address wasn't cached already. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
		
							parent
							
								
									fa96718512
								
							
						
					
					
						commit
						16341e0563
					
				| @ -233,6 +233,8 @@ func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, | ||||
| 	if err == nil { | ||||
| 		return sender, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// It was not found in cache, ask the server.
 | ||||
| 	var meta struct { | ||||
| 		Hash common.Hash | ||||
| 		From common.Address | ||||
|  | ||||
| @ -187,9 +187,34 @@ var ( | ||||
| 	testBalance = big.NewInt(2e15) | ||||
| ) | ||||
| 
 | ||||
| var genesis = &core.Genesis{ | ||||
| 	Config:    params.AllEthashProtocolChanges, | ||||
| 	Alloc:     core.GenesisAlloc{testAddr: {Balance: testBalance}}, | ||||
| 	ExtraData: []byte("test genesis"), | ||||
| 	Timestamp: 9000, | ||||
| 	BaseFee:   big.NewInt(params.InitialBaseFee), | ||||
| } | ||||
| 
 | ||||
| var testTx1 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{ | ||||
| 	Nonce:    0, | ||||
| 	Value:    big.NewInt(12), | ||||
| 	GasPrice: big.NewInt(params.InitialBaseFee), | ||||
| 	Gas:      params.TxGas, | ||||
| 	To:       &common.Address{2}, | ||||
| }) | ||||
| 
 | ||||
| var testTx2 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{ | ||||
| 	Nonce:    1, | ||||
| 	Value:    big.NewInt(8), | ||||
| 	GasPrice: big.NewInt(params.InitialBaseFee), | ||||
| 	Gas:      params.TxGas, | ||||
| 	To:       &common.Address{2}, | ||||
| }) | ||||
| 
 | ||||
| func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { | ||||
| 	// Generate test chain.
 | ||||
| 	genesis, blocks := generateTestChain() | ||||
| 	blocks := generateTestChain() | ||||
| 
 | ||||
| 	// Create node
 | ||||
| 	n, err := node.New(&node.Config{}) | ||||
| 	if err != nil { | ||||
| @ -212,25 +237,22 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { | ||||
| 	return n, blocks | ||||
| } | ||||
| 
 | ||||
| func generateTestChain() (*core.Genesis, []*types.Block) { | ||||
| func generateTestChain() []*types.Block { | ||||
| 	db := rawdb.NewMemoryDatabase() | ||||
| 	config := params.AllEthashProtocolChanges | ||||
| 	genesis := &core.Genesis{ | ||||
| 		Config:    config, | ||||
| 		Alloc:     core.GenesisAlloc{testAddr: {Balance: testBalance}}, | ||||
| 		ExtraData: []byte("test genesis"), | ||||
| 		Timestamp: 9000, | ||||
| 		BaseFee:   big.NewInt(params.InitialBaseFee), | ||||
| 	} | ||||
| 	generate := func(i int, g *core.BlockGen) { | ||||
| 		g.OffsetTime(5) | ||||
| 		g.SetExtra([]byte("test")) | ||||
| 		if i == 1 { | ||||
| 			// Test transactions are included in block #2.
 | ||||
| 			g.AddTx(testTx1) | ||||
| 			g.AddTx(testTx2) | ||||
| 		} | ||||
| 	} | ||||
| 	gblock := genesis.ToBlock(db) | ||||
| 	engine := ethash.NewFaker() | ||||
| 	blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) | ||||
| 	blocks, _ := core.GenerateChain(genesis.Config, gblock, engine, db, 2, generate) | ||||
| 	blocks = append([]*types.Block{gblock}, blocks...) | ||||
| 	return genesis, blocks | ||||
| 	return blocks | ||||
| } | ||||
| 
 | ||||
| func TestEthClient(t *testing.T) { | ||||
| @ -242,30 +264,33 @@ func TestEthClient(t *testing.T) { | ||||
| 	tests := map[string]struct { | ||||
| 		test func(t *testing.T) | ||||
| 	}{ | ||||
| 		"TestHeader": { | ||||
| 		"Header": { | ||||
| 			func(t *testing.T) { testHeader(t, chain, client) }, | ||||
| 		}, | ||||
| 		"TestBalanceAt": { | ||||
| 		"BalanceAt": { | ||||
| 			func(t *testing.T) { testBalanceAt(t, client) }, | ||||
| 		}, | ||||
| 		"TestTxInBlockInterrupted": { | ||||
| 		"TxInBlockInterrupted": { | ||||
| 			func(t *testing.T) { testTransactionInBlockInterrupted(t, client) }, | ||||
| 		}, | ||||
| 		"TestChainID": { | ||||
| 		"ChainID": { | ||||
| 			func(t *testing.T) { testChainID(t, client) }, | ||||
| 		}, | ||||
| 		"TestGetBlock": { | ||||
| 		"GetBlock": { | ||||
| 			func(t *testing.T) { testGetBlock(t, client) }, | ||||
| 		}, | ||||
| 		"TestStatusFunctions": { | ||||
| 		"StatusFunctions": { | ||||
| 			func(t *testing.T) { testStatusFunctions(t, client) }, | ||||
| 		}, | ||||
| 		"TestCallContract": { | ||||
| 		"CallContract": { | ||||
| 			func(t *testing.T) { testCallContract(t, client) }, | ||||
| 		}, | ||||
| 		"TestAtFunctions": { | ||||
| 		"AtFunctions": { | ||||
| 			func(t *testing.T) { testAtFunctions(t, client) }, | ||||
| 		}, | ||||
| 		"TransactionSender": { | ||||
| 			func(t *testing.T) { testTransactionSender(t, client) }, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	t.Parallel() | ||||
| @ -321,6 +346,11 @@ func testBalanceAt(t *testing.T, client *rpc.Client) { | ||||
| 		want    *big.Int | ||||
| 		wantErr error | ||||
| 	}{ | ||||
| 		"valid_account_genesis": { | ||||
| 			account: testAddr, | ||||
| 			block:   big.NewInt(0), | ||||
| 			want:    testBalance, | ||||
| 		}, | ||||
| 		"valid_account": { | ||||
| 			account: testAddr, | ||||
| 			block:   big.NewInt(1), | ||||
| @ -358,23 +388,25 @@ func testBalanceAt(t *testing.T, client *rpc.Client) { | ||||
| func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { | ||||
| 	ec := NewClient(client) | ||||
| 
 | ||||
| 	// Get current block by number
 | ||||
| 	// Get current block by number.
 | ||||
| 	block, err := ec.BlockByNumber(context.Background(), nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error: %v", err) | ||||
| 	} | ||||
| 	// Test tx in block interupted
 | ||||
| 
 | ||||
| 	// Test tx in block interupted.
 | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	cancel() | ||||
| 	tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1) | ||||
| 	tx, err := ec.TransactionInBlock(ctx, block.Hash(), 0) | ||||
| 	if tx != nil { | ||||
| 		t.Fatal("transaction should be nil") | ||||
| 	} | ||||
| 	if err == nil || err == ethereum.NotFound { | ||||
| 		t.Fatal("error should not be nil/notfound") | ||||
| 	} | ||||
| 	// Test tx in block not found
 | ||||
| 	if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 1); err != ethereum.NotFound { | ||||
| 
 | ||||
| 	// Test tx in block not found.
 | ||||
| 	if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != ethereum.NotFound { | ||||
| 		t.Fatal("error should be ethereum.NotFound") | ||||
| 	} | ||||
| } | ||||
| @ -392,12 +424,13 @@ func testChainID(t *testing.T, client *rpc.Client) { | ||||
| 
 | ||||
| func testGetBlock(t *testing.T, client *rpc.Client) { | ||||
| 	ec := NewClient(client) | ||||
| 
 | ||||
| 	// Get current block number
 | ||||
| 	blockNumber, err := ec.BlockNumber(context.Background()) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error: %v", err) | ||||
| 	} | ||||
| 	if blockNumber != 1 { | ||||
| 	if blockNumber != 2 { | ||||
| 		t.Fatalf("BlockNumber returned wrong number: %d", blockNumber) | ||||
| 	} | ||||
| 	// Get current block by number
 | ||||
| @ -445,6 +478,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { | ||||
| 	if progress != nil { | ||||
| 		t.Fatalf("unexpected progress: %v", progress) | ||||
| 	} | ||||
| 
 | ||||
| 	// NetworkID
 | ||||
| 	networkID, err := ec.NetworkID(context.Background()) | ||||
| 	if err != nil { | ||||
| @ -453,20 +487,22 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { | ||||
| 	if networkID.Cmp(big.NewInt(0)) != 0 { | ||||
| 		t.Fatalf("unexpected networkID: %v", networkID) | ||||
| 	} | ||||
| 	// SuggestGasPrice (should suggest 1 Gwei)
 | ||||
| 
 | ||||
| 	// SuggestGasPrice
 | ||||
| 	gasPrice, err := ec.SuggestGasPrice(context.Background()) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error: %v", err) | ||||
| 	} | ||||
| 	if gasPrice.Cmp(big.NewInt(1875000000)) != 0 { // 1 gwei tip + 0.875 basefee after a 1 gwei fee empty block
 | ||||
| 	if gasPrice.Cmp(big.NewInt(1000000000)) != 0 { | ||||
| 		t.Fatalf("unexpected gas price: %v", gasPrice) | ||||
| 	} | ||||
| 	// SuggestGasTipCap (should suggest 1 Gwei)
 | ||||
| 
 | ||||
| 	// SuggestGasTipCap
 | ||||
| 	gasTipCap, err := ec.SuggestGasTipCap(context.Background()) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error: %v", err) | ||||
| 	} | ||||
| 	if gasTipCap.Cmp(big.NewInt(1000000000)) != 0 { | ||||
| 	if gasTipCap.Cmp(big.NewInt(234375000)) != 0 { | ||||
| 		t.Fatalf("unexpected gas tip cap: %v", gasTipCap) | ||||
| 	} | ||||
| } | ||||
| @ -500,9 +536,11 @@ func testCallContract(t *testing.T, client *rpc.Client) { | ||||
| 
 | ||||
| func testAtFunctions(t *testing.T, client *rpc.Client) { | ||||
| 	ec := NewClient(client) | ||||
| 
 | ||||
| 	// send a transaction for some interesting pending status
 | ||||
| 	sendTransaction(ec) | ||||
| 	time.Sleep(100 * time.Millisecond) | ||||
| 
 | ||||
| 	// Check pending transaction count
 | ||||
| 	pending, err := ec.PendingTransactionCount(context.Background()) | ||||
| 	if err != nil { | ||||
| @ -561,23 +599,66 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func testTransactionSender(t *testing.T, client *rpc.Client) { | ||||
| 	ec := NewClient(client) | ||||
| 	ctx := context.Background() | ||||
| 
 | ||||
| 	// Retrieve testTx1 via RPC.
 | ||||
| 	block2, err := ec.HeaderByNumber(ctx, big.NewInt(2)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("can't get block 1:", err) | ||||
| 	} | ||||
| 	tx1, err := ec.TransactionInBlock(ctx, block2.Hash(), 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("can't get tx:", err) | ||||
| 	} | ||||
| 	if tx1.Hash() != testTx1.Hash() { | ||||
| 		t.Fatalf("wrong tx hash %v, want %v", tx1.Hash(), testTx1.Hash()) | ||||
| 	} | ||||
| 
 | ||||
| 	// The sender address is cached in tx1, so no additional RPC should be required in
 | ||||
| 	// TransactionSender. Ensure the server is not asked by canceling the context here.
 | ||||
| 	canceledCtx, cancel := context.WithCancel(context.Background()) | ||||
| 	cancel() | ||||
| 	sender1, err := ec.TransactionSender(canceledCtx, tx1, block2.Hash(), 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if sender1 != testAddr { | ||||
| 		t.Fatal("wrong sender:", sender1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Now try to get the sender of testTx2, which was not fetched through RPC.
 | ||||
| 	// TransactionSender should query the server here.
 | ||||
| 	sender2, err := ec.TransactionSender(ctx, testTx2, block2.Hash(), 1) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if sender2 != testAddr { | ||||
| 		t.Fatal("wrong sender:", sender2) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func sendTransaction(ec *Client) error { | ||||
| 	// Retrieve chainID
 | ||||
| 	chainID, err := ec.ChainID(context.Background()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// Create transaction
 | ||||
| 	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(params.InitialBaseFee), nil) | ||||
| 	nonce, err := ec.PendingNonceAt(context.Background(), testAddr) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	signer := types.LatestSignerForChainID(chainID) | ||||
| 	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) | ||||
| 	tx, err := types.SignNewTx(testKey, signer, &types.LegacyTx{ | ||||
| 		Nonce:    nonce, | ||||
| 		To:       &common.Address{2}, | ||||
| 		Value:    big.NewInt(1), | ||||
| 		Gas:      22000, | ||||
| 		GasPrice: big.NewInt(params.InitialBaseFee), | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	signedTx, err := tx.WithSignature(signer, signature) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// Send transaction
 | ||||
| 	return ec.SendTransaction(context.Background(), signedTx) | ||||
| 	return ec.SendTransaction(context.Background(), tx) | ||||
| } | ||||
|  | ||||
| @ -45,7 +45,7 @@ func (s *senderFromServer) Equal(other types.Signer) bool { | ||||
| } | ||||
| 
 | ||||
| func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error) { | ||||
| 	if s.blockhash == (common.Hash{}) { | ||||
| 	if s.addr == (common.Address{}) { | ||||
| 		return common.Address{}, errNotCached | ||||
| 	} | ||||
| 	return s.addr, nil | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user