From 50847c9724302f6fd63af92988590d8a1c1ee8d4 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Thu, 11 Apr 2024 13:58:07 +0800 Subject: [PATCH] types, core, miner: add block location fields to receipt --- core/blockchain.go | 5 +++++ core/database_util.go | 3 +++ core/state/statedb.go | 10 ++++++++++ core/state_processor.go | 9 +++++++++ core/types/gen_receipt_json.go | 19 +++++++++++++++++++ core/types/gen_tx_json.go | 2 ++ core/types/receipt.go | 14 ++++++++++++-- miner/worker.go | 22 +++++++++++++++------- 8 files changed, 75 insertions(+), 9 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index d4e3736d47..1e548ec28f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1049,6 +1049,11 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty // The transaction hash can be retrieved from the transaction itself receipts[j].TxHash = transactions[j].Hash() + // block location fields + receipts[j].BlockHash = block.Hash() + receipts[j].BlockNumber = block.Number() + receipts[j].TransactionIndex = uint(j) + // The contract address can be derived from the transaction itself if transactions[j].To() == nil { // Deriving the signer is expensive, only do if it's actually needed diff --git a/core/database_util.go b/core/database_util.go index 8e690898a3..81a82305fe 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -259,6 +259,9 @@ func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types. receipts := make(types.Receipts, len(storageReceipts)) for i, receipt := range storageReceipts { receipts[i] = (*types.Receipt)(receipt) + receipts[i].BlockHash = hash + receipts[i].BlockNumber = big.NewInt(0).SetUint64(number) + receipts[i].TransactionIndex = uint(i) for _, log := range receipts[i].Logs { // update BlockHash to fix #208 log.BlockHash = hash diff --git a/core/state/statedb.go b/core/state/statedb.go index 61084675ab..7abb88f12e 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -239,6 +239,16 @@ func (self *StateDB) GetStorageRoot(addr common.Address) common.Hash { return common.Hash{} } +// TxIndex returns the current transaction index set by Prepare. +func (self *StateDB) TxIndex() int { + return self.txIndex +} + +// BlockHash returns the current block hash set by Prepare. +func (self *StateDB) BlockHash() common.Hash { + return self.bhash +} + func (self *StateDB) GetCode(addr common.Address) []byte { stateObject := self.getStateObject(addr) if stateObject != nil { diff --git a/core/state_processor.go b/core/state_processor.go index acfec0c8fd..8a5906060a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -429,6 +429,9 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]* // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.BlockHash = statedb.BlockHash() + receipt.BlockNumber = header.Number + receipt.TransactionIndex = uint(statedb.TxIndex()) if balanceFee != nil && failed { state.PayFeeWithTRC21TxFail(statedb, msg.From(), *tx.To()) } @@ -467,6 +470,9 @@ func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, he statedb.AddLog(log) receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.BlockHash = statedb.BlockHash() + receipt.BlockNumber = header.Number + receipt.TransactionIndex = uint(statedb.TxIndex()) return receipt, 0, nil, false } @@ -491,6 +497,9 @@ func ApplyEmptyTransaction(config *params.ChainConfig, statedb *state.StateDB, h statedb.AddLog(log) receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.BlockHash = statedb.BlockHash() + receipt.BlockNumber = header.Number + receipt.TransactionIndex = uint(statedb.TxIndex()) return receipt, 0, nil, false } diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index 5fce768227..ee3e8c7c2a 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -5,6 +5,7 @@ package types import ( "encoding/json" "errors" + "math/big" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common/hexutil" @@ -22,6 +23,9 @@ func (r Receipt) MarshalJSON() ([]byte, error) { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + BlockHash common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` } var enc Receipt enc.PostState = r.PostState @@ -32,6 +36,9 @@ func (r Receipt) MarshalJSON() ([]byte, error) { enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress enc.GasUsed = hexutil.Uint64(r.GasUsed) + enc.BlockHash = r.BlockHash + enc.BlockNumber = (*hexutil.Big)(r.BlockNumber) + enc.TransactionIndex = hexutil.Uint(r.TransactionIndex) return json.Marshal(&enc) } @@ -45,6 +52,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + BlockHash *common.Hash `json:"blockHash,omitempty"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` + TransactionIndex *hexutil.Uint `json:"transactionIndex"` } var dec Receipt if err := json.Unmarshal(input, &dec); err != nil { @@ -79,5 +89,14 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'gasUsed' for Receipt") } r.GasUsed = uint64(*dec.GasUsed) + if dec.BlockHash != nil { + r.BlockHash = *dec.BlockHash + } + if dec.BlockNumber != nil { + r.BlockNumber = (*big.Int)(dec.BlockNumber) + } + if dec.TransactionIndex != nil { + r.TransactionIndex = uint(*dec.TransactionIndex) + } return nil } diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index 11b6f8ab41..71f4c7d373 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -13,6 +13,7 @@ import ( var _ = (*txdataMarshaling)(nil) +// MarshalJSON marshals as JSON. func (t txdata) MarshalJSON() ([]byte, error) { type txdata struct { AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` @@ -40,6 +41,7 @@ func (t txdata) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (t *txdata) UnmarshalJSON(input []byte) error { type txdata struct { AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` diff --git a/core/types/receipt.go b/core/types/receipt.go index f49d6f1c87..cec362f5a6 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "math/big" "unsafe" "github.com/XinFinOrg/XDPoSChain/common" @@ -44,17 +45,24 @@ const ( // Receipt represents the results of a transaction. type Receipt struct { - // Consensus fields + // Consensus fields: These fields are defined by the Yellow Paper PostState []byte `json:"root"` Status uint `json:"status"` CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` - // Implementation fields (don't reorder!) + // Implementation fields: These fields are added by geth when processing a transaction. + // They are stored in the chain database. TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` + + // 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"` + TransactionIndex uint `json:"transactionIndex"` } type receiptMarshaling struct { @@ -62,6 +70,8 @@ type receiptMarshaling struct { Status hexutil.Uint CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 + BlockNumber *hexutil.Big + TransactionIndex hexutil.Uint } // receiptRLP is the consensus encoding of a receipt. diff --git a/miner/worker.go b/miner/worker.go index 82457ef3ca..688d7556d8 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -364,18 +364,26 @@ func (self *worker) wait() { } work := result.Work + // Different block could share same sealhash, deep copy here to prevent write-write conflict. + hash := block.Hash() + receipts := make([]*types.Receipt, len(work.receipts)) + for i, receipt := range work.receipts { + // add block location fields + receipt.BlockHash = hash + receipt.BlockNumber = block.Number() + receipt.TransactionIndex = uint(i) + + receipts[i] = new(types.Receipt) + *receipts[i] = *receipt + } // Update the block hash in all logs since it is now available and not when the // receipt/log of individual transactions were created. - for _, r := range work.receipts { - for _, l := range r.Logs { - l.BlockHash = block.Hash() - } - } for _, log := range work.state.Logs() { - log.BlockHash = block.Hash() + log.BlockHash = hash } + // Commit block and state to database. self.currentMu.Lock() - stat, err := self.chain.WriteBlockWithState(block, work.receipts, work.state, work.tradingState, work.lendingState) + stat, err := self.chain.WriteBlockWithState(block, receipts, work.state, work.tradingState, work.lendingState) self.currentMu.Unlock() if err != nil { log.Error("Failed writing block to chain", "err", err)