From 15f24ff1896835e6ab908b0d17c1cc36b300c408 Mon Sep 17 00:00:00 2001
From: Dmitry Shulyak <yashulyak@gmail.com>
Date: Mon, 3 Jun 2019 18:52:02 +0300
Subject: [PATCH] ethclient: ensure tx json is not nil before accessing it
 (#19653)

TransactionInBlock crashed if json was nil and there was an error
because it tried to access fields `From` and `BlockHash` of the nil object.
---
 ethclient/ethclient.go      | 13 +++++++------
 ethclient/ethclient_test.go | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index f3163e19b..aedf2814a 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -241,12 +241,13 @@ func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (
 func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
 	var json *rpcTransaction
 	err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
-	if err == nil {
-		if json == nil {
-			return nil, ethereum.NotFound
-		} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
-			return nil, fmt.Errorf("server returned transaction without signature")
-		}
+	if err != nil {
+		return nil, err
+	}
+	if json == nil {
+		return nil, ethereum.NotFound
+	} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
+		return nil, fmt.Errorf("server returned transaction without signature")
 	}
 	if json.From != nil && json.BlockHash != nil {
 		setSenderFromServer(json.tx, *json.From, *json.BlockHash)
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index 74711bd39..2e464cd42 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -301,3 +301,21 @@ func TestBalanceAt(t *testing.T) {
 		})
 	}
 }
+
+func TestTransactionInBlockInterrupted(t *testing.T) {
+	backend, _ := newTestBackend(t)
+	client, _ := backend.Attach()
+	defer backend.Stop()
+	defer client.Close()
+
+	ec := NewClient(client)
+	ctx, cancel := context.WithCancel(context.Background())
+	cancel()
+	tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
+	if tx != nil {
+		t.Fatal("transaction should be nil")
+	}
+	if err == nil {
+		t.Fatal("error should not be nil")
+	}
+}
-- 
GitLab