Skip to content

Commit 7399b13

Browse files
committed
Merge pull request #1923 from karalabe/cleanup-receipt-data-access
core, eth, miner, xeth: clean up tx/receipt db accessors
2 parents 65bb07f + e86e0ec commit 7399b13

File tree

11 files changed

+359
-235
lines changed

11 files changed

+359
-235
lines changed

core/block_validator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func TestPutReceipt(t *testing.T) {
8181
Index: 0,
8282
}}
8383

84-
PutReceipts(db, types.Receipts{receipt})
84+
WriteReceipts(db, types.Receipts{receipt})
8585
receipt = GetReceipt(db, common.Hash{})
8686
if receipt == nil {
8787
t.Error("expected to get 1 receipt, got none.")

core/blockchain.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
972972
glog.Fatal(errs[index])
973973
return
974974
}
975-
if err := PutBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
975+
if err := WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
976976
errs[index] = fmt.Errorf("failed to write block receipts: %v", err)
977977
atomic.AddInt32(&failed, 1)
978978
glog.Fatal(errs[index])
@@ -1182,7 +1182,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
11821182
// coalesce logs for later processing
11831183
coalescedLogs = append(coalescedLogs, logs...)
11841184

1185-
if err := PutBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
1185+
if err := WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
11861186
return i, err
11871187
}
11881188

@@ -1201,11 +1201,11 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
12011201
events = append(events, ChainEvent{block, block.Hash(), logs})
12021202

12031203
// This puts transactions in a extra db for rpc
1204-
if err := PutTransactions(self.chainDb, block, block.Transactions()); err != nil {
1204+
if err := WriteTransactions(self.chainDb, block); err != nil {
12051205
return i, err
12061206
}
12071207
// store the receipts
1208-
if err := PutReceipts(self.chainDb, receipts); err != nil {
1208+
if err := WriteReceipts(self.chainDb, receipts); err != nil {
12091209
return i, err
12101210
}
12111211
// Write map map bloom filters
@@ -1294,12 +1294,12 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
12941294
// insert the block in the canonical way, re-writing history
12951295
self.insert(block)
12961296
// write canonical receipts and transactions
1297-
if err := PutTransactions(self.chainDb, block, block.Transactions()); err != nil {
1297+
if err := WriteTransactions(self.chainDb, block); err != nil {
12981298
return err
12991299
}
13001300
receipts := GetBlockReceipts(self.chainDb, block.Hash())
13011301
// write receipts
1302-
if err := PutReceipts(self.chainDb, receipts); err != nil {
1302+
if err := WriteReceipts(self.chainDb, receipts); err != nil {
13031303
return err
13041304
}
13051305
// Write map map bloom filters

core/blockchain_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -937,16 +937,16 @@ func TestChainTxReorgs(t *testing.T) {
937937

938938
// removed tx
939939
for i, tx := range (types.Transactions{pastDrop, freshDrop}) {
940-
if GetTransaction(db, tx.Hash()) != nil {
941-
t.Errorf("drop %d: tx found while shouldn't have been", i)
940+
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
941+
t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn)
942942
}
943943
if GetReceipt(db, tx.Hash()) != nil {
944944
t.Errorf("drop %d: receipt found while shouldn't have been", i)
945945
}
946946
}
947947
// added tx
948948
for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) {
949-
if GetTransaction(db, tx.Hash()) == nil {
949+
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {
950950
t.Errorf("add %d: expected tx to be found", i)
951951
}
952952
if GetReceipt(db, tx.Hash()) == nil {
@@ -955,7 +955,7 @@ func TestChainTxReorgs(t *testing.T) {
955955
}
956956
// shared tx
957957
for i, tx := range (types.Transactions{postponed, swapped}) {
958-
if GetTransaction(db, tx.Hash()) == nil {
958+
if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {
959959
t.Errorf("share %d: expected tx to be found", i)
960960
}
961961
if GetReceipt(db, tx.Hash()) == nil {

core/chain_util.go renamed to core/database_util.go

Lines changed: 174 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,15 @@ var (
4343
bodySuffix = []byte("-body")
4444
tdSuffix = []byte("-td")
4545

46-
ExpDiffPeriod = big.NewInt(100000)
47-
blockHashPre = []byte("block-hash-") // [deprecated by eth/63]
46+
txMetaSuffix = []byte{0x01}
47+
receiptsPrefix = []byte("receipts-")
48+
blockReceiptsPrefix = []byte("receipts-block-")
4849

4950
mipmapPre = []byte("mipmap-log-bloom-")
5051
MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000}
52+
53+
ExpDiffPeriod = big.NewInt(100000)
54+
blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
5155
)
5256

5357
// CalcDifficulty is the difficulty adjustment algorithm. It returns
@@ -234,6 +238,67 @@ func GetBlock(db ethdb.Database, hash common.Hash) *types.Block {
234238
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
235239
}
236240

241+
// GetBlockReceipts retrieves the receipts generated by the transactions included
242+
// in a block given by its hash.
243+
func GetBlockReceipts(db ethdb.Database, hash common.Hash) types.Receipts {
244+
data, _ := db.Get(append(blockReceiptsPrefix, hash[:]...))
245+
if len(data) == 0 {
246+
return nil
247+
}
248+
storageReceipts := []*types.ReceiptForStorage{}
249+
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
250+
glog.V(logger.Error).Infof("invalid receipt array RLP for hash %x: %v", hash, err)
251+
return nil
252+
}
253+
receipts := make(types.Receipts, len(storageReceipts))
254+
for i, receipt := range storageReceipts {
255+
receipts[i] = (*types.Receipt)(receipt)
256+
}
257+
return receipts
258+
}
259+
260+
// GetTransaction retrieves a specific transaction from the database, along with
261+
// its added positional metadata.
262+
func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
263+
// Retrieve the transaction itself from the database
264+
data, _ := db.Get(hash.Bytes())
265+
if len(data) == 0 {
266+
return nil, common.Hash{}, 0, 0
267+
}
268+
var tx types.Transaction
269+
if err := rlp.DecodeBytes(data, &tx); err != nil {
270+
return nil, common.Hash{}, 0, 0
271+
}
272+
// Retrieve the blockchain positional metadata
273+
data, _ = db.Get(append(hash.Bytes(), txMetaSuffix...))
274+
if len(data) == 0 {
275+
return nil, common.Hash{}, 0, 0
276+
}
277+
var meta struct {
278+
BlockHash common.Hash
279+
BlockIndex uint64
280+
Index uint64
281+
}
282+
if err := rlp.DecodeBytes(data, &meta); err != nil {
283+
return nil, common.Hash{}, 0, 0
284+
}
285+
return &tx, meta.BlockHash, meta.BlockIndex, meta.Index
286+
}
287+
288+
// GetReceipt returns a receipt by hash
289+
func GetReceipt(db ethdb.Database, txHash common.Hash) *types.Receipt {
290+
data, _ := db.Get(append(receiptsPrefix, txHash[:]...))
291+
if len(data) == 0 {
292+
return nil
293+
}
294+
var receipt types.ReceiptForStorage
295+
err := rlp.DecodeBytes(data, &receipt)
296+
if err != nil {
297+
glog.V(logger.Core).Infoln("GetReceipt err:", err)
298+
}
299+
return (*types.Receipt)(&receipt)
300+
}
301+
237302
// WriteCanonicalHash stores the canonical hash for the given block number.
238303
func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) error {
239304
key := append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)
@@ -329,6 +394,94 @@ func WriteBlock(db ethdb.Database, block *types.Block) error {
329394
return nil
330395
}
331396

397+
// WriteBlockReceipts stores all the transaction receipts belonging to a block
398+
// as a single receipt slice. This is used during chain reorganisations for
399+
// rescheduling dropped transactions.
400+
func WriteBlockReceipts(db ethdb.Database, hash common.Hash, receipts types.Receipts) error {
401+
// Convert the receipts into their storage form and serialize them
402+
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
403+
for i, receipt := range receipts {
404+
storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
405+
}
406+
bytes, err := rlp.EncodeToBytes(storageReceipts)
407+
if err != nil {
408+
return err
409+
}
410+
// Store the flattened receipt slice
411+
if err := db.Put(append(blockReceiptsPrefix, hash.Bytes()...), bytes); err != nil {
412+
glog.Fatalf("failed to store block receipts into database: %v", err)
413+
return err
414+
}
415+
glog.V(logger.Debug).Infof("stored block receipts [%x…]", hash.Bytes()[:4])
416+
return nil
417+
}
418+
419+
// WriteTransactions stores the transactions associated with a specific block
420+
// into the given database. Beside writing the transaction, the function also
421+
// stores a metadata entry along with the transaction, detailing the position
422+
// of this within the blockchain.
423+
func WriteTransactions(db ethdb.Database, block *types.Block) error {
424+
batch := db.NewBatch()
425+
426+
// Iterate over each transaction and encode it with its metadata
427+
for i, tx := range block.Transactions() {
428+
// Encode and queue up the transaction for storage
429+
data, err := rlp.EncodeToBytes(tx)
430+
if err != nil {
431+
return err
432+
}
433+
if err := batch.Put(tx.Hash().Bytes(), data); err != nil {
434+
return err
435+
}
436+
// Encode and queue up the transaction metadata for storage
437+
meta := struct {
438+
BlockHash common.Hash
439+
BlockIndex uint64
440+
Index uint64
441+
}{
442+
BlockHash: block.Hash(),
443+
BlockIndex: block.NumberU64(),
444+
Index: uint64(i),
445+
}
446+
data, err = rlp.EncodeToBytes(meta)
447+
if err != nil {
448+
return err
449+
}
450+
if err := batch.Put(append(tx.Hash().Bytes(), txMetaSuffix...), data); err != nil {
451+
return err
452+
}
453+
}
454+
// Write the scheduled data into the database
455+
if err := batch.Write(); err != nil {
456+
glog.Fatalf("failed to store transactions into database: %v", err)
457+
return err
458+
}
459+
return nil
460+
}
461+
462+
// WriteReceipts stores a batch of transaction receipts into the database.
463+
func WriteReceipts(db ethdb.Database, receipts types.Receipts) error {
464+
batch := db.NewBatch()
465+
466+
// Iterate over all the receipts and queue them for database injection
467+
for _, receipt := range receipts {
468+
storageReceipt := (*types.ReceiptForStorage)(receipt)
469+
data, err := rlp.EncodeToBytes(storageReceipt)
470+
if err != nil {
471+
return err
472+
}
473+
if err := batch.Put(append(receiptsPrefix, receipt.TxHash.Bytes()...), data); err != nil {
474+
return err
475+
}
476+
}
477+
// Write the scheduled data into the database
478+
if err := batch.Write(); err != nil {
479+
glog.Fatalf("failed to store receipts into database: %v", err)
480+
return err
481+
}
482+
return nil
483+
}
484+
332485
// DeleteCanonicalHash removes the number to hash canonical mapping.
333486
func DeleteCanonicalHash(db ethdb.Database, number uint64) {
334487
db.Delete(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...))
@@ -351,18 +504,35 @@ func DeleteTd(db ethdb.Database, hash common.Hash) {
351504

352505
// DeleteBlock removes all block data associated with a hash.
353506
func DeleteBlock(db ethdb.Database, hash common.Hash) {
507+
DeleteBlockReceipts(db, hash)
354508
DeleteHeader(db, hash)
355509
DeleteBody(db, hash)
356510
DeleteTd(db, hash)
357511
}
358512

359-
// [deprecated by eth/63]
513+
// DeleteBlockReceipts removes all receipt data associated with a block hash.
514+
func DeleteBlockReceipts(db ethdb.Database, hash common.Hash) {
515+
db.Delete(append(blockReceiptsPrefix, hash.Bytes()...))
516+
}
517+
518+
// DeleteTransaction removes all transaction data associated with a hash.
519+
func DeleteTransaction(db ethdb.Database, hash common.Hash) {
520+
db.Delete(hash.Bytes())
521+
db.Delete(append(hash.Bytes(), txMetaSuffix...))
522+
}
523+
524+
// DeleteReceipt removes all receipt data associated with a transaction hash.
525+
func DeleteReceipt(db ethdb.Database, hash common.Hash) {
526+
db.Delete(append(receiptsPrefix, hash.Bytes()...))
527+
}
528+
529+
// [deprecated by the header/block split, remove eventually]
360530
// GetBlockByHashOld returns the old combined block corresponding to the hash
361531
// or nil if not found. This method is only used by the upgrade mechanism to
362532
// access the old combined block representation. It will be dropped after the
363533
// network transitions to eth/63.
364534
func GetBlockByHashOld(db ethdb.Database, hash common.Hash) *types.Block {
365-
data, _ := db.Get(append(blockHashPre, hash[:]...))
535+
data, _ := db.Get(append(blockHashPrefix, hash[:]...))
366536
if len(data) == 0 {
367537
return nil
368538
}

0 commit comments

Comments
 (0)