aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2015-07-15 00:18:09 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2015-07-15 00:40:03 +0800
commite17d8ddbeb01a7e3eb745431d39c93661e167bbc (patch)
treef8814669fc41f220bc1173b58fdf23f27ce609ca
parent796c18db93add1d145db99d6088e445a56851e8b (diff)
downloaddexon-e17d8ddbeb01a7e3eb745431d39c93661e167bbc.tar.gz
dexon-e17d8ddbeb01a7e3eb745431d39c93661e167bbc.tar.zst
dexon-e17d8ddbeb01a7e3eb745431d39c93661e167bbc.zip
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.
-rw-r--r--core/block_processor.go4
-rw-r--r--core/chain_manager.go7
-rw-r--r--core/transaction_util.go48
3 files changed, 46 insertions, 13 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index f50ebb55a..e24b290dd 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -342,7 +342,7 @@ 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) types.Receipts {
if block := sm.ChainManager().GetBlock(bhash); block != nil {
- return GetReceiptsFromBlock(sm.extraDb, block)
+ return GetBlockReceipts(sm.extraDb, block.Hash())
}
return nil
@@ -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
// the depricated way by re-processing the block.
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 {
// coalesce logs
for _, receipt := range receipts {
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 8fa13ddec..1a703d084 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -667,6 +667,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queue[i] = ChainSplitEvent{block, logs}
queueEvent.splitCount++
}
+ PutBlockReceipts(self.extraDb, block, receipts)
+
stats.processed++
}
@@ -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
self.mu.Lock()
for _, block := range newChain {
+ // insert the block in the canonical way, re-writing history
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()
diff --git a/core/transaction_util.go b/core/transaction_util.go
index 0efeddfde..752d4f088 100644
--- a/core/transaction_util.go
+++ b/core/transaction_util.go
@@ -24,7 +24,10 @@ import (
"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
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 {
return &receipt
}
-// 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)
- }
+// GetBlockReceipts returns the receipts generated by the transactions
+// included in block's given hash.
+func GetBlockReceipts(db common.Database, hash common.Hash) types.Receipts {
+ data, _ := db.Get(append(blockReceiptsPre, hash[:]...))
+ if len(data) == 0 {
+ return nil
}
+ var receipts types.Receipts
+ err := rlp.DecodeBytes(data, &receipts)
+ if err != nil {
+ 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
+ }
+
+ hash := block.Hash()
+ err = db.Put(append(blockReceiptsPre, hash[:]...), bytes)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}