From 2feb23c1dacf1cc7ef664d92f28b63dd46502f21 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Sat, 4 Jul 2015 02:25:04 +0200 Subject: core, eth, miner, xeth: receipt storage fix * Added GetReceiptsFromBlock, GetReceipt, PutReceipts * Added ContractAddress to receipt. See #1042 --- core/block_processor.go | 34 +++++++++++++----------------- core/block_processor_test.go | 11 ++++------ core/chain_manager.go | 2 +- core/transaction_util.go | 50 +++++++++++++++++++++++++++++++++++++------- core/types/receipt.go | 8 +++++-- 5 files changed, 68 insertions(+), 37 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index 7171e3b2e..e8014ec22 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -9,12 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" - "github.com/ethereum/go-ethereum/rlp" "gopkg.in/fatih/set.v0" ) @@ -24,8 +24,6 @@ const ( BlockChainVersion = 3 ) -var receiptsPre = []byte("receipts-") - type BlockProcessor struct { db common.Database extraDb common.Database @@ -83,6 +81,12 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas) + receipt.TxHash = tx.Hash() + if MessageCreatesContract(tx) { + from, _ := tx.From() + receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce()) + } + logs := statedb.GetLogs(tx.Hash()) receipt.SetLogs(logs) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) @@ -319,16 +323,20 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty } // GetBlockReceipts returns the receipts beloniging to the block hash -func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) { - return getBlockReceipts(sm.extraDb, bhash) +func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts { + if block := sm.ChainManager().GetBlock(bhash); block != nil { + return GetReceiptsFromBlock(sm.extraDb, block) + } + + return nil } // GetLogs returns the logs of the given block. This method is using a two step approach // where it tries to get it from the (updated) method which gets them from the receipts or // the depricated way by re-processing the block. func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) { - receipts, err := sm.GetBlockReceipts(block.Hash()) - if err == nil && len(receipts) > 0 { + receipts := GetReceiptsFromBlock(sm.extraDb, block) + if len(receipts) > 0 { // coalesce logs for _, receipt := range receipts { logs = append(logs, receipt.Logs()...) @@ -391,15 +399,3 @@ func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, check return nil } - -func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) { - var rdata []byte - rdata, err = db.Get(append(receiptsPre, bhash[:]...)) - - if err == nil { - err = rlp.DecodeBytes(rdata, &receipts) - } else { - glog.V(logger.Detail).Infof("getBlockReceipts error %v\n", err) - } - return -} diff --git a/core/block_processor_test.go b/core/block_processor_test.go index 99681dabf..8c38d531f 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -64,12 +64,9 @@ func TestPutReceipt(t *testing.T) { Index: 0, }}) - PutReceipts(db, hash, types.Receipts{receipt}) - receipts, err := getBlockReceipts(db, hash) - if err != nil { - t.Error("got err:", err) - } - if len(receipts) != 1 { - t.Error("expected to get 1 receipt, got", len(receipts)) + PutReceipts(db, types.Receipts{receipt}) + receipt = GetReceipt(db, common.Hash{}) + if receipt == nil { + t.Error("expected to get 1 receipt, got none.") } } diff --git a/core/chain_manager.go b/core/chain_manager.go index b5381e336..4855162b5 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -632,7 +632,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) { // This puts transactions in a extra db for rpc PutTransactions(self.extraDb, block, block.Transactions()) // store the receipts - PutReceipts(self.extraDb, block.Hash(), receipts) + PutReceipts(self.extraDb, receipts) case SideStatTy: if glog.V(logger.Detail) { glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart)) diff --git a/core/transaction_util.go b/core/transaction_util.go index bbb215d91..cb5d6c7f7 100644 --- a/core/transaction_util.go +++ b/core/transaction_util.go @@ -8,6 +8,9 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) +var receiptsPre = []byte("receipts-") + +// PutTransactions stores the transactions in the given database func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) { for i, tx := range block.Transactions() { rlpEnc, err := rlp.EncodeToBytes(tx) @@ -34,18 +37,49 @@ func PutTransactions(db common.Database, block *types.Block, txs types.Transacti } } -func PutReceipts(db common.Database, hash common.Hash, receipts types.Receipts) error { - storageReceipts := make([]*types.ReceiptForStorage, len(receipts)) - for i, receipt := range receipts { - storageReceipts[i] = (*types.ReceiptForStorage)(receipt) +// PutReceipts stores the receipts in the current database +func PutReceipts(db common.Database, receipts types.Receipts) error { + for _, receipt := range receipts { + storageReceipt := (*types.ReceiptForStorage)(receipt) + bytes, err := rlp.EncodeToBytes(storageReceipt) + if err != nil { + return err + } + err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes) + if err != nil { + return err + } + } + + return nil +} + +// GetReceipt returns a receipt by hash +func GetReceipt(db common.Database, txHash common.Hash) *types.Receipt { + data, _ := db.Get(append(receiptsPre, txHash[:]...)) + if len(data) == 0 { + return nil } - bytes, err := rlp.EncodeToBytes(storageReceipts) + var receipt types.Receipt + err := rlp.DecodeBytes(data, &receipt) if err != nil { - return err + glog.V(logger.Error).Infoln("GetReceipt err:", err) } + return &receipt +} - db.Put(append(receiptsPre, hash[:]...), bytes) +// GetReceiptFromBlock returns all receipts with the given block +func GetReceiptsFromBlock(db common.Database, block *types.Block) types.Receipts { + // at some point we want: + //receipts := make(types.Receipts, len(block.Transactions())) + // but since we need to support legacy, we can't (yet) + var receipts types.Receipts + for _, tx := range block.Transactions() { + if receipt := GetReceipt(db, tx.Hash()); receipt != nil { + receipts = append(receipts, receipt) + } + } - return nil + return receipts } diff --git a/core/types/receipt.go b/core/types/receipt.go index 6b4024ada..ab52c6e60 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -15,6 +15,8 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int Bloom Bloom + TxHash common.Hash + ContractAddress common.Address logs state.Logs } @@ -39,12 +41,14 @@ func (self *Receipt) DecodeRLP(s *rlp.Stream) error { PostState []byte CumulativeGasUsed *big.Int Bloom Bloom + TxHash common.Hash + ContractAddress common.Address Logs state.Logs } if err := s.Decode(&r); err != nil { return err } - self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs = r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs + self.PostState, self.CumulativeGasUsed, self.Bloom, self.TxHash, self.ContractAddress, self.logs = r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, r.Logs return nil } @@ -56,7 +60,7 @@ func (self *ReceiptForStorage) EncodeRLP(w io.Writer) error { for i, log := range self.logs { storageLogs[i] = (*state.LogForStorage)(log) } - return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, storageLogs}) + return rlp.Encode(w, []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.TxHash, self.ContractAddress, storageLogs}) } func (self *Receipt) RlpEncode() []byte { -- cgit v1.2.3