mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Add a new abstraction called span store in bor consensus. This makes the header verification stateless as instead of fetching validator set (of a span) from genesis contract, we rely on span from heimdall itself for validator set. This doesn't change any assumptions for consensus as the data in genesis contracts is written by fetching span details from heimdall in the first place. This helps us with multiple things such as header verification for snap sync, validating producer set against header's extra data, and using heimdall as a source of truth instead of making a contract call to genesis contract which generally leads to issues when importing side chains (as we need to use the side chain state and not canonical). Span store is a minimal cache which maintains last 10 spans in memory. It provide simple read methods via span id and block number so that we can use it in consensus.
248 lines
6.9 KiB
Go
248 lines
6.9 KiB
Go
package miner
|
|
|
|
import (
|
|
"errors"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/consensus"
|
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/api"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
"github.com/ethereum/go-ethereum/core/txpool"
|
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
|
"github.com/ethereum/go-ethereum/event"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
|
"github.com/ethereum/go-ethereum/triedb"
|
|
)
|
|
|
|
type DefaultBorMiner struct {
|
|
Miner *Miner
|
|
Mux *event.TypeMux //nolint:staticcheck
|
|
Cleanup func(skipMiner bool)
|
|
|
|
Ctrl *gomock.Controller
|
|
EthAPIMock api.Caller
|
|
HeimdallClientMock bor.IHeimdallClient
|
|
ContractMock bor.GenesisContract
|
|
}
|
|
|
|
func NewBorDefaultMiner(t *testing.T) *DefaultBorMiner {
|
|
t.Helper()
|
|
|
|
ctrl := gomock.NewController(t)
|
|
|
|
ethAPI := api.NewMockCaller(ctrl)
|
|
ethAPI.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
|
|
|
// Mock span 0 for heimdall
|
|
span0 := createMockSpanForTest(common.Address{0x1}, "1337")
|
|
|
|
spanner := bor.NewMockSpanner(ctrl)
|
|
spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(span0.ValidatorSet.Validators, nil).AnyTimes()
|
|
|
|
heimdallClient := mocks.NewMockIHeimdallClient(ctrl)
|
|
heimdallClient.EXPECT().Span(gomock.Any(), uint64(0)).Return(&span0, nil).AnyTimes()
|
|
heimdallClient.EXPECT().Close().Times(1)
|
|
|
|
genesisContracts := bor.NewMockGenesisContract(ctrl)
|
|
|
|
miner, mux, cleanup := createBorMiner(t, ethAPI, spanner, heimdallClient, genesisContracts)
|
|
|
|
return &DefaultBorMiner{
|
|
Miner: miner,
|
|
Mux: mux,
|
|
Cleanup: cleanup,
|
|
Ctrl: ctrl,
|
|
EthAPIMock: ethAPI,
|
|
HeimdallClientMock: heimdallClient,
|
|
ContractMock: genesisContracts,
|
|
}
|
|
}
|
|
|
|
// //nolint:staticcheck
|
|
func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) (*Miner, *event.TypeMux, func(skipMiner bool)) {
|
|
t.Helper()
|
|
|
|
// Create Ethash config
|
|
chainDB, genspec, chainConfig := NewDBForFakes(t)
|
|
|
|
engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
|
|
|
// Create Ethereum backend
|
|
bc, err := core.NewBlockChain(chainDB, nil, genspec, nil, engine, vm.Config{}, nil, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("can't create new chain %v", err)
|
|
}
|
|
|
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil))
|
|
blockchain := &testBlockChainBor{chainConfig, statedb, 10000000, new(event.Feed)}
|
|
|
|
pool := legacypool.New(testTxPoolConfigBor, blockchain)
|
|
txpool, _ := txpool.New(testTxPoolConfigBor.PriceLimit, blockchain, []txpool.SubPool{pool})
|
|
|
|
backend := NewMockBackendBor(bc, txpool)
|
|
|
|
// Create event Mux
|
|
mux := new(event.TypeMux)
|
|
|
|
config := Config{
|
|
Etherbase: common.HexToAddress("123456789"),
|
|
}
|
|
|
|
// Create Miner
|
|
miner := New(backend, &config, chainConfig, mux, engine, nil)
|
|
|
|
cleanup := func(skipMiner bool) {
|
|
bc.Stop()
|
|
engine.Close()
|
|
|
|
if !skipMiner {
|
|
miner.Close()
|
|
}
|
|
}
|
|
|
|
return miner, mux, cleanup
|
|
}
|
|
|
|
type TensingObject interface {
|
|
Helper()
|
|
Fatalf(format string, args ...any)
|
|
}
|
|
|
|
func NewDBForFakes(t TensingObject) (ethdb.Database, *core.Genesis, *params.ChainConfig) {
|
|
t.Helper()
|
|
|
|
memdb := memorydb.New()
|
|
chainDB := rawdb.NewDatabase(memdb)
|
|
addr := common.HexToAddress("12345")
|
|
genesis := core.DeveloperGenesisBlock(11_500_000, &addr)
|
|
|
|
chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb.NewDatabase(chainDB, triedb.HashDefaults), genesis)
|
|
if err != nil {
|
|
t.Fatalf("can't create new chain config: %v", err)
|
|
}
|
|
|
|
chainConfig.Bor.Period = map[string]uint64{
|
|
"0": 1,
|
|
}
|
|
chainConfig.Bor.Sprint = map[string]uint64{
|
|
"0": 64,
|
|
}
|
|
|
|
return chainDB, genesis, chainConfig
|
|
}
|
|
|
|
func NewFakeBor(t TensingObject, chainDB ethdb.Database, chainConfig *params.ChainConfig, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) consensus.Engine {
|
|
t.Helper()
|
|
|
|
if chainConfig.Bor == nil {
|
|
chainConfig.Bor = params.BorUnittestChainConfig.Bor
|
|
}
|
|
|
|
return bor.New(chainConfig, chainDB, ethAPIMock, spanner, heimdallClientMock, contractMock, false)
|
|
}
|
|
|
|
func createMockSpanForTest(address common.Address, chainId string) span.HeimdallSpan {
|
|
// Mock span 0 for heimdall calls
|
|
validator := valset.Validator{
|
|
ID: 0,
|
|
Address: address,
|
|
VotingPower: 100,
|
|
ProposerPriority: 0,
|
|
}
|
|
validatorSet := valset.ValidatorSet{
|
|
Validators: []*valset.Validator{&validator},
|
|
Proposer: &validator,
|
|
}
|
|
span0 := span.HeimdallSpan{
|
|
Span: span.Span{
|
|
ID: 0,
|
|
StartBlock: 0,
|
|
EndBlock: 255,
|
|
},
|
|
ValidatorSet: validatorSet,
|
|
SelectedProducers: []valset.Validator{validator},
|
|
ChainID: chainId,
|
|
}
|
|
|
|
return span0
|
|
}
|
|
|
|
var (
|
|
// Test chain configurations
|
|
testTxPoolConfigBor legacypool.Config
|
|
)
|
|
|
|
// TODO - Arpit, Duplicate Functions
|
|
type mockBackendBor struct {
|
|
bc *core.BlockChain
|
|
txPool *txpool.TxPool
|
|
}
|
|
|
|
func NewMockBackendBor(bc *core.BlockChain, txPool *txpool.TxPool) *mockBackendBor {
|
|
return &mockBackendBor{
|
|
bc: bc,
|
|
txPool: txPool,
|
|
}
|
|
}
|
|
|
|
func (m *mockBackendBor) BlockChain() *core.BlockChain {
|
|
return m.bc
|
|
}
|
|
|
|
// PeerCount implements Backend.
|
|
func (*mockBackendBor) PeerCount() int {
|
|
panic("unimplemented")
|
|
}
|
|
|
|
func (m *mockBackendBor) TxPool() *txpool.TxPool {
|
|
return m.txPool
|
|
}
|
|
|
|
func (m *mockBackendBor) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
|
|
return nil, errors.New("not supported")
|
|
}
|
|
|
|
// TODO - Arpit, Duplicate Functions
|
|
type testBlockChainBor struct {
|
|
config *params.ChainConfig
|
|
statedb *state.StateDB
|
|
gasLimit uint64
|
|
chainHeadFeed *event.Feed
|
|
}
|
|
|
|
func (bc *testBlockChainBor) Config() *params.ChainConfig {
|
|
return bc.config
|
|
}
|
|
|
|
func (bc *testBlockChainBor) CurrentBlock() *types.Header {
|
|
return &types.Header{
|
|
Number: new(big.Int),
|
|
GasLimit: bc.gasLimit,
|
|
}
|
|
}
|
|
|
|
func (bc *testBlockChainBor) GetBlock(hash common.Hash, number uint64) *types.Block {
|
|
return types.NewBlock(bc.CurrentBlock(), nil, nil, nil)
|
|
}
|
|
|
|
func (bc *testBlockChainBor) StateAt(common.Hash) (*state.StateDB, error) {
|
|
return bc.statedb, nil
|
|
}
|
|
|
|
func (bc *testBlockChainBor) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
|
return bc.chainHeadFeed.Subscribe(ch)
|
|
}
|