diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9d9256862b6..01a424463d3 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -1,20 +1,3 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// geth is a command-line client for Ethereum. package main import ( diff --git a/core/bloom_indexer.go b/core/bloom_indexer.go index 68a35d811e4..babe37999ed 100644 --- a/core/bloom_indexer.go +++ b/core/bloom_indexer.go @@ -1,23 +1,8 @@ -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package core import ( "context" + "errors" "time" "github.com/ethereum/go-ethereum/common" @@ -39,7 +24,7 @@ const ( type BloomIndexer struct { size uint64 // section size to generate bloombits for db ethdb.Database // database instance to write index data and metadata into - gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index + gen *bloombits.Generator // generator to rotate the bloom bits creating the bloom index section uint64 // Section is the section number being processed currently head common.Hash // Head is the hash of the last header processed } @@ -60,14 +45,22 @@ func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *ChainIndexer { // section. func (b *BloomIndexer) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { gen, err := bloombits.NewGenerator(uint(b.size)) + if err != nil { + return err + } b.gen, b.section, b.head = gen, section, common.Hash{} - return err + return nil } // Process implements core.ChainIndexerBackend, adding a new header's bloom into // the index. func (b *BloomIndexer) Process(ctx context.Context, header *types.Header) error { - b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom) + if b.gen == nil { + return errors.New("bloom generator is not initialized") + } + if err := b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom); err != nil { + return err + } b.head = header.Hash() return nil } @@ -75,13 +68,18 @@ func (b *BloomIndexer) Process(ctx context.Context, header *types.Header) error // Commit implements core.ChainIndexerBackend, finalizing the bloom section and // writing it out into the database. func (b *BloomIndexer) Commit() error { + if b.gen == nil { + return errors.New("bloom generator is not initialized") + } batch := b.db.NewBatchWithSize((int(b.size) / 8) * types.BloomBitLength) for i := 0; i < types.BloomBitLength; i++ { bits, err := b.gen.Bitset(uint(i)) if err != nil { return err } - rawdb.WriteBloomBits(batch, uint(i), b.section, b.head, bitutil.CompressBytes(bits)) + if err := rawdb.WriteBloomBits(batch, uint(i), b.section, b.head, bitutil.CompressBytes(bits)); err != nil { + return err + } } return batch.Write() } diff --git a/core/bloombits/generator_test.go b/core/bloombits/generator_test.go index ac1aee0b252..65dbc1db45a 100644 --- a/core/bloombits/generator_test.go +++ b/core/bloombits/generator_test.go @@ -1,19 +1,3 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package bloombits import ( @@ -98,3 +82,43 @@ func BenchmarkGenerator(b *testing.B) { } }) } + +// TestGeneratorEdgeCases tests edge cases for the bloom generator. +func TestGeneratorEdgeCases(t *testing.T) { + // Test with zero sections + _, err := NewGenerator(0) + if err == nil { + t.Fatal("expected error for zero sections, got nil") + } + + // Test with non-multiple of 8 sections + _, err = NewGenerator(7) + if err == nil { + t.Fatal("expected error for non-multiple of 8 sections, got nil") + } + + // Test with valid sections + gen, err := NewGenerator(8) + if err != nil { + t.Fatalf("failed to create bloombit generator: %v", err) + } + + // Test adding bloom with unexpected index + err = gen.AddBloom(1, types.Bloom{}) + if err == nil { + t.Fatal("expected error for unexpected index, got nil") + } + + // Test retrieving bitset before fully generated + _, err = gen.Bitset(0) + if err == nil { + t.Fatal("expected error for bloom not fully generated, got nil") + } + + // Test retrieving bitset with out of bounds index + gen.AddBloom(0, types.Bloom{}) + _, err = gen.Bitset(types.BloomBitLength) + if err == nil { + t.Fatal("expected error for bloom bit out of bounds, got nil") + } +} diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index 7f3d5f279ca..8149d5bd1bf 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -1,19 +1,3 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package bloombits import ( @@ -290,3 +274,39 @@ func expMatch3(filter [][]bloomIndexes, i uint64) bool { } return true } + +// TestMatcherEdgeCases tests edge cases for the matcher. +func TestMatcherEdgeCases(t *testing.T) { + t.Parallel() + + // Test with zero sections + _, err := NewMatcher(0, nil) + if err == nil { + t.Fatal("expected error for zero sections, got nil") + } + + // Test with non-multiple of 8 sections + _, err = NewMatcher(7, nil) + if err == nil { + t.Fatal("expected error for non-multiple of 8 sections, got nil") + } + + // Test with valid sections + matcher := NewMatcher(8, nil) + if matcher == nil { + t.Fatal("failed to create matcher with valid sections") + } + + // Test starting a session with invalid range + _, err = matcher.Start(context.Background(), 10, 5, make(chan uint64)) + if err == nil { + t.Fatal("expected error for invalid range, got nil") + } + + // Test starting a session with valid range + session, err := matcher.Start(context.Background(), 0, 7, make(chan uint64)) + if err != nil { + t.Fatalf("failed to start matcher session: %v", err) + } + session.Close() +} diff --git a/core/bloombits/scheduler_test.go b/core/bloombits/scheduler_test.go index dcaaa915258..fdaaf946b5a 100644 --- a/core/bloombits/scheduler_test.go +++ b/core/bloombits/scheduler_test.go @@ -1,19 +1,3 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package bloombits import ( @@ -101,3 +85,42 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { t.Errorf("request count mismatch: have %v, want %v", have, requests) } } + +// TestSchedulerEdgeCases tests edge cases for the scheduler. +func TestSchedulerEdgeCases(t *testing.T) { + t.Parallel() + + // Test with zero sections + _, err := newScheduler(0) + if err == nil { + t.Fatal("expected error for zero sections, got nil") + } + + // Test with non-multiple of 8 sections + _, err = newScheduler(7) + if err == nil { + t.Fatal("expected error for non-multiple of 8 sections, got nil") + } + + // Test with valid sections + scheduler := newScheduler(8) + if scheduler == nil { + t.Fatal("failed to create scheduler with valid sections") + } + + // Test running the scheduler with invalid channels + in := make(chan uint64, 16) + out := make(chan []byte, 16) + quit := make(chan struct{}) + var pend sync.WaitGroup + pend.Add(1) + go func() { + defer pend.Done() + scheduler.run(in, nil, out, quit, &pend) + }() + + // Test sending invalid data to the scheduler + in <- 1 + close(in) + pend.Wait() +} diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index bf3bde756cb..6b2a41209c0 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -1,19 +1,3 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - package core import ( @@ -244,3 +228,85 @@ func (b *testChainIndexBackend) Commit() error { func (b *testChainIndexBackend) Prune(threshold uint64) error { return nil } + +// TestChainIndexerReorg tests the chain indexer for handling reorgs correctly. +func TestChainIndexerReorg(t *testing.T) { + db := rawdb.NewMemoryDatabase() + defer db.Close() + + // Create a chain indexer + sectionSize := uint64(10) + confirmsReq := uint64(5) + backend := &testChainIndexBackend{t: t, processCh: make(chan uint64)} + indexer := NewChainIndexer(db, rawdb.NewTable(db, "test"), backend, sectionSize, confirmsReq, 0, "indexer") + defer indexer.Close() + + // Function to inject headers into the database + inject := func(number uint64) { + header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} + if number > 0 { + header.ParentHash = rawdb.ReadCanonicalHash(db, number-1) + } + rawdb.WriteHeader(db, header) + rawdb.WriteCanonicalHash(db, header.Hash(), number) + } + + // Function to notify the indexer about new heads + notify := func(headNum uint64, reorg bool) { + indexer.newHead(headNum, reorg) + } + + // Inject initial chain + for i := uint64(0); i <= 50; i++ { + inject(i) + } + notify(50, false) + + // Reorg the chain + notify(25, true) + + // Create new fork + for i := uint64(26); i <= 50; i++ { + inject(i) + notify(i, false) + } +} + +// TestChainIndexerPrune tests the chain indexer for pruning old sections correctly. +func TestChainIndexerPrune(t *testing.T) { + db := rawdb.NewMemoryDatabase() + defer db.Close() + + // Create a chain indexer + sectionSize := uint64(10) + confirmsReq := uint64(5) + backend := &testChainIndexBackend{t: t, processCh: make(chan uint64)} + indexer := NewChainIndexer(db, rawdb.NewTable(db, "test"), backend, sectionSize, confirmsReq, 0, "indexer") + defer indexer.Close() + + // Function to inject headers into the database + inject := func(number uint64) { + header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} + if number > 0 { + header.ParentHash = rawdb.ReadCanonicalHash(db, number-1) + } + rawdb.WriteHeader(db, header) + rawdb.WriteCanonicalHash(db, header.Hash(), number) + } + + // Function to notify the indexer about new heads + notify := func(headNum uint64, reorg bool) { + indexer.newHead(headNum, reorg) + } + + // Inject initial chain + for i := uint64(0); i <= 50; i++ { + inject(i) + } + notify(50, false) + + // Prune old sections + if err := indexer.Prune(20); err != nil { + t.Fatalf("Failed to prune sections: %v", err) + } +}