From 253faa5bc166ab303c34913e2a6fe2d7a8c1b2db Mon Sep 17 00:00:00 2001 From: Manav Darji Date: Wed, 26 Mar 2025 11:23:11 +0530 Subject: [PATCH] core: add TestReorgSideEvent test and side chain event subscription back --- core/blockchain_reader.go | 5 +++ core/blockchain_test.go | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 07baa55349..c44e9d03fc 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -484,6 +484,11 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch)) } +// SubscribeChainSideEvent registers a subscription of ChainSideEvent. +func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Subscription { + return bc.scope.Track(bc.chainSideFeed.Subscribe(ch)) +} + // SubscribeLogsEvent registers a subscription of []*types.Log. func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return bc.scope.Track(bc.logsFeed.Subscribe(ch)) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ac9a1f6bae..2896a49392 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1512,6 +1512,94 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re } } +func TestReorgSideEvent(t *testing.T) { + testReorgSideEvent(t, rawdb.HashScheme) + testReorgSideEvent(t, rawdb.PathScheme) +} + +func testReorgSideEvent(t *testing.T, scheme string) { + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}, + } + signer = types.LatestSigner(gspec.Config) + ) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) + defer blockchain.Stop() + + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) + if _, err := blockchain.InsertChain(chain); err != nil { + t.Fatalf("failed to insert chain: %v", err) + } + + _, replacementBlocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, gen *BlockGen) { + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1) + + if i == 2 { + gen.OffsetTime(-9) + } + + if err != nil { + t.Fatalf("failed to create tx: %v", err) + } + + gen.AddTx(tx) + }) + chainSideCh := make(chan ChainSideEvent, 64) + blockchain.SubscribeChainSideEvent(chainSideCh) + + if _, err := blockchain.InsertChain(replacementBlocks); err != nil { + t.Fatalf("failed to insert chain: %v", err) + } + + // first two block of the secondary chain are for a brief moment considered + // side chains because up to that point the first one is considered the + // heavier chain. + expectedSideHashes := map[common.Hash]bool{ + replacementBlocks[0].Hash(): true, + replacementBlocks[1].Hash(): true, + chain[0].Hash(): true, + chain[1].Hash(): true, + chain[2].Hash(): true, + } + + i := 0 + + const timeoutDura = 10 * time.Second + timeout := time.NewTimer(timeoutDura) +done: + for { + select { + case ev := <-chainSideCh: + block := ev.Block + if _, ok := expectedSideHashes[block.Hash()]; !ok { + t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash()) + } + i++ + + if i == len(expectedSideHashes) { + timeout.Stop() + + break done + } + timeout.Reset(timeoutDura) + + case <-timeout.C: + t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent") + } + } + + // make sure no more events are fired + select { + case e := <-chainSideCh: + t.Errorf("unexpected event fired: %v", e) + case <-time.After(250 * time.Millisecond): + } +} + // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { testCanonicalBlockRetrieval(t, rawdb.HashScheme)