Skip to content

Commit

Permalink
Merge pull request ethereum#90 from maticnetwork/block-receipt
Browse files Browse the repository at this point in the history
Add state-sync logs into new tx/receipt
  • Loading branch information
jdkanani authored Dec 8, 2020
2 parents 3de2110 + bc44ada commit 1725944
Show file tree
Hide file tree
Showing 29 changed files with 1,655 additions and 178 deletions.
4 changes: 2 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ Please make sure your contributions adhere to our coding guidelines:
Before you submit a feature request, please check and make sure that it isn't
possible through some other means. The JavaScript-enabled console is a powerful
feature in the right hands. Please check our
[Wiki page](https://github.com/maticnetwork/bor/wiki) for more info
[Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
and help.

## Configuration, dependencies, and tests

Please see the [Developers' Guide](https://github.com/maticnetwork/bor/wiki/Developers'-Guide)
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, managing project dependencies
and testing procedures.
27 changes: 27 additions & 0 deletions accounts/abi/bind/backends/bor_simulated.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
package backends

import (
"context"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)

func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
number := rawdb.ReadHeaderNumber(fb.db, hash)
if number == nil {
return nil, nil
}
receipt := rawdb.ReadRawBorReceipt(fb.db, hash, *number)
if receipt == nil {
return nil, nil
}

return receipt, nil
}

func (fb *filterBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
receipt, err := fb.GetBorBlockReceipt(ctx, hash)
if err != nil || receipt == nil {
return nil, err
}

return receipt.Logs, nil
}

// SubscribeStateSyncEvent subscribes to state sync events
func (fb *filterBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription {
return fb.bc.SubscribeStateSyncEvent(ch)
Expand Down
62 changes: 58 additions & 4 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ type BlockChain struct {
writeLegacyJournal bool // Testing flag used to flush the snapshot journal in legacy format.

// Bor related changes
stateSyncData []*types.StateSyncData // State sync data
stateSyncFeed event.Feed // State sync feed
borReceiptsCache *lru.Cache // Cache for the most recent bor receipt receipts per block
stateSyncData []*types.StateSyncData // State sync data
stateSyncFeed event.Feed // State sync feed
}

// NewBlockChain returns a fully initialised block chain using information
Expand All @@ -232,6 +233,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)

borReceiptsCache, _ := lru.New(receiptsCacheLimit)

bc := &BlockChain{
chainConfig: chainConfig,
cacheConfig: cacheConfig,
Expand All @@ -249,6 +252,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,

borReceiptsCache: borReceiptsCache,
}
bc.validator = NewBlockValidator(chainConfig, bc, engine)
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
Expand Down Expand Up @@ -596,6 +601,8 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64,
// removed in the hc.SetHead function.
rawdb.DeleteBody(db, hash, num)
rawdb.DeleteReceipts(db, hash, num)
rawdb.DeleteBorReceipt(db, hash, num)
rawdb.DeleteBorTxLookupEntry(db, hash, num)
}
// Todo(rjl493456442) txlookup, bloombits, etc
}
Expand All @@ -618,6 +625,7 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64,
bc.blockCache.Purge()
bc.txLookupCache.Purge()
bc.futureBlocks.Purge()
bc.borReceiptsCache.Purge()

return rootNumber, bc.loadLastState()
}
Expand Down Expand Up @@ -1232,7 +1240,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
}
h := rawdb.ReadCanonicalHash(bc.db, frozen)
b := rawdb.ReadBlock(bc.db, h, frozen)
size += rawdb.WriteAncientBlock(bc.db, b, rawdb.ReadReceipts(bc.db, h, frozen, bc.chainConfig), rawdb.ReadTd(bc.db, h, frozen))
size += rawdb.WriteAncientBlock(bc.db, b, rawdb.ReadReceipts(bc.db, h, frozen, bc.chainConfig), rawdb.ReadTd(bc.db, h, frozen), rawdb.ReadBorReceipt(bc.db, h, frozen))
count += 1

// Always keep genesis block in active database.
Expand Down Expand Up @@ -1275,7 +1283,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
log.Info("Migrated ancient blocks", "count", count, "elapsed", common.PrettyDuration(time.Since(start)))
}
// Flush data into ancient database.
size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64()))
size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64()), bc.GetBorReceiptByHash(block.Hash()))

// Write tx indices if any condition is satisfied:
// * If user requires to reserve all tx indices(txlookuplimit=0)
Expand Down Expand Up @@ -1524,6 +1532,40 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
rawdb.WriteBlock(blockBatch, block)
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)

// System call appends state-sync logs into state. So, `state.Logs()` contains
// all logs including system-call logs (state sync logs) while `logs` contains
// only logs generated by transactions (receipts).
//
// That means that state.Logs() can have more logs than receipt logs.
// In that case, we can safely assume that extra logs are from state sync logs.
//
// block logs = receipt logs + state sync logs = `state.Logs()`
blockLogs := state.Logs()
var stateSyncLogs []*types.Log
if len(blockLogs) > 0 {
sort.SliceStable(blockLogs, func(i, j int) bool {
return blockLogs[i].Index < blockLogs[j].Index
})

if len(blockLogs) > len(logs) {
stateSyncLogs = blockLogs[len(logs):] // get state-sync logs from `state.Logs()`

// State sync logs don't have tx index, tx hash and other necessary fields
// DeriveFieldsForBorLogs will fill those fields for websocket subscriptions
types.DeriveFieldsForBorLogs(stateSyncLogs, block.Hash(), block.NumberU64(), uint(len(receipts)), uint(len(logs)))

// Write bor receipt
rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{
Status: types.ReceiptStatusSuccessful, // make receipt status successful
Logs: stateSyncLogs,
})

// Write bor tx reverse lookup
rawdb.WriteBorTxLookupEntry(blockBatch, block.Hash(), block.NumberU64())
}
}

rawdb.WritePreimages(blockBatch, state.Preimages())
if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err)
Expand Down Expand Up @@ -1627,6 +1669,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
if len(logs) > 0 {
bc.logsFeed.Send(logs)
}

// send state sync logs into logs feed
if len(stateSyncLogs) > 0 {
bc.logsFeed.Send(stateSyncLogs)
}

// In theory we should fire a ChainHeadEvent when we inject
// a canonical block, but sometimes we can insert a batch of
// canonicial blocks. Avoid firing too much ChainHeadEvents,
Expand Down Expand Up @@ -2146,6 +2194,12 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
receipts := rawdb.ReadReceipts(bc.db, hash, *number, bc.chainConfig)

// Append bor receipt
borReceipt := rawdb.ReadBorReceipt(bc.db, hash, *number)
if borReceipt != nil {
receipts = append(receipts, borReceipt)
}

var logs []*types.Log
for _, receipt := range receipts {
for _, log := range receipt.Logs {
Expand Down
30 changes: 30 additions & 0 deletions core/bor_blockchain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package core

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
)

// GetBorReceiptByHash retrieves the bor block receipt in a given block.
func (bc *BlockChain) GetBorReceiptByHash(hash common.Hash) *types.Receipt {
if receipt, ok := bc.borReceiptsCache.Get(hash); ok {
return receipt.(*types.Receipt)
}

// read header from hash
number := rawdb.ReadHeaderNumber(bc.db, hash)
if number == nil {
return nil
}

// read bor reciept by hash and number
receipt := rawdb.ReadBorReceipt(bc.db, hash, *number)
if receipt == nil {
return nil
}

// add into bor receipt cache
bc.borReceiptsCache.Add(hash, receipt)
return receipt
}
19 changes: 17 additions & 2 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
}

// WriteAncientBlock writes entire block data into ancient store and returns the total written size.
func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int) int {
func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts types.Receipts, td *big.Int, borReceipt *types.Receipt) int {
// Encode all block components to RLP format.
headerBlob, err := rlp.EncodeToBytes(block.Header())
if err != nil {
Expand All @@ -677,8 +677,17 @@ func WriteAncientBlock(db ethdb.AncientWriter, block *types.Block, receipts type
if err != nil {
log.Crit("Failed to RLP encode block total difficulty", "err", err)
}

borReceiptBlob := make([]byte, 0)
if borReceipt != nil {
borReceiptBlob, err = rlp.EncodeToBytes(borReceipt)
if err != nil {
log.Crit("Failed to RLP encode bor block receipt", "err", err)
}
}

// Write all blob to flatten files.
err = db.AppendAncient(block.NumberU64(), block.Hash().Bytes(), headerBlob, bodyBlob, receiptBlob, tdBlob)
err = db.AppendAncient(block.NumberU64(), block.Hash().Bytes(), headerBlob, bodyBlob, receiptBlob, tdBlob, borReceiptBlob)
if err != nil {
log.Crit("Failed to write block data to ancient store", "err", err)
}
Expand All @@ -691,6 +700,9 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)

// delete bor receipt
DeleteBorReceipt(db, hash, number)
}

// DeleteBlockWithoutNumber removes all block data associated with a hash, except
Expand All @@ -700,6 +712,9 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
deleteHeaderWithoutNumber(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)

// delete bor receipt
DeleteBorReceipt(db, hash, number)
}

// FindCommonAncestor returns the last common ancestor of two block headers
Expand Down
2 changes: 1 addition & 1 deletion core/rawdb/accessors_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ func TestAncientStorage(t *testing.T) {
t.Fatalf("non existent td returned")
}
// Write and verify the header in the database
WriteAncientBlock(db, block, nil, big.NewInt(100))
WriteAncientBlock(db, block, nil, big.NewInt(100), nil)
if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 {
t.Fatalf("no header returned")
}
Expand Down
Loading

0 comments on commit 1725944

Please sign in to comment.