mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
core: refactor DeriveReceipts a bit for generalization
This commit is contained in:
parent
019a6b4921
commit
e8e199749a
7 changed files with 110 additions and 90 deletions
|
|
@ -2273,7 +2273,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
|
|||
blobGasPrice = eip4844.CalcBlobFee(bc.chainConfig, b.Header())
|
||||
}
|
||||
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
|
||||
if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil {
|
||||
if err := receipts.DeriveFields(bc.chainConfig, b.Header(), blobGasPrice, b.Transactions()); err != nil {
|
||||
log.Error("Failed to derive block receipts fields", "hash", b.Hash(), "number", b.NumberU64(), "err", err)
|
||||
}
|
||||
var logs []*types.Log
|
||||
|
|
|
|||
|
|
@ -238,17 +238,7 @@ func (bc *BlockChain) GetReceiptByIndex(tx *types.Transaction, blockHash common.
|
|||
return nil, err
|
||||
}
|
||||
signer := types.MakeSigner(bc.chainConfig, new(big.Int).SetUint64(blockNumber), header.Time)
|
||||
receipt.DeriveFields(signer, types.DeriveReceiptContext{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockTime: header.Time,
|
||||
BaseFee: header.BaseFee,
|
||||
BlobGasPrice: blobGasPrice,
|
||||
GasUsed: ctx.GasUsed,
|
||||
LogIndex: ctx.LogIndex,
|
||||
Tx: tx,
|
||||
TxIndex: uint(txIndex),
|
||||
})
|
||||
receipt.DeriveFields(types.MakeDeriveReceiptContext(signer, header, blobGasPrice, tx, ctx.GasUsed, uint(txIndex), ctx.LogIndex))
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
if block.ExcessBlobGas() != nil {
|
||||
blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header())
|
||||
}
|
||||
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
||||
if err := receipts.DeriveFields(config, block.Header(), blobGasPrice, txs); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
|
@ -563,7 +563,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
|||
if block.ExcessBlobGas() != nil {
|
||||
blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header())
|
||||
}
|
||||
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
||||
if err := receipts.DeriveFields(config, block.Header(), blobGasPrice, txs); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -585,19 +585,15 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64,
|
|||
return nil
|
||||
}
|
||||
header := ReadHeader(db, hash, number)
|
||||
|
||||
var baseFee *big.Int
|
||||
if header == nil {
|
||||
baseFee = big.NewInt(0)
|
||||
} else {
|
||||
baseFee = header.BaseFee
|
||||
return nil
|
||||
}
|
||||
// Compute effective blob gas price.
|
||||
var blobGasPrice *big.Int
|
||||
if header != nil && header.ExcessBlobGas != nil {
|
||||
if header.ExcessBlobGas != nil {
|
||||
blobGasPrice = eip4844.CalcBlobFee(config, header)
|
||||
}
|
||||
if err := receipts.DeriveFields(config, hash, number, time, baseFee, blobGasPrice, body.Transactions); err != nil {
|
||||
if err := receipts.DeriveFields(config, header, blobGasPrice, body.Transactions); err != nil {
|
||||
log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,11 +354,13 @@ func TestBlockReceiptStorage(t *testing.T) {
|
|||
receipt2.Bloom = types.CreateBloom(receipt2)
|
||||
receipts := []*types.Receipt{receipt1, receipt2}
|
||||
|
||||
header := types.Header{Number: big.NewInt(0), Difficulty: big.NewInt(0)}
|
||||
// Check that no receipt entries are in a pristine database
|
||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||
hash := header.Hash()
|
||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
|
||||
t.Fatalf("non existent receipts returned: %v", rs)
|
||||
}
|
||||
WriteHeader(db, &header)
|
||||
// Insert the body that corresponds to the receipts
|
||||
WriteBody(db, hash, 0, body)
|
||||
|
||||
|
|
@ -834,19 +836,21 @@ func TestDeriveLogFields(t *testing.T) {
|
|||
}
|
||||
|
||||
// Derive log metadata fields
|
||||
number := big.NewInt(1)
|
||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||
types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 12, big.NewInt(0), big.NewInt(0), txs)
|
||||
header := types.Header{
|
||||
Number: big.NewInt(1),
|
||||
Time: 12,
|
||||
}
|
||||
types.Receipts(receipts).DeriveFields(params.TestChainConfig, &header, big.NewInt(0), txs)
|
||||
|
||||
// Iterate over all the computed fields and check that they're correct
|
||||
logIndex := uint(0)
|
||||
for i := range receipts {
|
||||
for j := range receipts[i].Logs {
|
||||
if receipts[i].Logs[j].BlockNumber != number.Uint64() {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64())
|
||||
if receipts[i].Logs[j].BlockNumber != header.Number.Uint64() {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, header.Number.Uint64())
|
||||
}
|
||||
if receipts[i].Logs[j].BlockHash != hash {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String())
|
||||
if receipts[i].Logs[j].BlockHash != header.Hash() {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), header.Hash().String())
|
||||
}
|
||||
if receipts[i].Logs[j].BlockTimestamp != 12 {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockTimestamp = %d, want %d", i, j, receipts[i].Logs[j].BlockTimestamp, 12)
|
||||
|
|
|
|||
|
|
@ -265,37 +265,74 @@ type DeriveReceiptContext struct {
|
|||
BlockTime uint64
|
||||
BaseFee *big.Int
|
||||
BlobGasPrice *big.Int
|
||||
GasUsed uint64
|
||||
LogIndex uint // Number of logs in the block until this receipt
|
||||
Tx *Transaction
|
||||
TxIndex uint
|
||||
|
||||
// Receipt fields
|
||||
GasUsed uint64
|
||||
LogIndex uint // Number of logs in the block until this receipt
|
||||
|
||||
// Tx fields
|
||||
Hash common.Hash
|
||||
Nonce uint64
|
||||
Index uint
|
||||
Type uint8
|
||||
From common.Address
|
||||
To *common.Address
|
||||
EffectiveGasPrice *big.Int
|
||||
BlobGas uint64
|
||||
}
|
||||
|
||||
// MakeDeriveReceiptContext builds the context needed to derive a receipt
|
||||
func MakeDeriveReceiptContext(
|
||||
signer Signer, header *Header, blobGasPrice *big.Int,
|
||||
tx *Transaction, gasUsed uint64, txIndex, logIndex uint,
|
||||
) DeriveReceiptContext {
|
||||
from, _ := signer.Sender(tx)
|
||||
return DeriveReceiptContext{
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number.Uint64(),
|
||||
BlockTime: header.Time,
|
||||
BaseFee: header.BaseFee,
|
||||
BlobGasPrice: blobGasPrice,
|
||||
|
||||
// Receipt fields
|
||||
GasUsed: gasUsed,
|
||||
LogIndex: logIndex, // Number of logs in the block until this receipt
|
||||
|
||||
// Tx fields
|
||||
Hash: tx.Hash(),
|
||||
Nonce: tx.Nonce(),
|
||||
Index: txIndex,
|
||||
Type: tx.Type(),
|
||||
From: from,
|
||||
To: tx.To(),
|
||||
EffectiveGasPrice: tx.EffectiveGasPrice(header.BaseFee),
|
||||
BlobGas: tx.BlobGas(),
|
||||
}
|
||||
}
|
||||
|
||||
// DeriveFields fills the receipt with computed fields based on consensus
|
||||
// data and contextual infos like containing block and transactions.
|
||||
func (r *Receipt) DeriveFields(signer Signer, context DeriveReceiptContext) {
|
||||
func (r *Receipt) DeriveFields(context DeriveReceiptContext) {
|
||||
// The transaction type and hash can be retrieved from the transaction itself
|
||||
r.Type = context.Tx.Type()
|
||||
r.TxHash = context.Tx.Hash()
|
||||
r.Type = context.Type
|
||||
r.TxHash = context.Hash
|
||||
r.GasUsed = context.GasUsed
|
||||
r.EffectiveGasPrice = context.Tx.inner.effectiveGasPrice(new(big.Int), context.BaseFee)
|
||||
r.EffectiveGasPrice = context.EffectiveGasPrice
|
||||
|
||||
// EIP-4844 blob transaction fields
|
||||
if context.Tx.Type() == BlobTxType {
|
||||
r.BlobGasUsed = context.Tx.BlobGas()
|
||||
if context.Type == BlobTxType {
|
||||
r.BlobGasUsed = context.BlobGas
|
||||
r.BlobGasPrice = context.BlobGasPrice
|
||||
}
|
||||
|
||||
// Block location fields
|
||||
r.BlockHash = context.BlockHash
|
||||
r.BlockNumber = new(big.Int).SetUint64(context.BlockNumber)
|
||||
r.TransactionIndex = context.TxIndex
|
||||
r.TransactionIndex = context.Index
|
||||
|
||||
// The contract address can be derived from the transaction itself
|
||||
if context.Tx.To() == nil {
|
||||
// Deriving the signer is expensive, only do if it's actually needed
|
||||
from, _ := Sender(signer, context.Tx)
|
||||
r.ContractAddress = crypto.CreateAddress(from, context.Tx.Nonce())
|
||||
if context.To == nil {
|
||||
r.ContractAddress = crypto.CreateAddress(context.From, context.Nonce)
|
||||
} else {
|
||||
r.ContractAddress = common.Address{}
|
||||
}
|
||||
|
|
@ -306,7 +343,7 @@ func (r *Receipt) DeriveFields(signer Signer, context DeriveReceiptContext) {
|
|||
r.Logs[j].BlockHash = context.BlockHash
|
||||
r.Logs[j].BlockTimestamp = context.BlockTime
|
||||
r.Logs[j].TxHash = r.TxHash
|
||||
r.Logs[j].TxIndex = context.TxIndex
|
||||
r.Logs[j].TxIndex = context.Index
|
||||
r.Logs[j].Index = logIndex
|
||||
logIndex++
|
||||
}
|
||||
|
|
@ -379,10 +416,12 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
|||
|
||||
// DeriveFields fills the receipts with their computed fields based on consensus
|
||||
// data and contextual infos like containing block and transactions.
|
||||
func (rs Receipts) DeriveFields(config *params.ChainConfig, blockHash common.Hash, blockNumber uint64, blockTime uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error {
|
||||
signer := MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
|
||||
func (rs Receipts) DeriveFields(config *params.ChainConfig, header *Header, blobGasPrice *big.Int, txs []*Transaction) error {
|
||||
var (
|
||||
signer = MakeSigner(config, header.Number, header.Time)
|
||||
logIndex = uint(0)
|
||||
)
|
||||
|
||||
logIndex := uint(0)
|
||||
if len(txs) != len(rs) {
|
||||
return errors.New("transaction and receipt count mismatch")
|
||||
}
|
||||
|
|
@ -391,17 +430,7 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, blockHash common.Has
|
|||
if i > 0 {
|
||||
cumulativeGasUsed = rs[i-1].CumulativeGasUsed
|
||||
}
|
||||
rs[i].DeriveFields(signer, DeriveReceiptContext{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockTime: blockTime,
|
||||
BaseFee: baseFee,
|
||||
BlobGasPrice: blobGasPrice,
|
||||
GasUsed: rs[i].CumulativeGasUsed - cumulativeGasUsed,
|
||||
LogIndex: logIndex,
|
||||
Tx: txs[i],
|
||||
TxIndex: uint(i),
|
||||
})
|
||||
rs[i].DeriveFields(MakeDeriveReceiptContext(signer, header, blobGasPrice, txs[i], rs[i].CumulativeGasUsed-cumulativeGasUsed, uint(i), logIndex))
|
||||
logIndex += uint(len(rs[i].Logs))
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -152,9 +152,11 @@ var (
|
|||
}),
|
||||
}
|
||||
|
||||
blockNumber = big.NewInt(1)
|
||||
blockTime = uint64(2)
|
||||
blockHash = common.BytesToHash([]byte{0x03, 0x14})
|
||||
header = Header{
|
||||
Number: big.NewInt(1),
|
||||
Difficulty: big.NewInt(0),
|
||||
Time: 2,
|
||||
}
|
||||
)
|
||||
|
||||
var receiptsOnce sync.Once
|
||||
|
|
@ -173,22 +175,22 @@ func getTestReceipts() Receipts {
|
|||
Address: common.BytesToAddress([]byte{0x11}),
|
||||
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
BlockNumber: header.Number.Uint64(),
|
||||
TxHash: txs[0].Hash(),
|
||||
TxIndex: 0,
|
||||
BlockHash: blockHash,
|
||||
BlockTimestamp: blockTime,
|
||||
BlockHash: header.Hash(),
|
||||
BlockTimestamp: header.Time,
|
||||
Index: 0,
|
||||
},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x01, 0x11}),
|
||||
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
BlockNumber: header.Number.Uint64(),
|
||||
TxHash: txs[0].Hash(),
|
||||
TxIndex: 0,
|
||||
BlockHash: blockHash,
|
||||
BlockTimestamp: blockTime,
|
||||
BlockHash: header.Hash(),
|
||||
BlockTimestamp: header.Time,
|
||||
Index: 1,
|
||||
},
|
||||
},
|
||||
|
|
@ -197,8 +199,8 @@ func getTestReceipts() Receipts {
|
|||
ContractAddress: common.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
|
||||
GasUsed: 1,
|
||||
EffectiveGasPrice: big.NewInt(11),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 0,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -209,22 +211,22 @@ func getTestReceipts() Receipts {
|
|||
Address: common.BytesToAddress([]byte{0x22}),
|
||||
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
BlockNumber: header.Number.Uint64(),
|
||||
TxHash: txs[1].Hash(),
|
||||
TxIndex: 1,
|
||||
BlockHash: blockHash,
|
||||
BlockTimestamp: blockTime,
|
||||
BlockHash: header.Hash(),
|
||||
BlockTimestamp: header.Time,
|
||||
Index: 2,
|
||||
},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x02, 0x22}),
|
||||
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
BlockNumber: header.Number.Uint64(),
|
||||
TxHash: txs[1].Hash(),
|
||||
TxIndex: 1,
|
||||
BlockHash: blockHash,
|
||||
BlockTimestamp: blockTime,
|
||||
BlockHash: header.Hash(),
|
||||
BlockTimestamp: header.Time,
|
||||
Index: 3,
|
||||
},
|
||||
},
|
||||
|
|
@ -232,8 +234,8 @@ func getTestReceipts() Receipts {
|
|||
TxHash: txs[1].Hash(),
|
||||
GasUsed: 2,
|
||||
EffectiveGasPrice: big.NewInt(22),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 1,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -245,8 +247,8 @@ func getTestReceipts() Receipts {
|
|||
TxHash: txs[2].Hash(),
|
||||
GasUsed: 3,
|
||||
EffectiveGasPrice: big.NewInt(33),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 2,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -258,8 +260,8 @@ func getTestReceipts() Receipts {
|
|||
TxHash: txs[3].Hash(),
|
||||
GasUsed: 4,
|
||||
EffectiveGasPrice: big.NewInt(1044),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 3,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -271,8 +273,8 @@ func getTestReceipts() Receipts {
|
|||
TxHash: txs[4].Hash(),
|
||||
GasUsed: 5,
|
||||
EffectiveGasPrice: big.NewInt(1055),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 4,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -286,8 +288,8 @@ func getTestReceipts() Receipts {
|
|||
EffectiveGasPrice: big.NewInt(1066),
|
||||
BlobGasUsed: params.BlobTxBlobGasPerBlob,
|
||||
BlobGasPrice: big.NewInt(920),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 5,
|
||||
},
|
||||
&Receipt{
|
||||
|
|
@ -301,8 +303,8 @@ func getTestReceipts() Receipts {
|
|||
EffectiveGasPrice: big.NewInt(1077),
|
||||
BlobGasUsed: 3 * params.BlobTxBlobGasPerBlob,
|
||||
BlobGasPrice: big.NewInt(920),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
BlockHash: header.Hash(),
|
||||
BlockNumber: header.Number,
|
||||
TransactionIndex: 6,
|
||||
},
|
||||
}
|
||||
|
|
@ -326,11 +328,10 @@ func TestDecodeEmptyTypedReceipt(t *testing.T) {
|
|||
// Tests that receipt data can be correctly derived from the contextual infos
|
||||
func TestDeriveFields(t *testing.T) {
|
||||
// Re-derive receipts.
|
||||
basefee := big.NewInt(1000)
|
||||
blobGasPrice := big.NewInt(920)
|
||||
receipts := getTestReceipts()
|
||||
derivedReceipts := clearComputedFieldsOnReceipts(receipts)
|
||||
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, blobGasPrice, txs)
|
||||
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, &header, blobGasPrice, txs)
|
||||
if err != nil {
|
||||
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue