From c57df9ca286aff90672044dc199014fba59bed11 Mon Sep 17 00:00:00 2001
From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com>
Date: Thu, 11 Nov 2021 15:04:06 +0100
Subject: [PATCH] core/rawdb: add slow path for getting legacy logs (#23879)

* eth/tracers: add slow path for getting legacy logs

* core/rawdb: fix test
---
 core/rawdb/accessors_chain.go      | 24 ++++++++++++++++++++++--
 core/rawdb/accessors_chain_test.go |  2 +-
 eth/api_backend.go                 |  2 +-
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go
index 7f26c3a42068..4028191b760c 100644
--- a/core/rawdb/accessors_chain.go
+++ b/core/rawdb/accessors_chain.go
@@ -669,7 +669,7 @@ func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, t
 // ReadLogs retrieves the logs for all transactions in a block. The log fields
 // are populated with metadata. In case the receipts or the block body
 // are not found, a nil is returned.
-func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
+func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log {
 	// Retrieve the flattened receipt slice
 	data := ReadReceiptsRLP(db, hash, number)
 	if len(data) == 0 {
@@ -677,7 +677,12 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
 	}
 	receipts := []*receiptLogs{}
 	if err := rlp.DecodeBytes(data, &receipts); err != nil {
-		log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
+		// Receipts might be in the legacy format, try decoding that.
+		// TODO: to be removed after users migrated
+		if logs := readLegacyLogs(db, hash, number, config); logs != nil {
+			return logs
+		}
+		log.Error("Invalid receipt array RLP", "hash", "err", err)
 		return nil
 	}
 
@@ -697,6 +702,21 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
 	return logs
 }
 
+// readLegacyLogs is a temporary workaround for when trying to read logs
+// from a block which has its receipt stored in the legacy format. It'll
+// be removed after users have migrated their freezer databases.
+func readLegacyLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log {
+	receipts := ReadReceipts(db, hash, number, config)
+	if receipts == nil {
+		return nil
+	}
+	logs := make([][]*types.Log, len(receipts))
+	for i, receipt := range receipts {
+		logs[i] = receipt.Logs
+	}
+	return logs
+}
+
 // ReadBlock retrieves an entire block corresponding to the hash, assembling it
 // back from the stored header and body. If either the header or body could not
 // be retrieved nil is returned.
diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go
index 4b173c55eeb0..50b0d53902dd 100644
--- a/core/rawdb/accessors_chain_test.go
+++ b/core/rawdb/accessors_chain_test.go
@@ -744,7 +744,7 @@ func TestReadLogs(t *testing.T) {
 	// Insert the receipt slice into the database and check presence
 	WriteReceipts(db, hash, 0, receipts)
 
-	logs := ReadLogs(db, hash, 0)
+	logs := ReadLogs(db, hash, 0, params.TestChainConfig)
 	if len(logs) == 0 {
 		t.Fatalf("no logs returned")
 	}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index a0704876a387..6a19fb36ac79 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -187,7 +187,7 @@ func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*typ
 	if number == nil {
 		return nil, errors.New("failed to get block number from hash")
 	}
-	logs := rawdb.ReadLogs(db, hash, *number)
+	logs := rawdb.ReadLogs(db, hash, *number, b.eth.blockchain.Config())
 	if logs == nil {
 		return nil, errors.New("failed to get logs for block")
 	}