mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-06 03:15:03 +00:00
222 lines
7.7 KiB
Go
222 lines
7.7 KiB
Go
// Copyright 2025 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 <http://www.gnu.org/licenses/>.
|
|
|
|
// Package core implements the Ethereum consensus protocol.
|
|
package core
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
func TestIndexServer(t *testing.T) {
|
|
testIndexServer(t, false, false)
|
|
testIndexServer(t, false, true)
|
|
testIndexServer(t, true, false)
|
|
testIndexServer(t, true, true)
|
|
}
|
|
|
|
func testIndexServer(t *testing.T, needBodies, needReceipts bool) {
|
|
ti := &testIndexer{
|
|
t: t,
|
|
eventCh: make(chan testIndexerEvent),
|
|
statusCh: make(chan testIndexerStatus),
|
|
}
|
|
var blockchain *BlockChain
|
|
doneCh := make(chan struct{})
|
|
expDone := func() {
|
|
select {
|
|
case <-doneCh:
|
|
case <-time.After(time.Second * 5):
|
|
t.Fatalf("Expected chain operation done but not finished yet")
|
|
}
|
|
}
|
|
testSuspendHookCh := make(chan struct{}, 1)
|
|
run := func(fn func()) {
|
|
go func() {
|
|
fn()
|
|
doneCh <- struct{}{}
|
|
}()
|
|
}
|
|
insert := func(chain []*types.Block) {
|
|
run(func() {
|
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
|
t.Fatalf("failed to insert chain[%d]: %v", i, err)
|
|
}
|
|
})
|
|
}
|
|
waitSuspend := func() {
|
|
select {
|
|
case <-testSuspendHookCh:
|
|
case <-time.After(time.Second * 5):
|
|
t.Fatalf("Expected index server suspend but suspended state not reached")
|
|
}
|
|
}
|
|
|
|
gspec := &Genesis{
|
|
Config: params.TestChainConfig,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
}
|
|
db := rawdb.NewMemoryDatabase()
|
|
blockchain, _ = NewBlockChain(db, gspec, ethash.NewFaker(), DefaultConfig())
|
|
chain := []*types.Block{gspec.ToBlock()}
|
|
blocks, _ := GenerateChain(gspec.Config, chain[0], ethash.NewFaker(), db, 110, func(i int, gen *BlockGen) {})
|
|
chain = append(chain, blocks...)
|
|
|
|
run(func() {
|
|
blockchain.RegisterIndexer(ti, "", needBodies, needReceipts)
|
|
blockchain.indexServers.servers[0].testSuspendHookCh = testSuspendHookCh
|
|
})
|
|
ti.expEvent(testIndexerEvent{ev: "SetHistoryCutoff", blockNumber: 0})
|
|
ti.expEvent(testIndexerEvent{ev: "SetFinalized", blockNumber: 0})
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: 0, blockHash: chain[0].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true})
|
|
expDone()
|
|
|
|
insert(chain[1:101])
|
|
waitSuspend()
|
|
ti.expEvent(testIndexerEvent{ev: "Suspended"})
|
|
for i := uint64(1); i <= 100; i++ {
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: i, blockHash: chain[i].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true})
|
|
}
|
|
expDone()
|
|
|
|
run(blockchain.Stop)
|
|
ti.expEvent(testIndexerEvent{ev: "Stop"})
|
|
expDone()
|
|
|
|
blockchain, _ = NewBlockChain(db, gspec, ethash.NewFaker(), DefaultConfig())
|
|
run(func() {
|
|
blockchain.RegisterIndexer(ti, "", needBodies, needReceipts)
|
|
blockchain.indexServers.servers[0].testSuspendHookCh = testSuspendHookCh
|
|
})
|
|
ti.expEvent(testIndexerEvent{ev: "SetHistoryCutoff", blockNumber: 0})
|
|
ti.expEvent(testIndexerEvent{ev: "SetFinalized", blockNumber: 0})
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: 100, blockHash: chain[100].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true, needBlocks: common.NewRange[uint64](0, 100)})
|
|
expDone()
|
|
// request entire chain as historical range, add a new block in the middle and check suspend mechanism
|
|
for i := uint64(0); i <= 49; i++ {
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: i, blockHash: chain[i].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true, needBlocks: common.NewRange[uint64](i+1, 99-i)})
|
|
}
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: 50, blockHash: chain[50].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
insert(chain[101:102])
|
|
waitSuspend()
|
|
ti.status(testIndexerStatus{ready: true, needBlocks: common.NewRange[uint64](51, 49)})
|
|
ti.expEvent(testIndexerEvent{ev: "Suspended"})
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: 101, blockHash: chain[101].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true, needBlocks: common.NewRange[uint64](51, 50)})
|
|
expDone()
|
|
for i := uint64(51); i <= 100; i++ {
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: i, blockHash: chain[i].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true, needBlocks: common.NewRange[uint64](i+1, 100-i)})
|
|
}
|
|
|
|
run(func() {
|
|
blockchain.SetHead(80)
|
|
})
|
|
ti.expEvent(testIndexerEvent{ev: "Revert", blockNumber: 80})
|
|
expDone()
|
|
chain = chain[:81]
|
|
blocks, _ = GenerateChain(gspec.Config, chain[80], ethash.NewFaker(), db, 45, func(i int, gen *BlockGen) {})
|
|
chain = append(chain, blocks...)
|
|
insert(chain[81:121])
|
|
waitSuspend()
|
|
ti.expEvent(testIndexerEvent{ev: "Suspended"})
|
|
for i := uint64(81); i <= 120; i++ {
|
|
ti.expEvent(testIndexerEvent{ev: "AddBlockData", blockNumber: i, blockHash: chain[i].Hash(), hasBody: needBodies, hasReceipts: needReceipts})
|
|
ti.status(testIndexerStatus{ready: true})
|
|
}
|
|
expDone()
|
|
|
|
run(blockchain.Stop)
|
|
ti.expEvent(testIndexerEvent{ev: "Stop"})
|
|
expDone()
|
|
}
|
|
|
|
type testIndexer struct {
|
|
t *testing.T
|
|
eventCh chan testIndexerEvent
|
|
statusCh chan testIndexerStatus
|
|
}
|
|
|
|
type testIndexerEvent struct {
|
|
ev string
|
|
blockNumber uint64
|
|
blockHash common.Hash
|
|
hasBody, hasReceipts bool
|
|
}
|
|
|
|
type testIndexerStatus struct {
|
|
ready bool
|
|
needBlocks common.Range[uint64]
|
|
}
|
|
|
|
func (ti *testIndexer) expEvent(exp testIndexerEvent) {
|
|
var got testIndexerEvent
|
|
select {
|
|
case got = <-ti.eventCh:
|
|
case <-time.After(time.Second * 5):
|
|
}
|
|
if got != exp {
|
|
ti.t.Fatalf("Wrong indexer event received (expected: %v, got: %v)", exp, got)
|
|
}
|
|
}
|
|
|
|
func (ti *testIndexer) status(status testIndexerStatus) {
|
|
ti.statusCh <- status
|
|
}
|
|
|
|
func (ti *testIndexer) AddBlockData(header *types.Header, body *types.Body, receipts types.Receipts) (ready bool, needBlocks common.Range[uint64]) {
|
|
ti.eventCh <- testIndexerEvent{ev: "AddBlockData", blockNumber: header.Number.Uint64(), blockHash: header.Hash(), hasBody: body != nil, hasReceipts: receipts != nil}
|
|
status := <-ti.statusCh
|
|
return status.ready, status.needBlocks
|
|
}
|
|
|
|
func (ti *testIndexer) Revert(blockNumber uint64) {
|
|
ti.eventCh <- testIndexerEvent{ev: "Revert", blockNumber: blockNumber}
|
|
}
|
|
|
|
func (ti *testIndexer) Status() (ready bool, needBlocks common.Range[uint64]) {
|
|
ti.eventCh <- testIndexerEvent{ev: "Status"}
|
|
status := <-ti.statusCh
|
|
return status.ready, status.needBlocks
|
|
}
|
|
|
|
func (ti *testIndexer) SetHistoryCutoff(blockNumber uint64) {
|
|
ti.eventCh <- testIndexerEvent{ev: "SetHistoryCutoff", blockNumber: blockNumber}
|
|
}
|
|
|
|
func (ti *testIndexer) SetFinalized(blockNumber uint64) {
|
|
ti.eventCh <- testIndexerEvent{ev: "SetFinalized", blockNumber: blockNumber}
|
|
}
|
|
|
|
func (ti *testIndexer) Suspended() {
|
|
ti.eventCh <- testIndexerEvent{ev: "Suspended"}
|
|
}
|
|
|
|
func (ti *testIndexer) Stop() {
|
|
ti.eventCh <- testIndexerEvent{ev: "Stop"}
|
|
}
|