Skip to content

Commit dbc1b4d

Browse files
authored
Coreth 0.11.6 sync (#436)
* sync changes from coreth-0.11.6 * remove diff patch * revert format changes * nits (#441)
1 parent 0a2e17e commit dbc1b4d

28 files changed

+1650
-170
lines changed

.github/CONTRIBUTING.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,34 @@
11
# Contributing
22

3-
Thank you for considering to help out with the source code! We welcome
4-
contributions from anyone on the internet, and are grateful for even the
3+
Thank you for considering to help out with the source code! We welcome
4+
contributions from anyone on the internet, and are grateful for even the
55
smallest of fixes!
66

7-
If you'd like to contribute to coreth, please fork, fix, commit and send a
7+
If you'd like to contribute to subnet-evm, please fork, fix, commit and send a
88
pull request for the maintainers to review and merge into the main code base. If
9-
you wish to submit more complex changes though, please check up with the core
10-
devs first on [Discord](https://chat.avalabs.org) to
11-
ensure those changes are in line with the general philosophy of the project
9+
you wish to submit more complex changes though, please check up with the core
10+
devs first on [Discord](https://chat.avalabs.org) to
11+
ensure those changes are in line with the general philosophy of the project
1212
and/or get some early feedback which can make both your efforts much lighter as
1313
well as our review and merge procedures quick and simple.
1414

1515
## Coding guidelines
1616

1717
Please make sure your contributions adhere to our coding guidelines:
1818

19-
* Code must adhere to the official Go
20-
[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines
21-
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
22-
* Code must be documented adhering to the official Go
23-
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
24-
* Pull requests need to be based on and opened against the `master` branch.
25-
* Pull reuqests should include a detailed description
26-
* Commits are required to be signed. See [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
27-
for information on signing commits.
28-
* Commit messages should be prefixed with the package(s) they modify.
29-
* E.g. "eth, rpc: make trace configs optional"
19+
- Code must adhere to the official Go
20+
[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines
21+
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
22+
- Code must be documented adhering to the official Go
23+
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
24+
- Pull requests need to be based on and opened against the `master` branch.
25+
- Pull reuqests should include a detailed description
26+
- Commits are required to be signed. See [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
27+
for information on signing commits.
28+
- Commit messages should be prefixed with the package(s) they modify.
29+
- E.g. "eth, rpc: make trace configs optional"
3030

3131
## Can I have feature X
3232

33-
Before you submit a feature request, please check and make sure that it isn't
33+
Before you submit a feature request, please check and make sure that it isn't
3434
possible through some other means.
35-

core/blockchain.go

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,13 @@ var (
8585
acceptedBlockGasUsedCounter = metrics.NewRegisteredCounter("chain/block/gas/used/accepted", nil)
8686
badBlockCounter = metrics.NewRegisteredCounter("chain/block/bad/count", nil)
8787

88+
txUnindexTimer = metrics.NewRegisteredCounter("chain/txs/unindex", nil)
8889
acceptedTxsCounter = metrics.NewRegisteredCounter("chain/txs/accepted", nil)
8990
processedTxsCounter = metrics.NewRegisteredCounter("chain/txs/processed", nil)
9091

92+
acceptedLogsCounter = metrics.NewRegisteredCounter("chain/logs/accepted", nil)
93+
processedLogsCounter = metrics.NewRegisteredCounter("chain/logs/processed", nil)
94+
9195
ErrRefuseToCorruptArchiver = errors.New("node has operated with pruning disabled, shutting down to prevent missing tries")
9296

9397
errFutureBlockUnsupported = errors.New("future block insertion not supported")
@@ -102,7 +106,6 @@ const (
102106
feeConfigCacheLimit = 256
103107
coinbaseConfigCacheLimit = 256
104108
badBlockLimit = 10
105-
TriesInMemory = 128
106109

107110
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
108111
//
@@ -173,6 +176,7 @@ type CacheConfig struct {
173176
SkipSnapshotRebuild bool // Whether to skip rebuilding the snapshot in favor of returning an error (only set to true for tests)
174177
Preimages bool // Whether to store preimage of trie key to the disk
175178
AcceptedCacheSize int // Depth of accepted headers cache and accepted logs cache at the accepted tip
179+
TxLookupLimit uint64 // Number of recent blocks for which to maintain transaction lookup indices
176180
}
177181

178182
var DefaultCacheConfig = &CacheConfig{
@@ -269,9 +273,8 @@ type BlockChain struct {
269273
// during shutdown and in tests.
270274
acceptorWg sync.WaitGroup
271275

272-
// [rejournalWg] is used to wait for the trie clean rejournaling to complete.
273-
// This is used during shutdown.
274-
rejournalWg sync.WaitGroup
276+
// [wg] is used to wait for the async blockchain processes to finish on shutdown.
277+
wg sync.WaitGroup
275278

276279
// quit channel is used to listen for when the blockchain is shut down to close
277280
// async processes.
@@ -354,6 +357,13 @@ func NewBlockChain(
354357
// Create the state manager
355358
bc.stateManager = NewTrieWriter(bc.stateCache.TrieDB(), cacheConfig)
356359

360+
// loadLastState writes indices, so we should start the tx indexer after that.
361+
// Start tx indexer/unindexer here.
362+
if bc.cacheConfig.TxLookupLimit != 0 {
363+
bc.wg.Add(1)
364+
go bc.dispatchTxUnindexer()
365+
}
366+
357367
// Re-generate current block state if it is missing
358368
if err := bc.loadLastState(lastAcceptedHash); err != nil {
359369
return nil, err
@@ -401,16 +411,82 @@ func NewBlockChain(
401411
log.Info("Starting to save trie clean cache periodically", "journalDir", bc.cacheConfig.TrieCleanJournal, "freq", bc.cacheConfig.TrieCleanRejournal)
402412

403413
triedb := bc.stateCache.TrieDB()
404-
bc.rejournalWg.Add(1)
414+
bc.wg.Add(1)
405415
go func() {
406-
defer bc.rejournalWg.Done()
416+
defer bc.wg.Done()
407417
triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit)
408418
}()
409419
}
410420

411421
return bc, nil
412422
}
413423

424+
// dispatchTxUnindexer is responsible for the deletion of the
425+
// transaction index.
426+
// Invariant: If TxLookupLimit is 0, it means all tx indices will be preserved.
427+
// Meaning that this function should never be called.
428+
func (bc *BlockChain) dispatchTxUnindexer() {
429+
defer bc.wg.Done()
430+
txLookupLimit := bc.cacheConfig.TxLookupLimit
431+
432+
// If the user just upgraded to a new version which supports transaction
433+
// index pruning, write the new tail and remove anything older.
434+
if rawdb.ReadTxIndexTail(bc.db) == nil {
435+
rawdb.WriteTxIndexTail(bc.db, 0)
436+
}
437+
438+
// unindexes transactions depending on user configuration
439+
unindexBlocks := func(tail uint64, head uint64, done chan struct{}) {
440+
start := time.Now()
441+
defer func() {
442+
txUnindexTimer.Inc(time.Since(start).Milliseconds())
443+
done <- struct{}{}
444+
}()
445+
446+
// Update the transaction index to the new chain state
447+
if head-txLookupLimit+1 >= tail {
448+
// Unindex a part of stale indices and forward index tail to HEAD-limit
449+
rawdb.UnindexTransactions(bc.db, tail, head-txLookupLimit+1, bc.quit)
450+
}
451+
}
452+
// Any reindexing done, start listening to chain events and moving the index window
453+
var (
454+
done chan struct{} // Non-nil if background unindexing or reindexing routine is active.
455+
headCh = make(chan ChainEvent, 1) // Buffered to avoid locking up the event feed
456+
)
457+
sub := bc.SubscribeChainAcceptedEvent(headCh)
458+
if sub == nil {
459+
log.Warn("could not create chain accepted subscription to unindex txs")
460+
return
461+
}
462+
defer sub.Unsubscribe()
463+
464+
for {
465+
select {
466+
case head := <-headCh:
467+
headNum := head.Block.NumberU64()
468+
if headNum < txLookupLimit {
469+
break
470+
}
471+
472+
if done == nil {
473+
done = make(chan struct{})
474+
// Note: tail will not be nil since it is initialized in this function.
475+
tail := rawdb.ReadTxIndexTail(bc.db)
476+
go unindexBlocks(*tail, headNum, done)
477+
}
478+
case <-done:
479+
done = nil
480+
case <-bc.quit:
481+
if done != nil {
482+
log.Info("Waiting background transaction indexer to exit")
483+
<-done
484+
}
485+
return
486+
}
487+
}
488+
}
489+
414490
// writeBlockAcceptedIndices writes any indices that must be persisted for accepted block.
415491
// This includes the following:
416492
// - transaction lookup indices
@@ -532,6 +608,9 @@ func (bc *BlockChain) startAcceptor() {
532608

533609
acceptorWorkTimer.Inc(time.Since(start).Milliseconds())
534610
acceptorWorkCount.Inc(1)
611+
// Note: in contrast to most accepted metrics, we increment the accepted log metrics in the acceptor queue because
612+
// the logs are already processed in the acceptor queue.
613+
acceptedLogsCounter.Inc(int64(len(logs)))
535614
}
536615
}
537616

@@ -555,8 +634,8 @@ func (bc *BlockChain) addAcceptorQueue(b *types.Block) {
555634
// DrainAcceptorQueue blocks until all items in [acceptorQueue] have been
556635
// processed.
557636
func (bc *BlockChain) DrainAcceptorQueue() {
558-
bc.acceptorClosingLock.Lock()
559-
defer bc.acceptorClosingLock.Unlock()
637+
bc.acceptorClosingLock.RLock()
638+
defer bc.acceptorClosingLock.RUnlock()
560639

561640
if bc.acceptorClosed {
562641
return
@@ -782,7 +861,8 @@ func (bc *BlockChain) ValidateCanonicalChain() error {
782861
// Transactions are only indexed beneath the last accepted block, so we only check
783862
// that the transactions have been indexed, if we are checking below the last accepted
784863
// block.
785-
if current.NumberU64() <= bc.lastAccepted.NumberU64() {
864+
shouldIndexTxs := bc.cacheConfig.TxLookupLimit == 0 || bc.lastAccepted.NumberU64() < current.NumberU64()+bc.cacheConfig.TxLookupLimit
865+
if current.NumberU64() <= bc.lastAccepted.NumberU64() && shouldIndexTxs {
786866
// Ensure that all of the transactions have been stored correctly in the canonical
787867
// chain
788868
for txIndex, tx := range txs {
@@ -840,7 +920,6 @@ func (bc *BlockChain) Stop() {
840920
return
841921
}
842922

843-
// Wait for accepted feed to process all remaining items
844923
log.Info("Closing quit channel")
845924
close(bc.quit)
846925
// Wait for accepted feed to process all remaining items
@@ -868,9 +947,9 @@ func (bc *BlockChain) Stop() {
868947
log.Info("Closing scope")
869948
bc.scope.Close()
870949

871-
// Waiting for clean trie re-journal to complete
872-
log.Info("Waiting for trie re-journal to complete")
873-
bc.rejournalWg.Wait()
950+
// Waiting for background processes to complete
951+
log.Info("Waiting for background processes to complete")
952+
bc.wg.Wait()
874953

875954
log.Info("Blockchain stopped")
876955
}
@@ -1313,6 +1392,7 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error {
13131392

13141393
processedBlockGasUsedCounter.Inc(int64(block.GasUsed()))
13151394
processedTxsCounter.Inc(int64(block.Transactions().Len()))
1395+
processedLogsCounter.Inc(int64(len(logs)))
13161396
blockInsertCount.Inc(1)
13171397
return nil
13181398
}

core/blockchain_test.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,3 +745,142 @@ func TestCanonicalHashMarker(t *testing.T) {
745745
}
746746
}
747747
}
748+
749+
func TestTransactionIndices(t *testing.T) {
750+
// Configure and generate a sample block chain
751+
require := require.New(t)
752+
var (
753+
gendb = rawdb.NewMemoryDatabase()
754+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
755+
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
756+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
757+
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
758+
funds = big.NewInt(10000000000000)
759+
gspec = &Genesis{
760+
Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
761+
Alloc: GenesisAlloc{addr1: {Balance: funds}},
762+
}
763+
genesis = gspec.MustCommit(gendb)
764+
signer = types.LatestSigner(gspec.Config)
765+
)
766+
height := uint64(128)
767+
blocks, _, err := GenerateChain(gspec.Config, genesis, dummy.NewFaker(), gendb, int(height), 10, func(i int, block *BlockGen) {
768+
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
769+
require.NoError(err)
770+
block.AddTx(tx)
771+
})
772+
require.NoError(err)
773+
774+
blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewFaker(), gendb, 10, 10, nil)
775+
require.NoError(err)
776+
777+
check := func(tail *uint64, chain *BlockChain) {
778+
stored := rawdb.ReadTxIndexTail(chain.db)
779+
require.EqualValues(tail, stored)
780+
781+
if tail == nil {
782+
return
783+
}
784+
for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ {
785+
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
786+
if block.Transactions().Len() == 0 {
787+
continue
788+
}
789+
for _, tx := range block.Transactions() {
790+
index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash())
791+
require.NotNilf(index, "Miss transaction indices, number %d hash %s", i, tx.Hash().Hex())
792+
}
793+
}
794+
795+
for i := uint64(0); i < *tail; i++ {
796+
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
797+
if block.Transactions().Len() == 0 {
798+
continue
799+
}
800+
for _, tx := range block.Transactions() {
801+
index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash())
802+
require.Nilf(index, "Transaction indices should be deleted, number %d hash %s", i, tx.Hash().Hex())
803+
}
804+
}
805+
}
806+
807+
conf := &CacheConfig{
808+
TrieCleanLimit: 256,
809+
TrieDirtyLimit: 256,
810+
TrieDirtyCommitTarget: 20,
811+
Pruning: true,
812+
CommitInterval: 4096,
813+
SnapshotLimit: 256,
814+
SkipSnapshotRebuild: true, // Ensure the test errors if snapshot initialization fails
815+
AcceptorQueueLimit: 64,
816+
}
817+
818+
// Init block chain and check all needed indices has been indexed.
819+
chainDB := rawdb.NewMemoryDatabase()
820+
gspec.MustCommit(chainDB)
821+
822+
chain, err := createBlockChain(chainDB, conf, gspec.Config, common.Hash{})
823+
require.NoError(err)
824+
825+
_, err = chain.InsertChain(blocks)
826+
require.NoError(err)
827+
828+
for _, block := range blocks {
829+
err := chain.Accept(block)
830+
require.NoError(err)
831+
}
832+
chain.DrainAcceptorQueue()
833+
834+
chain.Stop()
835+
check(nil, chain) // check all indices has been indexed
836+
837+
lastAcceptedHash := chain.CurrentHeader().Hash()
838+
839+
// Reconstruct a block chain which only reserves limited tx indices
840+
// 128 blocks were previously indexed. Now we add a new block at each test step.
841+
limit := []uint64{130 /* 129 + 1 reserve all */, 64 /* drop stale */, 32 /* shorten history */}
842+
tails := []uint64{0 /* reserve all */, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */}
843+
for i, l := range limit {
844+
conf.TxLookupLimit = l
845+
846+
chain, err := createBlockChain(chainDB, conf, gspec.Config, lastAcceptedHash)
847+
require.NoError(err)
848+
849+
newBlks := blocks2[i : i+1]
850+
_, err = chain.InsertChain(newBlks) // Feed chain a higher block to trigger indices updater.
851+
require.NoError(err)
852+
853+
err = chain.Accept(newBlks[0]) // Accept the block to trigger indices updater.
854+
require.NoError(err)
855+
856+
chain.DrainAcceptorQueue()
857+
time.Sleep(50 * time.Millisecond) // Wait for indices initialisation
858+
859+
chain.Stop()
860+
check(&tails[i], chain)
861+
862+
lastAcceptedHash = chain.CurrentHeader().Hash()
863+
}
864+
}
865+
866+
func TestTxLookupBlockChain(t *testing.T) {
867+
cacheConf := &CacheConfig{
868+
TrieCleanLimit: 256,
869+
TrieDirtyLimit: 256,
870+
TrieDirtyCommitTarget: 20,
871+
Pruning: true,
872+
CommitInterval: 4096,
873+
SnapshotLimit: 256,
874+
SkipSnapshotRebuild: true, // Ensure the test errors if snapshot initialization fails
875+
AcceptorQueueLimit: 64, // ensure channel doesn't block
876+
TxLookupLimit: 5,
877+
}
878+
createTxLookupBlockChain := func(db ethdb.Database, chainConfig *params.ChainConfig, lastAcceptedHash common.Hash) (*BlockChain, error) {
879+
return createBlockChain(db, cacheConf, chainConfig, lastAcceptedHash)
880+
}
881+
for _, tt := range tests {
882+
t.Run(tt.Name, func(t *testing.T) {
883+
tt.testFunc(t, createTxLookupBlockChain)
884+
})
885+
}
886+
}

0 commit comments

Comments
 (0)