Commit e17d8ddb authored by Jeffrey Wilcke's avatar Jeffrey Wilcke

core: during chain reorg rewrite receipts and transactions

Added PutBlockReceipts; storing receipts by blocks. Eventually this will
require pruning during some cleanup cycle. During forks the receipts by
block are used to get the new canonical receipts and transactions.

This PR fixes #1473 by rewriting transactions and receipts from the point
of where the fork occured.
parent 796c18db
...@@ -342,7 +342,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty ...@@ -342,7 +342,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
// GetBlockReceipts returns the receipts beloniging to the block hash // GetBlockReceipts returns the receipts beloniging to the block hash
func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts { func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
if block := sm.ChainManager().GetBlock(bhash); block != nil { if block := sm.ChainManager().GetBlock(bhash); block != nil {
return GetReceiptsFromBlock(sm.extraDb, block) return GetBlockReceipts(sm.extraDb, block.Hash())
} }
return nil return nil
...@@ -352,7 +352,7 @@ func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts { ...@@ -352,7 +352,7 @@ func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
// where it tries to get it from the (updated) method which gets them from the receipts or // 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. // the depricated way by re-processing the block.
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) { func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
receipts := GetReceiptsFromBlock(sm.extraDb, block) receipts := GetBlockReceipts(sm.extraDb, block.Hash())
if len(receipts) > 0 { if len(receipts) > 0 {
// coalesce logs // coalesce logs
for _, receipt := range receipts { for _, receipt := range receipts {
......
...@@ -667,6 +667,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) { ...@@ -667,6 +667,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queue[i] = ChainSplitEvent{block, logs} queue[i] = ChainSplitEvent{block, logs}
queueEvent.splitCount++ queueEvent.splitCount++
} }
PutBlockReceipts(self.extraDb, block, receipts)
stats.processed++ stats.processed++
} }
...@@ -744,7 +746,12 @@ func (self *ChainManager) merge(oldBlock, newBlock *types.Block) error { ...@@ -744,7 +746,12 @@ func (self *ChainManager) merge(oldBlock, newBlock *types.Block) error {
// insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly // insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly
self.mu.Lock() self.mu.Lock()
for _, block := range newChain { for _, block := range newChain {
// insert the block in the canonical way, re-writing history
self.insert(block) self.insert(block)
// write canonical receipts and transactions
PutTransactions(self.extraDb, block, block.Transactions())
PutReceipts(self.extraDb, GetBlockReceipts(self.extraDb, block.Hash()))
} }
self.mu.Unlock() self.mu.Unlock()
......
...@@ -24,7 +24,10 @@ import ( ...@@ -24,7 +24,10 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
var receiptsPre = []byte("receipts-") var (
receiptsPre = []byte("receipts-")
blockReceiptsPre = []byte("receipts-block-")
)
// PutTransactions stores the transactions in the given database // PutTransactions stores the transactions in the given database
func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) { func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) {
...@@ -85,17 +88,40 @@ func GetReceipt(db common.Database, txHash common.Hash) *types.Receipt { ...@@ -85,17 +88,40 @@ func GetReceipt(db common.Database, txHash common.Hash) *types.Receipt {
return &receipt return &receipt
} }
// GetReceiptFromBlock returns all receipts with the given block // GetBlockReceipts returns the receipts generated by the transactions
func GetReceiptsFromBlock(db common.Database, block *types.Block) types.Receipts { // included in block's given hash.
// at some point we want: func GetBlockReceipts(db common.Database, hash common.Hash) types.Receipts {
//receipts := make(types.Receipts, len(block.Transactions())) data, _ := db.Get(append(blockReceiptsPre, hash[:]...))
// but since we need to support legacy, we can't (yet) if len(data) == 0 {
return nil
}
var receipts types.Receipts var receipts types.Receipts
for _, tx := range block.Transactions() { err := rlp.DecodeBytes(data, &receipts)
if receipt := GetReceipt(db, tx.Hash()); receipt != nil { if err != nil {
receipts = append(receipts, receipt) glog.V(logger.Core).Infoln("GetReceiptse err", err)
}
return receipts
}
// PutBlockReceipts stores the block's transactions associated receipts
// and stores them by block hash in a single slice. This is required for
// forks and chain reorgs
func PutBlockReceipts(db common.Database, block *types.Block, receipts types.Receipts) error {
rs := make([]*types.ReceiptForStorage, len(receipts))
for i, receipt := range receipts {
rs[i] = (*types.ReceiptForStorage)(receipt)
} }
bytes, err := rlp.EncodeToBytes(rs)
if err != nil {
return err
} }
return receipts hash := block.Hash()
err = db.Put(append(blockReceiptsPre, hash[:]...), bytes)
if err != nil {
return err
}
return nil
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment