From 30708baafd066e427c550adcaac32fc86d122a2d Mon Sep 17 00:00:00 2001
From: Jaynti Kanani <jdkanani@gmail.com>
Date: Mon, 26 Oct 2020 15:43:07 +0530
Subject: [PATCH] new: add bor block tx/receipt/logs as normal entities

---
 accounts/abi/bind/backends/bor_simulated.go |   2 +-
 core/blockchain.go                          |   7 +-
 core/bor_blockchain.go                      |   4 +-
 core/rawdb/accessors_chain.go               |   2 +-
 core/rawdb/bor_receipt.go                   |  97 ++++++++++++--
 core/types/bor_receipt.go                   | 136 +++++++-------------
 eth/api_tracer.go                           |  10 ++
 eth/bor_api_backend.go                      |   8 +-
 eth/filters/api.go                          |  15 ++-
 eth/filters/bor_filter.go                   |   9 +-
 eth/filters/bor_filter_system_test.go       |   2 +-
 eth/filters/filter.go                       |   2 +-
 ethclient/bor_ethclient.go                  |   4 +-
 internal/ethapi/api.go                      |  63 +++++++--
 internal/ethapi/backend.go                  |   3 +-
 internal/ethapi/bor_api.go                  |  26 +++-
 les/api_backend.go                          |   6 +-
 17 files changed, 268 insertions(+), 128 deletions(-)

diff --git a/accounts/abi/bind/backends/bor_simulated.go b/accounts/abi/bind/backends/bor_simulated.go
index 3f5480d6a..ef5a7202c 100644
--- a/accounts/abi/bind/backends/bor_simulated.go
+++ b/accounts/abi/bind/backends/bor_simulated.go
@@ -8,7 +8,7 @@ import (
 	"github.com/maticnetwork/bor/core/types"
 )
 
-func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
+func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
 	number := rawdb.ReadHeaderNumber(fb.db, hash)
 	if number == nil {
 		return nil, nil
diff --git a/core/blockchain.go b/core/blockchain.go
index 2fd91de3a..bb9c13017 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -497,6 +497,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
 			// removed in the hc.SetHead function.
 			rawdb.DeleteBody(db, hash, num)
 			rawdb.DeleteReceipts(db, hash, num)
+			rawdb.DeleteBorReceipt(db, hash, num)
 		}
 		// Todo(rjl493456442) txlookup, bloombits, etc
 	}
@@ -509,6 +510,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
 	bc.blockCache.Purge()
 	bc.txLookupCache.Purge()
 	bc.futureBlocks.Purge()
+	bc.borReceiptsCache.Purge()
 
 	return bc.loadLastState()
 }
@@ -1460,8 +1462,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
 		})
 
 		if len(blockLogs) > len(logs) {
-			rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.BorReceiptForStorage{
-				Logs: blockLogs[len(logs):], // get state-sync logs from `state.Logs()`
+			rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{
+				Status: types.ReceiptStatusSuccessful, // make receipt status successful
+				Logs:   blockLogs[len(logs):],         // get state-sync logs from `state.Logs()`
 			})
 		}
 	}
diff --git a/core/bor_blockchain.go b/core/bor_blockchain.go
index 21e5b73fb..1fe518c48 100644
--- a/core/bor_blockchain.go
+++ b/core/bor_blockchain.go
@@ -7,9 +7,9 @@ import (
 )
 
 // GetBorReceiptByHash retrieves the bor block receipt in a given block.
-func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.BorReceipt {
+func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.Receipt {
 	if receipt, ok := bc.borReceiptsCache.Get(hash); ok {
-		return receipt.(*types.BorReceipt)
+		return receipt.(*types.Receipt)
 	}
 
 	// read header from hash
diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go
index d863e2408..f0a964f0e 100644
--- a/core/rawdb/accessors_chain.go
+++ b/core/rawdb/accessors_chain.go
@@ -596,7 +596,7 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
 }
 
 // WriteAncientBlock writes entire block data into ancient store and returns the total written size.
-func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.BorReceipt) int {
+func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.Receipt) int {
 	// Encode all block components to RLP format.
 	headerBlob, err := rlp.EncodeToBytes(block.Header())
 	if err != nil {
diff --git a/core/rawdb/bor_receipt.go b/core/rawdb/bor_receipt.go
index f5fed7432..8a58d2050 100644
--- a/core/rawdb/bor_receipt.go
+++ b/core/rawdb/bor_receipt.go
@@ -1,6 +1,8 @@
 package rawdb
 
 import (
+	"math/big"
+
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/ethdb"
@@ -9,15 +11,19 @@ import (
 )
 
 var (
-	borReceiptPrefix = []byte("bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt
+	// bor receipt key
+	borReceiptKey = types.BorReceiptKey
+
+	// borTxLookupPrefix + hash -> transaction/receipt lookup metadata
+	borTxLookupPrefix = []byte("matic-bor-tx-lookup-")
 
 	// freezerBorReceiptTable indicates the name of the freezer bor receipts table.
-	freezerBorReceiptTable = "bor-receipts"
+	freezerBorReceiptTable = "matic-bor-receipts"
 )
 
-// borReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash
-func borReceiptKey(number uint64, hash common.Hash) []byte {
-	return append(append(borReceiptPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
+// borTxLookupKey = borTxLookupPrefix + hash
+func borTxLookupKey(hash common.Hash) []byte {
+	return append(borTxLookupPrefix, hash.Bytes()...)
 }
 
 // HasBorReceipt verifies the existence of all block receipt belonging
@@ -68,7 +74,7 @@ func ReadBorReceiptRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.Raw
 // ReadRawBorReceipt retrieves the block receipt belonging to a block.
 // The receipt metadata fields are not guaranteed to be populated, so they
 // should not be used. Use ReadBorReceipt instead if the metadata is needed.
-func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt {
+func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt {
 	// Retrieve the flattened receipt slice
 	data := ReadBorReceiptRLP(db, hash, number)
 	if data == nil || len(data) == 0 {
@@ -76,32 +82,38 @@ func ReadRawBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.
 	}
 
 	// Convert the receipts from their storage form to their internal representation
-	var storageReceipt types.BorReceiptForStorage
+	var storageReceipt types.ReceiptForStorage
 	if err := rlp.DecodeBytes(data, &storageReceipt); err != nil {
 		log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
 		return nil
 	}
 
-	return (*types.BorReceipt)(&storageReceipt)
+	return (*types.Receipt)(&storageReceipt)
 }
 
 // ReadBorReceipt retrieves all the bor block receipts belonging to a block, including
 // its correspoinding metadata fields. If it is unable to populate these metadata
 // fields then nil is returned.
-func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.BorReceipt {
+func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Receipt {
 	// We're deriving many fields from the block body, retrieve beside the receipt
 	borReceipt := ReadRawBorReceipt(db, hash, number)
 	if borReceipt == nil {
 		return nil
 	}
 
+	// We're deriving many fields from the block body, retrieve beside the receipt
+	receipts := ReadRawReceipts(db, hash, number)
+	if receipts == nil {
+		return nil
+	}
+
 	body := ReadBody(db, hash, number)
 	if body == nil {
 		log.Error("Missing body but have bor receipt", "hash", hash, "number", number)
 		return nil
 	}
 
-	if err := borReceipt.DeriveFields(hash, number); err != nil {
+	if err := types.DeriveFieldsForBorReceipt(borReceipt, hash, number, receipts); err != nil {
 		log.Error("Failed to derive bor receipt fields", "hash", hash, "number", number, "err", err)
 		return nil
 	}
@@ -109,7 +121,7 @@ func ReadBorReceipt(db ethdb.Reader, hash common.Hash, number uint64) *types.Bor
 }
 
 // WriteBorReceipt stores all the bor receipt belonging to a block.
-func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.BorReceiptForStorage) {
+func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, borReceipt *types.ReceiptForStorage) {
 	// Convert the bor receipt into their storage form and serialize them
 	bytes, err := rlp.EncodeToBytes(borReceipt)
 	if err != nil {
@@ -117,14 +129,73 @@ func WriteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64, b
 	}
 
 	// Store the flattened receipt slice
-	if err := db.Put(borReceiptKey(number, hash), bytes); err != nil {
+	key := borReceiptKey(number, hash)
+	if err := db.Put(key, bytes); err != nil {
 		log.Crit("Failed to store bor receipt", "err", err)
 	}
+
+	// Write bor tx reverse lookup
+	WriteBorTxLookupEntry(db, types.GetDerivedBorTxHash(key), big.NewInt(0).SetUint64(number))
 }
 
 // DeleteBorReceipt removes receipt data associated with a block hash.
 func DeleteBorReceipt(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
-	if err := db.Delete(borReceiptKey(number, hash)); err != nil {
+	key := borReceiptKey(number, hash)
+
+	if err := db.Delete(key); err != nil {
 		log.Crit("Failed to delete bor receipt", "err", err)
 	}
 }
+
+// ReadBorTransaction retrieves a specific bor (fake) transaction, along with
+// its added positional metadata.
+func ReadBorTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
+	blockNumber := ReadBorTxLookupEntry(db, hash)
+	if blockNumber == nil {
+		return nil, common.Hash{}, 0, 0
+	}
+
+	blockHash := ReadCanonicalHash(db, *blockNumber)
+	if blockHash == (common.Hash{}) {
+		return nil, common.Hash{}, 0, 0
+	}
+
+	body := ReadBody(db, blockHash, *blockNumber)
+	if body == nil {
+		log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash)
+		return nil, common.Hash{}, 0, 0
+	}
+
+	// fetch receipt and return it
+	return types.NewBorTransaction(), blockHash, *blockNumber, uint64(len(body.Transactions))
+}
+
+//
+// Indexes for reverse lookup
+//
+
+// ReadBorTxLookupEntry retrieves the positional metadata associated with a transaction
+// hash to allow retrieving the bor transaction or bor receipt by hash.
+func ReadBorTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 {
+	data, _ := db.Get(borTxLookupKey(hash))
+	if len(data) == 0 {
+		return nil
+	}
+
+	number := new(big.Int).SetBytes(data).Uint64()
+	return &number
+}
+
+// WriteBorTxLookupEntry stores a positional metadata for bor transaction.
+func WriteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, number *big.Int) {
+	if err := db.Put(borTxLookupKey(hash), number.Bytes()); err != nil {
+		log.Crit("Failed to store bor transaction lookup entry", "err", err)
+	}
+}
+
+// DeleteBorTxLookupEntry removes bor transaction data associated with a hash.
+func DeleteBorTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) {
+	if err := db.Delete(borTxLookupKey(hash)); err != nil {
+		log.Crit("Failed to delete bor transaction lookup entry", "err", err)
+	}
+}
diff --git a/core/types/bor_receipt.go b/core/types/bor_receipt.go
index d88a3baa0..e00739f09 100644
--- a/core/types/bor_receipt.go
+++ b/core/types/bor_receipt.go
@@ -1,109 +1,73 @@
 package types
 
 import (
-	"io"
+	"encoding/binary"
 	"math/big"
+	"sort"
 
 	"github.com/maticnetwork/bor/common"
-	"github.com/maticnetwork/bor/rlp"
+	"github.com/maticnetwork/bor/crypto"
 )
 
-// BorReceipt represents the results of a block state syncs
-type BorReceipt struct {
-	// Consensus fields
-	Bloom Bloom  `json:"logsBloom"         gencodec:"required"`
-	Logs  []*Log `json:"logs"              gencodec:"required"`
+var (
+	borReceiptPrefix = []byte("matic-bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt
 
-	// Inclusion information: These fields provide information about the inclusion of the
-	// transaction corresponding to this receipt.
-	BlockHash   common.Hash `json:"blockHash,omitempty"`
-	BlockNumber *big.Int    `json:"blockNumber,omitempty"`
-}
-
-// borReceiptRLP is the consensus encoding of a block receipt.
-type borReceiptRLP struct {
-	Bloom Bloom
-	Logs  []*Log
-}
-
-// storedBorReceiptRLP is the storage encoding of a block receipt.
-type storedBorReceiptRLP struct {
-	Logs []*LogForStorage
-}
-
-// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a block receipt
-// into an RLP stream. If no post state is present, byzantium fork is assumed.
-func (r *BorReceipt) EncodeRLP(w io.Writer) error {
-	return rlp.Encode(w, &borReceiptRLP{r.Bloom, r.Logs})
-}
+	// SystemAddress address for system sender
+	SystemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE")
+)
 
-// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a block receipt
-// from an RLP stream.
-func (r *BorReceipt) DecodeRLP(s *rlp.Stream) error {
-	var dec receiptRLP
-	if err := s.Decode(&dec); err != nil {
-		return err
-	}
-	r.Bloom, r.Logs = dec.Bloom, dec.Logs
-	return nil
+// BorReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash
+func BorReceiptKey(number uint64, hash common.Hash) []byte {
+	enc := make([]byte, 8)
+	binary.BigEndian.PutUint64(enc, number)
+	return append(append(borReceiptPrefix, enc...), hash.Bytes()...)
 }
 
-// BorReceiptForStorage is a wrapper around a Bor Receipt that flattens and parses the
-// entire content of a receipt, as opposed to only the consensus fields originally.
-type BorReceiptForStorage BorReceipt
-
-// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
-// into an RLP stream.
-func (r *BorReceiptForStorage) EncodeRLP(w io.Writer) error {
-	enc := &storedBorReceiptRLP{
-		Logs: make([]*LogForStorage, len(r.Logs)),
-	}
-
-	for i, log := range r.Logs {
-		enc.Logs[i] = (*LogForStorage)(log)
-	}
-	return rlp.Encode(w, enc)
+// GetDerivedBorTxHash get derived tx hash from receipt key
+func GetDerivedBorTxHash(receiptKey []byte) common.Hash {
+	return common.BytesToHash(crypto.Keccak256(receiptKey))
 }
 
-// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
-// fields of a receipt from an RLP stream.
-func (r *BorReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
-	// Retrieve the entire receipt blob as we need to try multiple decoders
-	blob, err := s.Raw()
-	if err != nil {
-		return err
-	}
-
-	return decodeStoredBorReceiptRLP(r, blob)
+// NewBorTransaction create new bor transaction for bor receipt
+func NewBorTransaction() *Transaction {
+	return NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), make([]byte, 0))
 }
 
-func decodeStoredBorReceiptRLP(r *BorReceiptForStorage, blob []byte) error {
-	var stored storedBorReceiptRLP
-	if err := rlp.DecodeBytes(blob, &stored); err != nil {
-		return err
+// DeriveFieldsForBorReceipt fills the receipts with their computed fields based on consensus
+// data and contextual infos like containing block and transactions.
+func DeriveFieldsForBorReceipt(receipt *Receipt, hash common.Hash, number uint64, receipts Receipts) error {
+	// get derived tx hash
+	txHash := GetDerivedBorTxHash(BorReceiptKey(number, hash))
+	txIndex := uint(len(receipts))
+
+	// set tx hash and tx index
+	receipt.TxHash = txHash
+	receipt.TransactionIndex = txIndex
+	receipt.BlockHash = hash
+	receipt.BlockNumber = big.NewInt(0).SetUint64(number)
+
+	logIndex := 0
+	for i := 0; i < len(receipts); i++ {
+		logIndex += len(receipts[i].Logs)
 	}
 
-	r.Logs = make([]*Log, len(stored.Logs))
-	for i, log := range stored.Logs {
-		r.Logs[i] = (*Log)(log)
+	// The derived log fields can simply be set from the block and transaction
+	for j := 0; j < len(receipt.Logs); j++ {
+		receipt.Logs[j].BlockNumber = number
+		receipt.Logs[j].BlockHash = hash
+		receipt.Logs[j].TxHash = txHash
+		receipt.Logs[j].TxIndex = txIndex
+		receipt.Logs[j].Index = uint(logIndex)
+		logIndex++
 	}
-	r.Bloom = BytesToBloom(LogsBloom(r.Logs).Bytes())
-
 	return nil
 }
 
-// DeriveFields fills the receipts with their computed fields based on consensus
-// data and contextual infos like containing block and transactions.
-func (r *BorReceipt) DeriveFields(hash common.Hash, number uint64) error {
-	// txHash := common.BytesToHash(crypto.Keccak256(append([]byte("bor-receipt-"), hash.Bytes()...)))
-
-	// The derived log fields can simply be set from the block and transaction
-	for j := 0; j < len(r.Logs); j++ {
-		r.Logs[j].BlockNumber = number
-		r.Logs[j].BlockHash = hash
-		// r.Logs[j].TxHash = txHash
-		r.Logs[j].TxIndex = uint(0)
-		r.Logs[j].Index = uint(j)
-	}
-	return nil
+// MergeBorLogs merges receipt logs and block receipt logs
+func MergeBorLogs(logs []*Log, borLogs []*Log) []*Log {
+	result := append(logs, borLogs...)
+	sort.SliceStable(result, func(i int, j int) bool {
+		return (result[i].BlockNumber*100000 + uint64(result[i].Index)) < (result[j].BlockNumber*100000 + uint64(result[j].Index))
+	})
+	return result
 }
diff --git a/eth/api_tracer.go b/eth/api_tracer.go
index d91e81e9a..d48f68092 100644
--- a/eth/api_tracer.go
+++ b/eth/api_tracer.go
@@ -704,6 +704,16 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
 func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
 	// Retrieve the transaction and assemble its EVM context
 	tx, blockHash, _, index := rawdb.ReadTransaction(api.eth.ChainDb(), hash)
+	if tx == nil {
+		// For BorTransaction, there will be no trace available
+		tx, _, _, _ = rawdb.ReadBorTransaction(api.eth.ChainDb(), hash)
+		if tx != nil {
+			return &ethapi.ExecutionResult{
+				StructLogs: make([]ethapi.StructLogRes, 0),
+			}, nil
+		}
+	}
+
 	if tx == nil {
 		return nil, fmt.Errorf("transaction %#x not found", hash)
 	}
diff --git a/eth/bor_api_backend.go b/eth/bor_api_backend.go
index 5a13ea1a6..497a75094 100644
--- a/eth/bor_api_backend.go
+++ b/eth/bor_api_backend.go
@@ -6,6 +6,7 @@ import (
 	ethereum "github.com/maticnetwork/bor"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus/bor"
+	"github.com/maticnetwork/bor/core/rawdb"
 	"github.com/maticnetwork/bor/core/types"
 )
 
@@ -24,7 +25,7 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
 	return root, nil
 }
 
-func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
+func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
 	receipt := b.eth.blockchain.GetBorReceiptByHash(hash)
 	if receipt == nil {
 		return nil, ethereum.NotFound
@@ -40,3 +41,8 @@ func (b *EthAPIBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) (
 	}
 	return receipt.Logs, nil
 }
+
+func (b *EthAPIBackend) GetBorBlockTransaction(ctx context.Context, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
+	tx, blockHash, blockNumber, index := rawdb.ReadBorTransaction(b.eth.ChainDb(), hash)
+	return tx, blockHash, blockNumber, index, nil
+}
diff --git a/eth/filters/api.go b/eth/filters/api.go
index 66aa2d436..5c53e4139 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -357,9 +357,12 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
 // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
 func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) {
 	var filter *Filter
+	var borLogsFilter *BorBlockLogsFilter
 	if crit.BlockHash != nil {
 		// Block filter requested, construct a single-shot filter
 		filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
+		// Block bor filter
+		borLogsFilter = NewBorBlockLogsFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
 	} else {
 		// Convert the RPC block numbers into internal representations
 		begin := rpc.LatestBlockNumber.Int64()
@@ -372,13 +375,23 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
 		}
 		// Construct the range filter
 		filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
+		// Block bor filter
+		borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
 	}
+
 	// Run the filter and return all the logs
 	logs, err := filter.Logs(ctx)
 	if err != nil {
 		return nil, err
 	}
-	return returnLogs(logs), err
+	// Run the filter and return all the logs
+	borBlockLogs, err := borLogsFilter.Logs(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	// merge bor block logs and receipt logs and return it
+	return returnLogs(types.MergeBorLogs(logs, borBlockLogs)), err
 }
 
 // UninstallFilter removes the filter with the given filter id.
diff --git a/eth/filters/bor_filter.go b/eth/filters/bor_filter.go
index 3d7e7a62f..7c0114635 100644
--- a/eth/filters/bor_filter.go
+++ b/eth/filters/bor_filter.go
@@ -97,7 +97,7 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) {
 	}
 
 	// adjust begin for sprint
-	f.begin = nextSprintEnd(f.begin)
+	f.begin = currentSprintEnd(f.begin)
 
 	end := f.end
 	if f.end == -1 {
@@ -136,15 +136,14 @@ func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*
 }
 
 // borBlockLogs returns the logs matching the filter criteria within a single block.
-func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.BorReceipt) (logs []*types.Log, err error) {
+func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.Receipt) (logs []*types.Log, err error) {
 	if bloomFilter(receipt.Bloom, f.addresses, f.topics) {
-		found := filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics)
-		logs = append(logs, found...)
+		logs = filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics)
 	}
 	return logs, nil
 }
 
-func nextSprintEnd(n int64) int64 {
+func currentSprintEnd(n int64) int64 {
 	m := n % 64
 	if m == 0 {
 		return n
diff --git a/eth/filters/bor_filter_system_test.go b/eth/filters/bor_filter_system_test.go
index d1c6fbd07..a6eebfa19 100644
--- a/eth/filters/bor_filter_system_test.go
+++ b/eth/filters/bor_filter_system_test.go
@@ -8,7 +8,7 @@ import (
 	"github.com/maticnetwork/bor/core/types"
 )
 
-func (b *testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
+func (b *testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
 	number := rawdb.ReadHeaderNumber(b.db, hash)
 	if number == nil {
 		return nil, nil
diff --git a/eth/filters/filter.go b/eth/filters/filter.go
index 1b91e06ed..d15f26356 100644
--- a/eth/filters/filter.go
+++ b/eth/filters/filter.go
@@ -36,7 +36,7 @@ type Backend interface {
 	HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
 	GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
 	GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
-	GetBorBlockReceipt(ctx context.Context, blockHash common.Hash) (*types.BorReceipt, error)
+	GetBorBlockReceipt(ctx context.Context, blockHash common.Hash) (*types.Receipt, error)
 	GetBorBlockLogs(ctx context.Context, blockHash common.Hash) ([]*types.Log, error)
 
 	SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
diff --git a/ethclient/bor_ethclient.go b/ethclient/bor_ethclient.go
index 4b1a01a26..dc19fb179 100644
--- a/ethclient/bor_ethclient.go
+++ b/ethclient/bor_ethclient.go
@@ -18,8 +18,8 @@ func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endB
 }
 
 // GetBorBlockReceipt returns bor block receipt
-func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
-	var r *types.BorReceipt
+func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
+	var r *types.Receipt
 	err := ec.c.CallContext(ctx, &r, "eth_getBorBlockReceipt", hash)
 	if err == nil {
 		if r == nil {
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 09a3e0c47..eb41aade3 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -661,6 +661,12 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B
 				response[field] = nil
 			}
 		}
+
+		// append marshalled bor transaction
+		if err == nil && response != nil {
+			response = s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx)
+		}
+
 		return response, err
 	}
 	return nil, err
@@ -671,7 +677,12 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B
 func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
 	block, err := s.b.BlockByHash(ctx, hash)
 	if block != nil {
-		return s.rpcMarshalBlock(block, true, fullTx)
+		response, err := s.rpcMarshalBlock(block, true, fullTx)
+		// append marshalled bor transaction
+		if err == nil && response != nil {
+			return s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx), err
+		}
+		return response, err
 	}
 	return nil, err
 }
@@ -1357,14 +1368,33 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
 
 // GetTransactionByHash returns the transaction for the given hash
 func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
+	borTx := false
+
 	// Try to return an already finalized transaction
 	tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
 	if err != nil {
 		return nil, err
 	}
+
+	// fetch bor block tx if necessary
+	if tx == nil {
+		if tx, blockHash, blockNumber, index, err = s.b.GetBorBlockTransaction(ctx, hash); err != nil {
+			return nil, err
+		}
+
+		borTx = true
+	}
+
 	if tx != nil {
-		return newRPCTransaction(tx, blockHash, blockNumber, index), nil
+		resultTx := newRPCTransaction(tx, blockHash, blockNumber, index)
+		if borTx {
+			// newRPCTransaction calculates hash based on RLP of the transaction data.
+			// In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash
+			resultTx.Hash = hash
+		}
+		return resultTx, nil
 	}
+
 	// No finalized transaction, try to retrieve it from the pool
 	if tx := s.b.GetPoolTransaction(hash); tx != nil {
 		return newRPCPendingTransaction(tx), nil
@@ -1393,18 +1423,33 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
 
 // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
 func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
+	borTx := false
+
 	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
 	if tx == nil {
-		return nil, nil
-	}
-	receipts, err := s.b.GetReceipts(ctx, blockHash)
-	if err != nil {
-		return nil, err
+		tx, blockHash, blockNumber, index = rawdb.ReadBorTransaction(s.b.ChainDb(), hash)
+		borTx = true
 	}
-	if len(receipts) <= int(index) {
+
+	if tx == nil {
 		return nil, nil
 	}
-	receipt := receipts[index]
+
+	var receipt *types.Receipt
+
+	if borTx {
+		// Fetch bor block receipt
+		receipt = rawdb.ReadBorReceipt(s.b.ChainDb(), blockHash, blockNumber)
+	} else {
+		receipts, err := s.b.GetReceipts(ctx, blockHash)
+		if err != nil {
+			return nil, err
+		}
+		if len(receipts) <= int(index) {
+			return nil, nil
+		}
+		receipt = receipts[index]
+	}
 
 	var signer types.Signer = types.FrontierSigner{}
 	if tx.Protected() {
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index a8a6c4b9e..fc4950623 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -68,8 +68,9 @@ type Backend interface {
 
 	// Bor API
 	GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error)
-	GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error)
+	GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error)
 	GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error)
+	GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
 
 	// Transaction pool API
 	SendTx(ctx context.Context, signedTx *types.Transaction) error
diff --git a/internal/ethapi/bor_api.go b/internal/ethapi/bor_api.go
index 3cf1347a4..624f6d70d 100644
--- a/internal/ethapi/bor_api.go
+++ b/internal/ethapi/bor_api.go
@@ -15,6 +15,30 @@ func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint6
 	return root, nil
 }
 
-func (s *PublicBlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
+func (s *PublicBlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
 	return s.b.GetBorBlockReceipt(ctx, hash)
 }
+
+//
+// Bor transaction utils
+//
+
+func (s *PublicBlockChainAPI) appendRPCMarshalBorTransaction(ctx context.Context, block *types.Block, fields map[string]interface{}, fullTx bool) map[string]interface{} {
+	if block != nil {
+		txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash()))
+		borTx, blockHash, blockNumber, txIndex, _ := s.b.GetBorBlockTransaction(ctx, txHash)
+		if borTx != nil {
+			formattedTxs := fields["transactions"].([]interface{})
+			if fullTx {
+				marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex)
+				// newRPCTransaction calculates hash based on RLP of the transaction data.
+				// In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash
+				marshalledTx.Hash = txHash
+				fields["transactions"] = append(formattedTxs, marshalledTx)
+			} else {
+				fields["transactions"] = append(formattedTxs, txHash)
+			}
+		}
+	}
+	return fields
+}
diff --git a/les/api_backend.go b/les/api_backend.go
index 1f0dc8abf..defe86ba2 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -288,10 +288,14 @@ func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
 	return "", errors.New("Not implemented")
 }
 
-func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) {
+func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
 	return nil, errors.New("Not implemented")
 }
 
 func (b *LesApiBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
 	return nil, errors.New("Not implemented")
 }
+
+func (b *LesApiBackend) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
+	return nil, common.Hash{}, 0, 0, errors.New("Not implemented")
+}
-- 
GitLab