Skip to content

Commit

Permalink
Merge pull request #5 from trinhdn2/optimize/receipt-storing
Browse files Browse the repository at this point in the history
Optimize/receipt storing
  • Loading branch information
trinhdn2 authored Jul 31, 2023
2 parents e29a6fe + 91bc3f9 commit 4056a32
Show file tree
Hide file tree
Showing 21 changed files with 355 additions and 94 deletions.
6 changes: 3 additions & 3 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (b *SimulatedBackend) ForEachStorageAt(ctx context.Context, contract common

// TransactionReceipt returns the receipt of a transaction.
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
receipt, _, _, _ := core.GetReceipt(b.database, txHash)
receipt, _, _, _ := core.GetReceipt(b.database, txHash, b.config)
return receipt, nil
}

Expand Down Expand Up @@ -500,11 +500,11 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
}

func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash), fb.bc.Config()), nil
}

func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash))
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash), fb.bc.Config())
if receipts == nil {
return nil, nil
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *t
block := chain.GetBlock(header.Hash(), i)
txs := block.Transactions()
if !chain.Config().IsTIPSigning(header.Number) {
receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i, chain.Config())
signData = c.CacheData(header, txs, receipts)
} else {
signData = c.CacheSigner(header.Hash(), txs)
Expand Down
4 changes: 2 additions & 2 deletions core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package core

import (
"crypto/ecdsa"
"github.com/tomochain/tomochain/core/rawdb"
"io/ioutil"
"math/big"
"os"
Expand All @@ -27,6 +26,7 @@ import (
"github.com/tomochain/tomochain/common"
"github.com/tomochain/tomochain/common/math"
"github.com/tomochain/tomochain/consensus/ethash"
"github.com/tomochain/tomochain/core/rawdb"
"github.com/tomochain/tomochain/core/types"
"github.com/tomochain/tomochain/core/vm"
"github.com/tomochain/tomochain/crypto"
Expand Down Expand Up @@ -294,7 +294,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if full {
hash := header.Hash()
GetBody(db, hash, n)
GetBlockReceipts(db, hash, n)
GetBlockReceipts(db, hash, n, chain.Config())
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {

// GetReceiptsByHash retrieves the receipts for all transactions in a given block.
func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
return GetBlockReceipts(bc.db, hash, GetBlockNumber(bc.db, hash))
return GetBlockReceipts(bc.db, hash, GetBlockNumber(bc.db, hash), bc.chainConfig)
}

// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors.
Expand Down Expand Up @@ -2120,7 +2120,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// These logs are later announced as deleted.
collectLogs = func(h common.Hash) {
// Coalesce logs and set 'Removed'.
receipts := GetBlockReceipts(bc.db, h, bc.hc.GetBlockNumber(h))
receipts := GetBlockReceipts(bc.db, h, bc.hc.GetBlockNumber(h), bc.chainConfig)
for _, receipt := range receipts {
for _, log := range receipt.Logs {
del := *log
Expand Down
11 changes: 6 additions & 5 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ package core

import (
"fmt"
"github.com/tomochain/tomochain/core/rawdb"
"math/big"
"math/rand"
"sync"
"testing"
"time"

"github.com/tomochain/tomochain/core/rawdb"

"github.com/tomochain/tomochain/common"
"github.com/tomochain/tomochain/consensus/ethash"
"github.com/tomochain/tomochain/core/state"
Expand Down Expand Up @@ -622,7 +623,7 @@ func TestFastVsFullChains(t *testing.T) {
} else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) {
t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles())
}
if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) {
if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash), fast.Config()), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash), fast.Config()); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) {
t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts)
}
}
Expand Down Expand Up @@ -807,7 +808,7 @@ func TestChainTxReorgs(t *testing.T) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn)
}
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil {
if rcpt, _, _, _ := GetReceipt(db, tx.Hash(), blockchain.Config()); rcpt != nil {
t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt)
}
}
Expand All @@ -816,7 +817,7 @@ func TestChainTxReorgs(t *testing.T) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {
t.Errorf("add %d: expected tx to be found", i)
}
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil {
if rcpt, _, _, _ := GetReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil {
t.Errorf("add %d: expected receipt to be found", i)
}
}
Expand All @@ -825,7 +826,7 @@ func TestChainTxReorgs(t *testing.T) {
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {
t.Errorf("share %d: expected tx to be found", i)
}
if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil {
if rcpt, _, _, _ := GetReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil {
t.Errorf("share %d: expected receipt to be found", i)
}
}
Expand Down
107 changes: 101 additions & 6 deletions core/database_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"fmt"
"math/big"

"github.com/tomochain/tomochain/core/rawdb"

"github.com/tomochain/tomochain/common"
"github.com/tomochain/tomochain/core/rawdb"
"github.com/tomochain/tomochain/core/types"
Expand Down Expand Up @@ -224,6 +226,66 @@ func GetTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
return td
}

// ReceiptLogs is a barebone version of ReceiptForStorage which only keeps
// the list of logs. When decoding a stored receipt into this object we
// avoid creating the bloom filter.
type receiptLogs struct {
Logs []*types.Log
}

// DecodeRLP implements rlp.Decoder.
func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error {
var stored types.StoredReceiptRLP
if err := s.Decode(&stored); err != nil {
return err
}
r.Logs = stored.Logs
return nil
}

// DeriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc.
func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error {
logIndex := uint(0)
if len(txs) != len(receipts) {
return errors.New("transaction and receipt count mismatch")
}
for i := 0; i < len(receipts); i++ {
txHash := txs[i].Hash()
// The derived log fields can simply be set from the block and transaction
for j := 0; j < len(receipts[i].Logs); j++ {
receipts[i].Logs[j].BlockNumber = number
receipts[i].Logs[j].BlockHash = hash
receipts[i].Logs[j].TxHash = txHash
receipts[i].Logs[j].TxIndex = uint(i)
receipts[i].Logs[j].Index = logIndex
logIndex++
}
}
return nil
}

// ReadLogs retrieves the logs for all transactions in a block. In case
// receipts is not found, a nil is returned.
// Note: ReadLogs does not derive unstored log fields.
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 {
return nil
}
var receipts []*receiptLogs
if err := rlp.DecodeBytes(data, &receipts); err != nil {
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
return nil
}

logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs
}

// GetBlock 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.
Expand All @@ -244,14 +306,25 @@ func GetBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block {
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
}

// GetBlockReceipts retrieves the receipts generated by the transactions included
// in a block given by its hash.
func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
// ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding.
func ReadReceiptsRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
if len(data) == 0 {
return nil
}
storageReceipts := []*types.ReceiptForStorage{}
return data
}

// ReadRawReceipts retrieves all the transaction receipts belonging to a block.
// The receipt metadata fields are not guaranteed to be populated, so they
// should not be used. Use ReadReceipts instead if the metadata is needed.
func ReadRawReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
// Retrieve the flattened receipt slice
data := ReadReceiptsRLP(db, hash, number)
if len(data) == 0 {
return nil
}
var storageReceipts []*types.ReceiptForStorage
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
return nil
Expand All @@ -263,6 +336,28 @@ func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.
return receipts
}

// GetBlockReceipts retrieves the receipts generated by the transactions included
// in a block given by its hash.
func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64, config *params.ChainConfig) types.Receipts {
// We're deriving many fields from the block body, retrieve beside the receipt
receipts := ReadRawReceipts(db, hash, number)
if receipts == nil {
return nil
}

body := GetBody(db, hash, number)
if body == nil {
log.Error("Missing body but have receipt", "hash", hash, "number", number)
return nil
}
if err := receipts.DeriveFields(config, hash, number, body.Transactions); err != nil {
log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err)
return nil
}

return receipts
}

// GetTxLookupEntry retrieves the positional metadata associated with a transaction
// hash to allow retrieving the transaction or receipt by hash.
func GetTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
Expand Down Expand Up @@ -317,12 +412,12 @@ func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, co

// GetReceipt retrieves a specific transaction receipt from the database, along with
// its added positional metadata.
func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
func GetReceipt(db DatabaseReader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) {
// Retrieve the lookup metadata and resolve the receipt from the receipts
blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash)

if blockHash != (common.Hash{}) {
receipts := GetBlockReceipts(db, blockHash, blockNumber)
receipts := GetBlockReceipts(db, blockHash, blockNumber, config)
if len(receipts) <= int(receiptIndex) {
log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex)
return nil, common.Hash{}, 0, 0
Expand Down
Loading

0 comments on commit 4056a32

Please sign in to comment.