Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: missing reorged blocks #250

Merged
merged 6 commits into from
Apr 3, 2023

Conversation

DNK90
Copy link
Contributor

@DNK90 DNK90 commented Mar 29, 2023

Purpose:
After reorg happened, only canonical block is published. Added blocks during this process will not be published.

How to

  • Add dirtyAccounts and internal transactions caches to cache latest 32 blocks data, write them on insertchain function
  • Also add flag to enable storing internal transactions to db if needed (to prevent storage cost) and include writing internal transactions into db after caching internal transactions
  • Get these values in reorg function at processing newchain blocks and publish them via event chainFeed

@DNK90 DNK90 force-pushed the fix/missing_new_chain_blocks_in_reorg branch from 41abbca to 216e024 Compare March 29, 2023 10:51
core/rawdb/accessors_snapshot.go Outdated Show resolved Hide resolved
@@ -161,6 +162,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)

// store internal transaction is enabled flag
rawdb.WriteStoreInternalTransactionsEnabled(backend.ChainDb(), ctx.GlobalBool(utils.StoreInternalTransactions.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, it's better to add a field to blockchain object and read from it to check whether this feature is enabled instead of reading from DB

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be complicated to pass the config to blockchain object from cli and a lot of code changes. Therefore I think, the most simple wait is add it to db

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a field shouldStoreInternalTxs in blockchain object, and get it from db to reduce validation cost everytine WriteInternalTransactions is triggered

bc.internalTransactionsCache.Add(hash, internalTxs)

// check if store internal transactions is enabled or not
if !rawdb.ReadStoreInternalTransactionsEnabled(bc.db) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should check this before caching the internalTxs

if !rawdb.ReadStoreInternalTransactionsEnabled(bc.db) {
return
}
rawdb.WriteInternalTransactions(bc.db, hash, internalTxs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The internal transactions are written to db and never deleted. I think we should cache them to LRU cache and store them to DB only on blockchain.Stop, load them from DB when block.NewBlockChain. The same logic can apply to dirty accounts.

Copy link
Contributor Author

@DNK90 DNK90 Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we have the options of storing internal transactions within db. We should accept the increment of the storage. I agree with the logic of storing dirtyAccounts to db when blockchain is stop

@@ -1712,6 +1721,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er

if dirtyAccounts != nil {
bc.dirtyAccountFeed.Send(dirtyAccounts)
bc.dirtyAccountsCache.Add(block.Hash(), dirtyAccounts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to cache dirty accounts when a configuration is on only, not to always do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think dirty accounts cache is not big compare to other caches such as block. Therefore, we don't need to add more configuration for it

return bc, nil
}

func (bc *BlockChain) loadLatestDirtyAccounts() {
for i := uint64(dirtyAccountsCacheLimit); i > 0; i-- {
hash := rawdb.ReadCanonicalHash(bc.db, bc.CurrentBlock().NumberU64()-i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to store the dirty accounts of side chain, with this logic, dirty accounts of side chain are not loaded. I think we store them as an array of struct { blockHash, dirtyAccounts }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check it again

@datnguyencse datnguyencse merged commit bf13c3e into master Apr 3, 2023
@DNK90 DNK90 deleted the fix/missing_new_chain_blocks_in_reorg branch April 28, 2023 02:11
andicrypt pushed a commit to andicrypt/ronin that referenced this pull request Nov 1, 2023
* fix: add `added blocks` to ChainEvent if reorg happened

* chore: fix unit test failed

* chore: move read/write store internal transaction flag to `accessors_chain`

* chore: add `shouldStoreInternalTxs` into blockchain and use it to check if internal txs should be stored into db or not

* chore: backup dirty accounts to db when blockchain is stop

* chore: change struct of storing latest dirty accounts to make sure canonical or sidechain blockhash can be found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants