mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-11 22:43:47 +00:00
Merge branch 'develop' of https://github.com/maticnetwork/bor into shivam/pos-636
This commit is contained in:
commit
73054f8608
84 changed files with 2227 additions and 568 deletions
3
Makefile
3
Makefile
|
|
@ -32,6 +32,9 @@ bor:
|
||||||
protoc:
|
protoc:
|
||||||
protoc --go_out=. --go-grpc_out=. ./internal/cli/server/proto/*.proto
|
protoc --go_out=. --go-grpc_out=. ./internal/cli/server/proto/*.proto
|
||||||
|
|
||||||
|
generate-mocks:
|
||||||
|
go generate mockgen -destination=./tests/bor/mocks/IHeimdallClient.go -package=mocks ./consensus/bor IHeimdallClient
|
||||||
|
|
||||||
geth:
|
geth:
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ type SimulatedBackend struct {
|
||||||
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||||
genesis.MustCommit(database)
|
genesis.MustCommit(database)
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
|
|
||||||
backend := &SimulatedBackend{
|
backend := &SimulatedBackend{
|
||||||
database: database,
|
database: database,
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,12 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"gopkg.in/urfave/cli.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
pcsclite "github.com/gballet/go-libpcsclite"
|
||||||
|
gopsutil "github.com/shirou/gopsutil/mem"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -68,9 +72,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
pcsclite "github.com/gballet/go-libpcsclite"
|
|
||||||
gopsutil "github.com/shirou/gopsutil/mem"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -2072,7 +2073,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||||
|
|
||||||
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
|
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
|
||||||
// Disable transaction indexing/unindexing by default.
|
// Disable transaction indexing/unindexing by default.
|
||||||
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil)
|
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -606,7 +606,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
if !snap.ValidatorSet.HasAddress(signer) {
|
||||||
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
||||||
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
@ -623,13 +623,13 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
||||||
parent = chain.GetHeader(header.ParentHash, number-1)
|
parent = chain.GetHeader(header.ParentHash, number-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) {
|
if IsBlockOnTime(parent, header, number, succession, c.config) {
|
||||||
return &BlockTooSoonError{number, succession}
|
return &BlockTooSoonError{number, succession}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the difficulty corresponds to the turn-ness of the signer
|
// Ensure that the difficulty corresponds to the turn-ness of the signer
|
||||||
if !c.fakeDiff {
|
if !c.fakeDiff {
|
||||||
difficulty := snap.Difficulty(signer)
|
difficulty := Difficulty(snap.ValidatorSet, signer)
|
||||||
if header.Difficulty.Uint64() != difficulty {
|
if header.Difficulty.Uint64() != difficulty {
|
||||||
return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
|
return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
@ -638,6 +638,10 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsBlockOnTime(parent *types.Header, header *types.Header, number uint64, succession int, cfg *params.BorConfig) bool {
|
||||||
|
return parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
||||||
// header for running the transactions on top.
|
// header for running the transactions on top.
|
||||||
func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||||
|
|
@ -653,7 +657,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the correct difficulty
|
// Set the correct difficulty
|
||||||
header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
header.Difficulty = new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, c.signer))
|
||||||
|
|
||||||
// Ensure the extra data has all it's components
|
// Ensure the extra data has all it's components
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < extraVanity {
|
||||||
|
|
@ -716,7 +720,7 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
||||||
|
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
|
|
||||||
if headerNumber%c.config.Sprint == 0 {
|
if IsSprintStart(headerNumber, c.config.Sprint) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||||
|
|
@ -727,7 +731,7 @@ func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.HeimdallClient != nil {
|
if c.HeimdallClient != nil {
|
||||||
// commit statees
|
// commit states
|
||||||
stateSyncData, err = c.CommitStates(ctx, state, header, cx)
|
stateSyncData, err = c.CommitStates(ctx, state, header, cx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error while committing states", "error", err)
|
log.Error("Error while committing states", "error", err)
|
||||||
|
|
@ -790,7 +794,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
|
||||||
|
|
||||||
headerNumber := header.Number.Uint64()
|
headerNumber := header.Number.Uint64()
|
||||||
|
|
||||||
if headerNumber%c.config.Sprint == 0 {
|
if IsSprintStart(headerNumber, c.config.Sprint) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
cx := statefull.ChainContext{Chain: chain, Bor: c}
|
||||||
|
|
@ -867,7 +871,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bail out if we're unauthorized to sign a block
|
// Bail out if we're unauthorized to sign a block
|
||||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
if !snap.ValidatorSet.HasAddress(signer) {
|
||||||
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
|
||||||
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
return &UnauthorizedSignerError{number - 1, signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
@ -945,7 +949,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, _ uint64, parent
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(big.Int).SetUint64(snap.Difficulty(c.signer))
|
return new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, c.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SealHash returns the hash of a block prior to it being sealed.
|
// SealHash returns the hash of a block prior to it being sealed.
|
||||||
|
|
@ -1059,7 +1063,6 @@ func (c *Bor) CommitStates(
|
||||||
header *types.Header,
|
header *types.Header,
|
||||||
chain statefull.ChainContext,
|
chain statefull.ChainContext,
|
||||||
) ([]*types.StateSyncData, error) {
|
) ([]*types.StateSyncData, error) {
|
||||||
stateSyncs := make([]*types.StateSyncData, 0)
|
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
|
||||||
|
|
@ -1087,15 +1090,17 @@ func (c *Bor) CommitStates(
|
||||||
}
|
}
|
||||||
|
|
||||||
totalGas := 0 /// limit on gas for state sync per block
|
totalGas := 0 /// limit on gas for state sync per block
|
||||||
|
|
||||||
chainID := c.chainConfig.ChainID.String()
|
chainID := c.chainConfig.ChainID.String()
|
||||||
|
stateSyncs := make([]*types.StateSyncData, len(eventRecords))
|
||||||
|
|
||||||
|
var gasUsed uint64
|
||||||
|
|
||||||
for _, eventRecord := range eventRecords {
|
for _, eventRecord := range eventRecords {
|
||||||
if eventRecord.ID <= lastStateID {
|
if eventRecord.ID <= lastStateID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
|
||||||
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
|
log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -1109,7 +1114,10 @@ func (c *Bor) CommitStates(
|
||||||
|
|
||||||
stateSyncs = append(stateSyncs, &stateData)
|
stateSyncs = append(stateSyncs, &stateData)
|
||||||
|
|
||||||
gasUsed, err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain)
|
// we expect that this call MUST emit an event, otherwise we wouldn't make a receipt
|
||||||
|
// if the receiver address is not a contract then we'll skip the most of the execution and emitting an event as well
|
||||||
|
// https://github.com/maticnetwork/genesis-contracts/blob/master/contracts/StateReceiver.sol#L27
|
||||||
|
gasUsed, err = c.GenesisContractsClient.CommitState(eventRecord, state, header, chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
package bor
|
package bor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
|
@ -55,11 +57,11 @@ func TestGenesisContractChange(t *testing.T) {
|
||||||
genesis := genspec.MustCommit(db)
|
genesis := genspec.MustCommit(db)
|
||||||
|
|
||||||
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
|
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
config := params.ChainConfig{}
|
config := params.ChainConfig{}
|
||||||
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil, nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
|
addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) {
|
||||||
h := &types.Header{
|
h := &types.Header{
|
||||||
|
|
@ -70,37 +72,37 @@ func TestGenesisContractChange(t *testing.T) {
|
||||||
|
|
||||||
// write state to database
|
// write state to database
|
||||||
root, err := statedb.Commit(false)
|
root, err := statedb.Commit(false)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
|
require.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil))
|
||||||
|
|
||||||
statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
|
statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return root, statedb
|
return root, statedb
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||||
|
|
||||||
root := genesis.Root()
|
root := genesis.Root()
|
||||||
|
|
||||||
// code does not change
|
// code does not change
|
||||||
root, statedb = addBlock(root, 1)
|
root, statedb = addBlock(root, 1)
|
||||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1})
|
||||||
|
|
||||||
// code changes 1st time
|
// code changes 1st time
|
||||||
root, statedb = addBlock(root, 2)
|
root, statedb = addBlock(root, 2)
|
||||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||||
|
|
||||||
// code same as 1st change
|
// code same as 1st change
|
||||||
root, statedb = addBlock(root, 3)
|
root, statedb = addBlock(root, 3)
|
||||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2})
|
||||||
|
|
||||||
// code changes 2nd time
|
// code changes 2nd time
|
||||||
_, statedb = addBlock(root, 4)
|
_, statedb = addBlock(root, 4)
|
||||||
assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})
|
require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3})
|
||||||
|
|
||||||
// make sure balance change DOES NOT take effect
|
// make sure balance change DOES NOT take effect
|
||||||
assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
|
require.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||||
|
|
@ -124,19 +126,64 @@ func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||||
|
|
||||||
// Jaipur NOT enabled and BaseFee not set
|
// Jaipur NOT enabled and BaseFee not set
|
||||||
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
require.Equal(t, hash, hashWithoutBaseFee)
|
||||||
|
|
||||||
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
||||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
||||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
require.Equal(t, hash, hashWithoutBaseFee)
|
||||||
|
|
||||||
h.BaseFee = big.NewInt(2)
|
h.BaseFee = big.NewInt(2)
|
||||||
|
|
||||||
// Jaipur enabled (Jaipur=Header block) and BaseFee set
|
// Jaipur enabled (Jaipur=Header block) and BaseFee set
|
||||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 1})
|
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 1})
|
||||||
assert.Equal(t, hash, hashWithBaseFee)
|
require.Equal(t, hash, hashWithBaseFee)
|
||||||
|
|
||||||
// Jaipur NOT enabled and BaseFee set
|
// Jaipur NOT enabled and BaseFee set
|
||||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
require.Equal(t, hash, hashWithoutBaseFee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCheckpoint can be used for to fetch checkpoint
|
||||||
|
// count and checkpoint for debugging purpose.
|
||||||
|
// Also, this is kept only for local use.
|
||||||
|
func TestCheckpoint(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// TODO: For testing, add heimdall url here
|
||||||
|
h := heimdall.NewHeimdallClient("http://localhost:1317")
|
||||||
|
|
||||||
|
count, err := h.FetchCheckpointCount(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Count:", count)
|
||||||
|
|
||||||
|
checkpoint1, err := h.FetchCheckpoint(ctx, count)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Checkpoint1:", checkpoint1)
|
||||||
|
|
||||||
|
checkpoint2, err := h.FetchCheckpoint(ctx, 10000)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Checkpoint2:", checkpoint2)
|
||||||
|
|
||||||
|
checkpoint3, err := h.FetchCheckpoint(ctx, -1)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Checkpoint3:", checkpoint3)
|
||||||
|
|
||||||
|
if checkpoint3.RootHash != checkpoint1.RootHash {
|
||||||
|
t.Fatal("Invalid root hash")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ func (gc *GenesisContractsClient) CommitState(
|
||||||
|
|
||||||
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
|
func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
|
||||||
blockNr := rpc.BlockNumber(snapshotNumber)
|
blockNr := rpc.BlockNumber(snapshotNumber)
|
||||||
method := "lastStateId"
|
|
||||||
|
const method = "lastStateId"
|
||||||
|
|
||||||
data, err := gc.stateReceiverABI.Pack(method)
|
data, err := gc.stateReceiverABI.Pack(method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type IHeimdallClient interface {
|
type IHeimdallClient interface {
|
||||||
StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error)
|
StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error)
|
||||||
Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error)
|
Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error)
|
||||||
FetchLatestCheckpoint(ctx context.Context) (*checkpoint.Checkpoint, error)
|
FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
||||||
|
FetchCheckpointCount(ctx context.Context) (int64, error)
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,12 @@ type CheckpointResponse struct {
|
||||||
Height string `json:"height"`
|
Height string `json:"height"`
|
||||||
Result Checkpoint `json:"result"`
|
Result Checkpoint `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckpointCount struct {
|
||||||
|
Result int64 `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckpointCountResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result CheckpointCount `json:"result"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -59,7 +59,8 @@ func NewHeimdallClient(urlString string) *HeimdallClient {
|
||||||
const (
|
const (
|
||||||
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
||||||
fetchStateSyncEventsPath = "clerk/event-record/list"
|
fetchStateSyncEventsPath = "clerk/event-record/list"
|
||||||
fetchLatestCheckpoint = "/checkpoints/latest"
|
fetchCheckpoint = "/checkpoints/%s"
|
||||||
|
fetchCheckpointCount = "/checkpoints/count"
|
||||||
|
|
||||||
fetchSpanFormat = "bor/span/%d"
|
fetchSpanFormat = "bor/span/%d"
|
||||||
)
|
)
|
||||||
|
|
@ -115,9 +116,9 @@ func (h *HeimdallClient) Span(ctx context.Context, spanID uint64) (*span.Heimdal
|
||||||
return &response.Result, nil
|
return &response.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchLatestCheckpoint fetches the latest bor submitted checkpoint from heimdall
|
// FetchCheckpoint fetches the checkpoint from heimdall
|
||||||
func (h *HeimdallClient) FetchLatestCheckpoint(ctx context.Context) (*checkpoint.Checkpoint, error) {
|
func (h *HeimdallClient) FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) {
|
||||||
url, err := latestCheckpointURL(h.urlString)
|
url, err := checkpointURL(h.urlString, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +131,21 @@ func (h *HeimdallClient) FetchLatestCheckpoint(ctx context.Context) (*checkpoint
|
||||||
return &response.Result, nil
|
return &response.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchCheckpointCount fetches the checkpoint count from heimdall
|
||||||
|
func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
||||||
|
url, err := checkpointCountURL(h.urlString)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[checkpoint.CheckpointCountResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FetchWithRetry returns data from heimdall with retry
|
// FetchWithRetry returns data from heimdall with retry
|
||||||
func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
||||||
// request data once
|
// request data once
|
||||||
|
|
@ -210,8 +226,19 @@ func stateSyncURL(urlString string, fromID uint64, to int64) (*url.URL, error) {
|
||||||
return makeURL(urlString, fetchStateSyncEventsPath, queryParams)
|
return makeURL(urlString, fetchStateSyncEventsPath, queryParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestCheckpointURL(urlString string) (*url.URL, error) {
|
func checkpointURL(urlString string, number int64) (*url.URL, error) {
|
||||||
return makeURL(urlString, fetchLatestCheckpoint, "")
|
url := ""
|
||||||
|
if number == -1 {
|
||||||
|
url = fmt.Sprintf(fetchCheckpoint, "latest")
|
||||||
|
} else {
|
||||||
|
url = fmt.Sprintf(fetchCheckpoint, fmt.Sprint(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeURL(urlString, url, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkpointCountURL(urlString string) (*url.URL, error) {
|
||||||
|
return makeURL(urlString, fetchCheckpointCount, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
||||||
|
|
@ -251,7 +278,7 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
// get response
|
// get response
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Has
|
||||||
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false)
|
||||||
|
|
||||||
// method
|
// method
|
||||||
method := "getCurrentSpan"
|
const method = "getCurrentSpan"
|
||||||
|
|
||||||
data, err := c.validatorSet.Pack(method)
|
data, err := c.validatorSet.Pack(method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func convertTo32(input []byte) (output [32]byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convert(input []([32]byte)) [][]byte {
|
func convert(input [][32]byte) [][]byte {
|
||||||
output := make([][]byte, 0, len(input))
|
output := make([][]byte, 0, len(input))
|
||||||
|
|
||||||
for _, in := range input {
|
for _, in := range input {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if signer is in validator set
|
// check if signer is in validator set
|
||||||
if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
|
if !snap.ValidatorSet.HasAddress(signer) {
|
||||||
return nil, &UnauthorizedSignerError{number, signer.Bytes()}
|
return nil, &UnauthorizedSignerError{number, signer.Bytes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,18 +201,18 @@ func (s *Snapshot) signers() []common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
// Difficulty returns the difficulty for a particular signer at the current snapshot number
|
||||||
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
|
func Difficulty(validatorSet *valset.ValidatorSet, signer common.Address) uint64 {
|
||||||
// if signer is empty
|
// if signer is empty
|
||||||
if signer == (common.Address{}) {
|
if signer == (common.Address{}) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
validators := s.ValidatorSet.Validators
|
validators := validatorSet.Validators
|
||||||
proposer := s.ValidatorSet.GetProposer().Address
|
proposer := validatorSet.GetProposer().Address
|
||||||
totalValidators := len(validators)
|
totalValidators := len(validators)
|
||||||
|
|
||||||
proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
|
proposerIndex, _ := validatorSet.GetByAddress(proposer)
|
||||||
signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
|
signerIndex, _ := validatorSet.GetByAddress(signer)
|
||||||
|
|
||||||
// temp index
|
// temp index
|
||||||
tempIndex := signerIndex
|
tempIndex := signerIndex
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
"pgregory.net/rapid"
|
"pgregory.net/rapid"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -34,7 +34,7 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, 0, successionNumber)
|
require.Equal(t, 0, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
|
|
@ -60,7 +60,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex-proposerIndex, successionNumber)
|
require.Equal(t, signerIndex-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
|
|
@ -82,7 +82,7 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
require.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
|
|
@ -93,6 +93,8 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
ValidatorSet: valset.NewValidatorSet(validators),
|
ValidatorSet: valset.NewValidatorSet(validators),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require.Len(t, snap.ValidatorSet.Validators, numVals)
|
||||||
|
|
||||||
dummyProposerAddress := randomAddress()
|
dummyProposerAddress := randomAddress()
|
||||||
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress}
|
||||||
|
|
||||||
|
|
@ -100,11 +102,11 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
|
||||||
signer := snap.ValidatorSet.Validators[3].Address
|
signer := snap.ValidatorSet.Validators[3].Address
|
||||||
|
|
||||||
_, err := snap.GetSignerSuccessionNumber(signer)
|
_, err := snap.GetSignerSuccessionNumber(signer)
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
|
|
||||||
e, ok := err.(*UnauthorizedProposerError)
|
e, ok := err.(*UnauthorizedProposerError)
|
||||||
assert.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
require.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
|
|
@ -116,10 +118,10 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
|
||||||
}
|
}
|
||||||
dummySignerAddress := randomAddress()
|
dummySignerAddress := randomAddress()
|
||||||
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
e, ok := err.(*UnauthorizedSignerError)
|
e, ok := err.(*UnauthorizedSignerError)
|
||||||
assert.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
require.Equal(t, dummySignerAddress.Bytes(), e.Signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
|
|
|
||||||
|
|
@ -47,21 +47,26 @@ func (v *Validator) Cmp(other *Validator) *Validator {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint:nestif
|
|
||||||
if v.ProposerPriority > other.ProposerPriority {
|
if v.ProposerPriority > other.ProposerPriority {
|
||||||
return v
|
return v
|
||||||
} else if v.ProposerPriority < other.ProposerPriority {
|
|
||||||
return other
|
|
||||||
} else {
|
|
||||||
result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes())
|
|
||||||
if result < 0 {
|
|
||||||
return v
|
|
||||||
} else if result > 0 {
|
|
||||||
return other
|
|
||||||
} else {
|
|
||||||
panic("Cannot compare identical validators")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v.ProposerPriority < other.ProposerPriority {
|
||||||
|
return other
|
||||||
|
}
|
||||||
|
|
||||||
|
result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes())
|
||||||
|
|
||||||
|
if result == 0 {
|
||||||
|
panic("Cannot compare identical validators")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result < 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// result > 0
|
||||||
|
return other
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) String() string {
|
func (v *Validator) String() string {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ type ValidatorSet struct {
|
||||||
|
|
||||||
// cached (unexported)
|
// cached (unexported)
|
||||||
totalVotingPower int64
|
totalVotingPower int64
|
||||||
|
validatorsMap map[common.Address]int // address -> index
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidatorSet initializes a ValidatorSet by copying over the
|
// NewValidatorSet initializes a ValidatorSet by copying over the
|
||||||
|
|
@ -54,7 +55,7 @@ type ValidatorSet struct {
|
||||||
// The addresses of validators in `valz` must be unique otherwise the
|
// The addresses of validators in `valz` must be unique otherwise the
|
||||||
// function panics.
|
// function panics.
|
||||||
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
func NewValidatorSet(valz []*Validator) *ValidatorSet {
|
||||||
vals := &ValidatorSet{}
|
vals := &ValidatorSet{validatorsMap: make(map[common.Address]int)}
|
||||||
|
|
||||||
err := vals.updateWithChangeSet(valz, false)
|
err := vals.updateWithChangeSet(valz, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -232,30 +233,34 @@ func validatorListCopy(valsList []*Validator) []*Validator {
|
||||||
|
|
||||||
// Copy each validator into a new ValidatorSet.
|
// Copy each validator into a new ValidatorSet.
|
||||||
func (vals *ValidatorSet) Copy() *ValidatorSet {
|
func (vals *ValidatorSet) Copy() *ValidatorSet {
|
||||||
|
valCopy := validatorListCopy(vals.Validators)
|
||||||
|
validatorsMap := make(map[common.Address]int, len(vals.Validators))
|
||||||
|
|
||||||
|
for i, val := range valCopy {
|
||||||
|
validatorsMap[val.Address] = i
|
||||||
|
}
|
||||||
|
|
||||||
return &ValidatorSet{
|
return &ValidatorSet{
|
||||||
Validators: validatorListCopy(vals.Validators),
|
Validators: validatorListCopy(vals.Validators),
|
||||||
Proposer: vals.Proposer,
|
Proposer: vals.Proposer,
|
||||||
totalVotingPower: vals.totalVotingPower,
|
totalVotingPower: vals.totalVotingPower,
|
||||||
|
validatorsMap: validatorsMap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasAddress returns true if address given is in the validator set, false -
|
// HasAddress returns true if address given is in the validator set, false -
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func (vals *ValidatorSet) HasAddress(address []byte) bool {
|
func (vals *ValidatorSet) HasAddress(address common.Address) bool {
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
_, ok := vals.validatorsMap[address]
|
||||||
return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0
|
|
||||||
})
|
|
||||||
|
|
||||||
return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address)
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByAddress returns an index of the validator with address and validator
|
// GetByAddress returns an index of the validator with address and validator
|
||||||
// itself if found. Otherwise, -1 and nil are returned.
|
// itself if found. Otherwise, -1 and nil are returned.
|
||||||
func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) {
|
func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) {
|
||||||
idx := sort.Search(len(vals.Validators), func(i int) bool {
|
idx, ok := vals.validatorsMap[address]
|
||||||
return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0
|
if ok {
|
||||||
})
|
|
||||||
if idx < len(vals.Validators) && vals.Validators[idx].Address == address {
|
|
||||||
return idx, vals.Validators[idx].Copy()
|
return idx, vals.Validators[idx].Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,14 +270,14 @@ func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *
|
||||||
// GetByIndex returns the validator's address and validator itself by index.
|
// GetByIndex returns the validator's address and validator itself by index.
|
||||||
// It returns nil values if index is less than 0 or greater or equal to
|
// It returns nil values if index is less than 0 or greater or equal to
|
||||||
// len(ValidatorSet.Validators).
|
// len(ValidatorSet.Validators).
|
||||||
func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
|
func (vals *ValidatorSet) GetByIndex(index int) (address common.Address, val *Validator) {
|
||||||
if index < 0 || index >= len(vals.Validators) {
|
if index < 0 || index >= len(vals.Validators) {
|
||||||
return nil, nil
|
return common.Address{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
val = vals.Validators[index]
|
val = vals.Validators[index]
|
||||||
|
|
||||||
return val.Address.Bytes(), val.Copy()
|
return val.Address, val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the length of the validator set.
|
// Size returns the length of the validator set.
|
||||||
|
|
@ -328,7 +333,7 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
|
||||||
func (vals *ValidatorSet) findProposer() *Validator {
|
func (vals *ValidatorSet) findProposer() *Validator {
|
||||||
var proposer *Validator
|
var proposer *Validator
|
||||||
for _, val := range vals.Validators {
|
for _, val := range vals.Validators {
|
||||||
if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) {
|
if proposer == nil || val.Address != proposer.Address {
|
||||||
proposer = proposer.Cmp(val)
|
proposer = proposer.Cmp(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -371,14 +376,19 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e
|
||||||
changes := validatorListCopy(origChanges)
|
changes := validatorListCopy(origChanges)
|
||||||
sort.Sort(ValidatorsByAddress(changes))
|
sort.Sort(ValidatorsByAddress(changes))
|
||||||
|
|
||||||
removals = make([]*Validator, 0, len(changes))
|
sliceCap := len(changes) / 2
|
||||||
updates = make([]*Validator, 0, len(changes))
|
if sliceCap == 0 {
|
||||||
|
sliceCap = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
removals = make([]*Validator, 0, sliceCap)
|
||||||
|
updates = make([]*Validator, 0, sliceCap)
|
||||||
|
|
||||||
var prevAddr common.Address
|
var prevAddr common.Address
|
||||||
|
|
||||||
// Scan changes by address and append valid validators to updates or removals lists.
|
// Scan changes by address and append valid validators to updates or removals lists.
|
||||||
for _, valUpdate := range changes {
|
for _, valUpdate := range changes {
|
||||||
if bytes.Equal(valUpdate.Address.Bytes(), prevAddr.Bytes()) {
|
if valUpdate.Address == prevAddr {
|
||||||
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -489,10 +499,11 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
} else {
|
} else {
|
||||||
// Apply add or update.
|
// Apply add or update.
|
||||||
merged[i] = updates[0]
|
merged[i] = updates[0]
|
||||||
if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) {
|
if existing[0].Address == updates[0].Address {
|
||||||
// Validator is present in both, advance existing.
|
// Validator is present in both, advance existing.
|
||||||
existing = existing[1:]
|
existing = existing[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
updates = updates[1:]
|
updates = updates[1:]
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
|
|
@ -503,6 +514,7 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) {
|
||||||
merged[i] = existing[j]
|
merged[i] = existing[j]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
// OR add updates which are left.
|
// OR add updates which are left.
|
||||||
for j := 0; j < len(updates); j++ {
|
for j := 0; j < len(updates); j++ {
|
||||||
merged[i] = updates[j]
|
merged[i] = updates[j]
|
||||||
|
|
@ -541,7 +553,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) {
|
||||||
|
|
||||||
// Loop over deletes until we removed all of them.
|
// Loop over deletes until we removed all of them.
|
||||||
for len(deletes) > 0 {
|
for len(deletes) > 0 {
|
||||||
if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) {
|
if existing[0].Address == deletes[0].Address {
|
||||||
deletes = deletes[1:]
|
deletes = deletes[1:]
|
||||||
} else { // Leave it in the resulting slice.
|
} else { // Leave it in the resulting slice.
|
||||||
merged[i] = existing[0]
|
merged[i] = existing[0]
|
||||||
|
|
@ -599,8 +611,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
||||||
computeNewPriorities(updates, vals, updatedTotalVotingPower)
|
computeNewPriorities(updates, vals, updatedTotalVotingPower)
|
||||||
|
|
||||||
// Apply updates and removals.
|
// Apply updates and removals.
|
||||||
vals.applyUpdates(updates)
|
vals.updateValidators(updates, deletes)
|
||||||
vals.applyRemovals(deletes)
|
|
||||||
|
|
||||||
if err := vals.UpdateTotalVotingPower(); err != nil {
|
if err := vals.UpdateTotalVotingPower(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -613,6 +624,17 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Validator) {
|
||||||
|
vals.applyUpdates(updates)
|
||||||
|
vals.applyRemovals(deletes)
|
||||||
|
|
||||||
|
vals.validatorsMap = make(map[common.Address]int, len(vals.Validators))
|
||||||
|
|
||||||
|
for i, val := range vals.Validators {
|
||||||
|
vals.validatorsMap[val.Address] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateWithChangeSet attempts to update the validator set with 'changes'.
|
// UpdateWithChangeSet attempts to update the validator set with 'changes'.
|
||||||
// It performs the following steps:
|
// It performs the following steps:
|
||||||
// - validates the changes making sure there are no duplicates and splits them in updates and deletes
|
// - validates the changes making sure there are no duplicates and splits them in updates and deletes
|
||||||
|
|
@ -661,7 +683,7 @@ func (vals *ValidatorSet) StringIndented(indent string) string {
|
||||||
return "nil-ValidatorSet"
|
return "nil-ValidatorSet"
|
||||||
}
|
}
|
||||||
|
|
||||||
var valStrings []string
|
valStrings := make([]string, 0, len(vals.Validators))
|
||||||
|
|
||||||
vals.Iterate(func(index int, val *Validator) bool {
|
vals.Iterate(func(index int, val *Validator) bool {
|
||||||
valStrings = append(valStrings, val.String())
|
valStrings = append(valStrings, val.String())
|
||||||
|
|
|
||||||
199
consensus/bor/valset/validator_set_test.go
Normal file
199
consensus/bor/valset/validator_set_test.go
Normal file
|
|
@ -0,0 +1,199 @@
|
||||||
|
package valset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewValidatorFromKey(key string, votingPower int64) *Validator {
|
||||||
|
privKey, _ := crypto.HexToECDSA(key)
|
||||||
|
|
||||||
|
return NewValidator(crypto.PubkeyToAddress(privKey.PublicKey), votingPower)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetValidators() [4]*Validator {
|
||||||
|
const (
|
||||||
|
// addr0 = 0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a
|
||||||
|
signer0 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
||||||
|
|
||||||
|
// addr1 = 0x98925BE497f6dFF6A5a33dDA8B5933cA35262d69
|
||||||
|
signer1 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd8"
|
||||||
|
|
||||||
|
//addr2 = 0x648Cf2A5b119E2c04061021834F8f75735B1D36b
|
||||||
|
signer2 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd7"
|
||||||
|
|
||||||
|
//addr3 = 0x168f220B3b313D456eD4797520eFdFA9c57E6C45
|
||||||
|
signer3 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd6"
|
||||||
|
)
|
||||||
|
|
||||||
|
return [4]*Validator{
|
||||||
|
NewValidatorFromKey(signer0, 100),
|
||||||
|
NewValidatorFromKey(signer1, 200),
|
||||||
|
NewValidatorFromKey(signer2, 300),
|
||||||
|
NewValidatorFromKey(signer3, 400),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIncrementProposerPriority(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
vals := GetValidators()
|
||||||
|
|
||||||
|
// Validator set length = 1
|
||||||
|
valSet := NewValidatorSet(vals[:1])
|
||||||
|
|
||||||
|
expectedPropsers := []*Validator{vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0]}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
valSet.IncrementProposerPriority(1)
|
||||||
|
|
||||||
|
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 2
|
||||||
|
valSet = NewValidatorSet(vals[:2])
|
||||||
|
|
||||||
|
expectedPropsers = []*Validator{vals[0], vals[1], vals[1], vals[0], vals[1], vals[1], vals[0], vals[1], vals[1], vals[0]}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
valSet.IncrementProposerPriority(1)
|
||||||
|
|
||||||
|
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 3
|
||||||
|
valSet = NewValidatorSet(vals[:3])
|
||||||
|
|
||||||
|
expectedPropsers = []*Validator{vals[1], vals[2], vals[0], vals[1], vals[2], vals[2], vals[1], vals[2], vals[0], vals[1]}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
valSet.IncrementProposerPriority(1)
|
||||||
|
|
||||||
|
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 4
|
||||||
|
valSet = NewValidatorSet(vals[:4])
|
||||||
|
|
||||||
|
expectedPropsers = []*Validator{vals[2], vals[1], vals[3], vals[2], vals[0], vals[3], vals[1], vals[2], vals[3], vals[3]}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
valSet.IncrementProposerPriority(1)
|
||||||
|
|
||||||
|
require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRescalePriorities(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
vals := GetValidators()
|
||||||
|
|
||||||
|
// Validator set length = 1
|
||||||
|
valSet := NewValidatorSet(vals[:1])
|
||||||
|
|
||||||
|
valSet.RescalePriorities(10)
|
||||||
|
|
||||||
|
expectedPriorities := []int64{0}
|
||||||
|
for i, val := range valSet.Validators {
|
||||||
|
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 2
|
||||||
|
|
||||||
|
valSet = NewValidatorSet(vals[:2])
|
||||||
|
|
||||||
|
valSet.RescalePriorities(100)
|
||||||
|
|
||||||
|
expectedPriorities = []int64{50, -50}
|
||||||
|
for i, val := range valSet.Validators {
|
||||||
|
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 3
|
||||||
|
|
||||||
|
valSet = NewValidatorSet(vals[:3])
|
||||||
|
|
||||||
|
valSet.RescalePriorities(30)
|
||||||
|
|
||||||
|
expectedPriorities = []int64{-17, 5, 11}
|
||||||
|
for i, val := range valSet.Validators {
|
||||||
|
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator set length = 4
|
||||||
|
|
||||||
|
valSet = NewValidatorSet(vals[:4])
|
||||||
|
|
||||||
|
valSet.RescalePriorities(10)
|
||||||
|
|
||||||
|
expectedPriorities = []int64{-6, 3, 1, 2}
|
||||||
|
for i, val := range valSet.Validators {
|
||||||
|
require.Equal(t, expectedPriorities[i], val.ProposerPriority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetValidatorByAddressAndIndex(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
vals := GetValidators()
|
||||||
|
valSet := NewValidatorSet(vals[:4])
|
||||||
|
|
||||||
|
for _, val := range valSet.Validators {
|
||||||
|
idx, valByAddress := valSet.GetByAddress(val.Address)
|
||||||
|
addr, valByIndex := valSet.GetByIndex(idx)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, val, valByIndex)
|
||||||
|
assert.DeepEqual(t, val, valByAddress)
|
||||||
|
assert.DeepEqual(t, val.Address, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tempAddress := common.HexToAddress("0x12345")
|
||||||
|
|
||||||
|
// Negative Testcase
|
||||||
|
idx, _ := valSet.GetByAddress(tempAddress)
|
||||||
|
require.Equal(t, idx, -1)
|
||||||
|
|
||||||
|
// checking for validator index out of range
|
||||||
|
addr, _ := valSet.GetByIndex(100)
|
||||||
|
require.Equal(t, addr, common.Address{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateWithChangeSet(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
vals := GetValidators()
|
||||||
|
valSet := NewValidatorSet(vals[:4])
|
||||||
|
|
||||||
|
// halved the power of vals[2] and doubled the power of vals[3]
|
||||||
|
vals[2].VotingPower = 150
|
||||||
|
vals[3].VotingPower = 800
|
||||||
|
|
||||||
|
// Adding new temp validator in the set
|
||||||
|
const tempSigner = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5"
|
||||||
|
|
||||||
|
tempVal := NewValidatorFromKey(tempSigner, 250)
|
||||||
|
|
||||||
|
// check totalVotingPower before updating validator set
|
||||||
|
require.Equal(t, int64(1000), valSet.TotalVotingPower())
|
||||||
|
|
||||||
|
err := valSet.UpdateWithChangeSet([]*Validator{vals[2], vals[3], tempVal})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// check totalVotingPower after updating validator set
|
||||||
|
require.Equal(t, int64(1500), valSet.TotalVotingPower())
|
||||||
|
|
||||||
|
_, updatedVal2 := valSet.GetByAddress(vals[2].Address)
|
||||||
|
require.Equal(t, int64(150), updatedVal2.VotingPower)
|
||||||
|
|
||||||
|
_, updatedVal3 := valSet.GetByAddress(vals[3].Address)
|
||||||
|
require.Equal(t, int64(800), updatedVal3.VotingPower)
|
||||||
|
|
||||||
|
_, updatedTempVal := valSet.GetByAddress(tempVal.Address)
|
||||||
|
require.Equal(t, int64(250), updatedTempVal.VotingPower)
|
||||||
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
genesis := genspec.MustCommit(db)
|
genesis := genspec.MustCommit(db)
|
||||||
|
|
||||||
// Generate a batch of blocks, each properly signed
|
// Generate a batch of blocks, each properly signed
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
||||||
|
|
@ -89,7 +89,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
genspec.MustCommit(db)
|
genspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
||||||
|
|
@ -102,7 +102,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
// Simulate a crash by creating a new chain on top of the database, without
|
// Simulate a crash by creating a new chain on top of the database, without
|
||||||
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
||||||
// reimport.
|
// reimport.
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -450,7 +450,7 @@ func TestClique(t *testing.T) {
|
||||||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||||
}
|
}
|
||||||
// Pass all the headers through clique and ensure tallying succeeds
|
// Pass all the headers through clique and ensure tallying succeeds
|
||||||
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -317,7 +317,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ func TestHeaderVerification(t *testing.T) {
|
||||||
headers[i] = block.Header()
|
headers[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
|
@ -168,7 +168,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
||||||
t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob))
|
t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob))
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Verify the blocks before the merging
|
// Verify the blocks before the merging
|
||||||
|
|
@ -279,11 +279,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
||||||
var results <-chan error
|
var results <-chan error
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
} else {
|
} else {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil, nil)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +346,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
||||||
defer runtime.GOMAXPROCS(old)
|
defer runtime.GOMAXPROCS(old)
|
||||||
|
|
||||||
// Start the verifications and immediately abort
|
// Start the verifications and immediately abort
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
|
|
@ -38,6 +39,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader/whitelist"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/internal/syncx"
|
"github.com/ethereum/go-ethereum/internal/syncx"
|
||||||
|
|
@ -221,7 +223,8 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator
|
// available in the database. It initialises the default Ethereum Validator
|
||||||
// and Processor.
|
// and Processor.
|
||||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
//nolint:gocognit
|
||||||
|
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64, checker ethereum.ChainValidator) (*BlockChain, error) {
|
||||||
if cacheConfig == nil {
|
if cacheConfig == nil {
|
||||||
cacheConfig = DefaultCacheConfig
|
cacheConfig = DefaultCacheConfig
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +260,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
|
|
||||||
borReceiptsCache: borReceiptsCache,
|
borReceiptsCache: borReceiptsCache,
|
||||||
}
|
}
|
||||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
bc.forker = NewForkChoice(bc, shouldPreserve, checker)
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
||||||
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
||||||
|
|
@ -908,6 +911,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
ancientBlocks, liveBlocks types.Blocks
|
ancientBlocks, liveBlocks types.Blocks
|
||||||
ancientReceipts, liveReceipts []types.Receipts
|
ancientReceipts, liveReceipts []types.Receipts
|
||||||
)
|
)
|
||||||
|
|
||||||
// Do a sanity check that the provided chain is actually ordered and linked
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
for i := 0; i < len(blockChain); i++ {
|
for i := 0; i < len(blockChain); i++ {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
|
|
@ -933,7 +937,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
|
|
||||||
// updateHead updates the head fast sync block if the inserted blocks are better
|
// updateHead updates the head fast sync block if the inserted blocks are better
|
||||||
// and returns an indicator whether the inserted blocks are canonical.
|
// and returns an indicator whether the inserted blocks are canonical.
|
||||||
updateHead := func(head *types.Block) bool {
|
updateHead := func(head *types.Block, headers []*types.Header) bool {
|
||||||
if !bc.chainmu.TryLock() {
|
if !bc.chainmu.TryLock() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -948,6 +952,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
} else if !reorg {
|
} else if !reorg {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValid, err := bc.forker.ValidateReorg(bc.CurrentFastBlock().Header(), headers)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Reorg failed", "err", err)
|
||||||
|
return false
|
||||||
|
} else if !isValid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
||||||
bc.currentFastBlock.Store(head)
|
bc.currentFastBlock.Store(head)
|
||||||
headFastBlockGauge.Update(int64(head.NumberU64()))
|
headFastBlockGauge.Update(int64(head.NumberU64()))
|
||||||
|
|
@ -985,10 +997,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
return 0, fmt.Errorf("containing header #%d [%x..] unknown", last.Number(), last.Hash().Bytes()[:4])
|
return 0, fmt.Errorf("containing header #%d [%x..] unknown", last.Number(), last.Hash().Bytes()[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOR: Retrieve all the bor receipts.
|
// BOR: Retrieve all the bor receipts and also maintain the array of headers
|
||||||
|
// for bor specific reorg check.
|
||||||
borReceipts := []types.Receipts{}
|
borReceipts := []types.Receipts{}
|
||||||
|
|
||||||
|
var headers []*types.Header
|
||||||
for _, block := range blockChain {
|
for _, block := range blockChain {
|
||||||
borReceipts = append(borReceipts, []*types.Receipt{bc.GetBorReceiptByHash(block.Hash())})
|
borReceipts = append(borReceipts, []*types.Receipt{bc.GetBorReceiptByHash(block.Hash())})
|
||||||
|
headers = append(headers, block.Header())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all chain data to ancients.
|
// Write all chain data to ancients.
|
||||||
|
|
@ -1039,7 +1055,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
}
|
}
|
||||||
// Update the current fast block because all block data is now present in DB.
|
// Update the current fast block because all block data is now present in DB.
|
||||||
previousFastBlock := bc.CurrentFastBlock().NumberU64()
|
previousFastBlock := bc.CurrentFastBlock().NumberU64()
|
||||||
if !updateHead(blockChain[len(blockChain)-1]) {
|
if !updateHead(blockChain[len(blockChain)-1], headers) {
|
||||||
// We end up here if the header chain has reorg'ed, and the blocks/receipts
|
// We end up here if the header chain has reorg'ed, and the blocks/receipts
|
||||||
// don't match the canonical chain.
|
// don't match the canonical chain.
|
||||||
if err := bc.db.TruncateHead(previousFastBlock + 1); err != nil {
|
if err := bc.db.TruncateHead(previousFastBlock + 1); err != nil {
|
||||||
|
|
@ -1075,7 +1091,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
writeLive := func(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
writeLive := func(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
||||||
skipPresenceCheck := false
|
skipPresenceCheck := false
|
||||||
batch := bc.db.NewBatch()
|
batch := bc.db.NewBatch()
|
||||||
|
headers := make([]*types.Header, 0, len(blockChain))
|
||||||
for i, block := range blockChain {
|
for i, block := range blockChain {
|
||||||
|
// Update the headers for bor specific reorg check
|
||||||
|
headers = append(headers, block.Header())
|
||||||
|
|
||||||
// Short circuit insertion if shutting down or processing failed
|
// Short circuit insertion if shutting down or processing failed
|
||||||
if bc.insertStopped() {
|
if bc.insertStopped() {
|
||||||
return 0, errInsertionInterrupted
|
return 0, errInsertionInterrupted
|
||||||
|
|
@ -1122,7 +1142,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateHead(blockChain[len(blockChain)-1])
|
|
||||||
|
updateHead(blockChain[len(blockChain)-1], headers)
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1491,6 +1512,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
||||||
it := newInsertIterator(chain, results, bc.validator)
|
it := newInsertIterator(chain, results, bc.validator)
|
||||||
block, err := it.next()
|
block, err := it.next()
|
||||||
|
|
||||||
|
// Check the validity of incoming chain
|
||||||
|
isValid, err1 := bc.forker.ValidateReorg(bc.CurrentBlock().Header(), headers)
|
||||||
|
if err1 != nil {
|
||||||
|
return it.index, err1
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValid {
|
||||||
|
// The chain to be imported is invalid as the blocks doesn't match with
|
||||||
|
// the whitelisted checkpoints.
|
||||||
|
return it.index, whitelist.ErrCheckpointMismatch
|
||||||
|
}
|
||||||
|
|
||||||
// Left-trim all the known blocks that don't need to build snapshot
|
// Left-trim all the known blocks that don't need to build snapshot
|
||||||
if bc.skipBlock(err, it) {
|
if bc.skipBlock(err, it) {
|
||||||
// First block (and state) is known
|
// First block (and state) is known
|
||||||
|
|
@ -1833,6 +1866,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||||
externTd *big.Int
|
externTd *big.Int
|
||||||
lastBlock = block
|
lastBlock = block
|
||||||
current = bc.CurrentBlock()
|
current = bc.CurrentBlock()
|
||||||
|
headers []*types.Header
|
||||||
)
|
)
|
||||||
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
||||||
// Since we don't import them here, we expect ErrUnknownAncestor for the remaining
|
// Since we don't import them here, we expect ErrUnknownAncestor for the remaining
|
||||||
|
|
@ -1840,6 +1874,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||||
// to disk.
|
// to disk.
|
||||||
err := consensus.ErrPrunedAncestor
|
err := consensus.ErrPrunedAncestor
|
||||||
for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() {
|
for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() {
|
||||||
|
headers = append(headers, block.Header())
|
||||||
// Check the canonical state root for that number
|
// Check the canonical state root for that number
|
||||||
if number := block.NumberU64(); current.NumberU64() >= number {
|
if number := block.NumberU64(); current.NumberU64() >= number {
|
||||||
canonical := bc.GetBlockByNumber(number)
|
canonical := bc.GetBlockByNumber(number)
|
||||||
|
|
@ -1895,7 +1930,13 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
if !reorg {
|
|
||||||
|
isValid, err := bc.forker.ValidateReorg(current.Header(), headers)
|
||||||
|
if err != nil {
|
||||||
|
return it.index, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reorg || !isValid {
|
||||||
localTd := bc.GetTd(current.Hash(), current.NumberU64())
|
localTd := bc.GetTd(current.Hash(), current.NumberU64())
|
||||||
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
|
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
|
||||||
return it.index, err
|
return it.index, err
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestChain2HeadEvent(t *testing.T) {
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
chain2HeadCh := make(chan Chain2HeadEvent, 64)
|
chain2HeadCh := make(chan Chain2HeadEvent, 64)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize a fresh chain with only a genesis block
|
// Initialize a fresh chain with only a genesis block
|
||||||
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
@ -655,7 +655,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
blockchain.Stop()
|
blockchain.Stop()
|
||||||
|
|
||||||
// Create a new BlockChain and check that it rolled back the state.
|
// Create a new BlockChain and check that it rolled back the state.
|
||||||
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -768,7 +768,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := rawdb.NewMemoryDatabase()
|
archiveDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer archive.Stop()
|
defer archive.Stop()
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
|
|
@ -777,7 +777,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := rawdb.NewMemoryDatabase()
|
fastDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -801,7 +801,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -923,7 +923,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
archiveCaching := *DefaultCacheConfig
|
archiveCaching := *DefaultCacheConfig
|
||||||
archiveCaching.TrieDirtyDisabled = true
|
archiveCaching.TrieDirtyDisabled = true
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -936,7 +936,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb, delfn := makeDb()
|
fastDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -956,7 +957,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||||
ancientDb, delfn := makeDb()
|
ancientDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -975,7 +977,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a light node and ensure all pointers are updated
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb, delfn := makeDb()
|
lightDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -1044,7 +1047,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -1114,7 +1117,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
rmLogsCh := make(chan RemovedLogsEvent)
|
||||||
|
|
@ -1167,7 +1170,7 @@ func TestLogRebirth(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
engine = ethash.NewFaker()
|
engine = ethash.NewFaker()
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
@ -1230,7 +1233,7 @@ func TestSideLogRebirth(t *testing.T) {
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
@ -1305,7 +1308,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -1437,7 +1440,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1545,7 +1548,8 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1620,7 +1624,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1664,7 +1668,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1703,7 +1707,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1764,7 +1768,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -1784,7 +1788,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
||||||
|
|
||||||
// Reopen broken blockchain again
|
// Reopen broken blockchain again
|
||||||
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
||||||
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
||||||
|
|
@ -1836,7 +1840,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||||
}
|
}
|
||||||
gspec := Genesis{Config: params.AllEthashProtocolChanges}
|
gspec := Genesis{Config: params.AllEthashProtocolChanges}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer ancientChain.Stop()
|
defer ancientChain.Stop()
|
||||||
|
|
||||||
// Import the canonical header chain.
|
// Import the canonical header chain.
|
||||||
|
|
@ -1897,7 +1901,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1963,7 +1967,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
// Generate and import the canonical chain
|
// Generate and import the canonical chain
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
chain, err := NewBlockChain(diskdb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2102,7 +2106,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2266,7 +2270,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
chain, err := NewBlockChain(chaindb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(chaindb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2384,7 +2388,7 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2577,7 +2581,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
|
|
||||||
// Import all blocks into ancient db
|
// Import all blocks into ancient db
|
||||||
l := uint64(0)
|
l := uint64(0)
|
||||||
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2602,7 +2606,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2626,7 +2630,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */}
|
limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */}
|
||||||
tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0}
|
tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0}
|
||||||
for i, l := range limit {
|
for i, l := range limit {
|
||||||
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2704,7 +2708,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) {
|
||||||
|
|
||||||
// Import all blocks into ancient db, only HEAD-32 indices are kept.
|
// Import all blocks into ancient db, only HEAD-32 indices are kept.
|
||||||
l := uint64(32)
|
l := uint64(32)
|
||||||
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2768,7 +2772,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to create tester chain: %v", err)
|
b.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2851,7 +2855,7 @@ func TestSideImportPrunedBlocks(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2945,7 +2949,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3059,7 +3063,7 @@ func TestDeleteRecreateSlots(t *testing.T) {
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3139,7 +3143,7 @@ func TestDeleteRecreateAccount(t *testing.T) {
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3312,7 +3316,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) {
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3446,7 +3450,7 @@ func TestInitThenFailCreateContract(t *testing.T) {
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3533,7 +3537,7 @@ func TestEIP2718Transition(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3628,7 +3632,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func ExampleGenerateChain() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
proConf.DAOForkBlock = forkBlock
|
proConf.DAOForkBlock = forkBlock
|
||||||
proConf.DAOForkSupport = true
|
proConf.DAOForkSupport = true
|
||||||
|
|
||||||
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer proBc.Stop()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := rawdb.NewMemoryDatabase()
|
conDb := rawdb.NewMemoryDatabase()
|
||||||
|
|
@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
conConf.DAOForkBlock = forkBlock
|
conConf.DAOForkBlock = forkBlock
|
||||||
conConf.DAOForkSupport = false
|
conConf.DAOForkSupport = false
|
||||||
|
|
||||||
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer conBc.Stop()
|
defer conBc.Stop()
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
|
|
@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -54,18 +55,21 @@ type ForkChoice struct {
|
||||||
// local td is equal to the extern one. It can be nil for light
|
// local td is equal to the extern one. It can be nil for light
|
||||||
// client
|
// client
|
||||||
preserve func(header *types.Header) bool
|
preserve func(header *types.Header) bool
|
||||||
|
|
||||||
|
validator ethereum.ChainValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice {
|
func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool, validator ethereum.ChainValidator) *ForkChoice {
|
||||||
// Seed a fast but crypto originating random generator
|
// Seed a fast but crypto originating random generator
|
||||||
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to initialize random seed", "err", err)
|
log.Crit("Failed to initialize random seed", "err", err)
|
||||||
}
|
}
|
||||||
return &ForkChoice{
|
return &ForkChoice{
|
||||||
chain: chainReader,
|
chain: chainReader,
|
||||||
rand: mrand.New(mrand.NewSource(seed.Int64())),
|
rand: mrand.New(mrand.NewSource(seed.Int64())), //nolint:gosec
|
||||||
preserve: preserve,
|
preserve: preserve,
|
||||||
|
validator: validator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,3 +110,15 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (b
|
||||||
}
|
}
|
||||||
return reorg, nil
|
return reorg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateReorg calls the chain validator service to check if the reorg is valid or not
|
||||||
|
func (f *ForkChoice) ValidateReorg(current *types.Header, chain []*types.Header) (bool, error) {
|
||||||
|
// Call the bor chain validator service
|
||||||
|
if f.validator != nil {
|
||||||
|
if isValid := f.validator.IsValidChain(current, chain); !isValid {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
240
core/forkchoice_test.go
Normal file
240
core/forkchoice_test.go
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// chainValidatorFake is a mock for the chain validator service
|
||||||
|
type chainValidatorFake struct {
|
||||||
|
validate func(currentHeader *types.Header, chain []*types.Header) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// chainReaderFake is a mock for the chain reader service
|
||||||
|
type chainReaderFake struct {
|
||||||
|
getTd func(hash common.Hash, number uint64) *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChainValidatorFake(validate func(currentHeader *types.Header, chain []*types.Header) bool) *chainValidatorFake {
|
||||||
|
return &chainValidatorFake{validate: validate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChainReaderFake(getTd func(hash common.Hash, number uint64) *big.Int) *chainReaderFake {
|
||||||
|
return &chainReaderFake{getTd: getTd}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPastChainInsert(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
|
)
|
||||||
|
|
||||||
|
hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false })
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create mocks for forker
|
||||||
|
getTd := func(hash common.Hash, number uint64) *big.Int {
|
||||||
|
return big.NewInt(int64(number))
|
||||||
|
}
|
||||||
|
validate := func(currentHeader *types.Header, chain []*types.Header) bool {
|
||||||
|
// Put all explicit conditions here
|
||||||
|
// If canonical chain is empty and we're importing a chain of 64 blocks
|
||||||
|
if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If canonical chain is of len 64 and we're importing a past chain from 54-64, then accept it
|
||||||
|
if currentHeader.Number.Uint64() == uint64(64) && chain[0].Number.Uint64() == 55 && len(chain) == 10 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mockChainReader := newChainReaderFake(getTd)
|
||||||
|
mockChainValidator := newChainValidatorFake(validate)
|
||||||
|
mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator)
|
||||||
|
|
||||||
|
// chain A: G->A1->A2...A64
|
||||||
|
chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 64 headers on an empty chain
|
||||||
|
// expecting 1 write status with no error
|
||||||
|
testInsert(t, hc, chainA, CanonStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain B: G->A1->A2...A44->B45->B46...B64
|
||||||
|
chainB := makeHeaderChain(chainA[43], 20, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain C: G->A1->A2...A54->C55->C56...C64
|
||||||
|
chainC := makeHeaderChain(chainA[53], 10, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Update the function to consider chainC with higher difficulty
|
||||||
|
getTd = func(hash common.Hash, number uint64) *big.Int {
|
||||||
|
td := big.NewInt(int64(number))
|
||||||
|
if hash == chainB[len(chainB)-1].Hash() || hash == chainC[len(chainC)-1].Hash() {
|
||||||
|
td = big.NewInt(65)
|
||||||
|
}
|
||||||
|
|
||||||
|
return td
|
||||||
|
}
|
||||||
|
mockChainReader = newChainReaderFake(getTd)
|
||||||
|
mockForker = NewForkChoice(mockChainReader, nil, mockChainValidator)
|
||||||
|
|
||||||
|
// Inserting 20 blocks from chainC on canonical chain
|
||||||
|
// expecting 2 write status with no error
|
||||||
|
testInsert(t, hc, chainB, SideStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// Inserting 10 blocks from chainB on canonical chain
|
||||||
|
// expecting 1 write status with no error
|
||||||
|
testInsert(t, hc, chainC, CanonStatTy, nil, mockForker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFutureChainInsert(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
|
)
|
||||||
|
|
||||||
|
hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false })
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create mocks for forker
|
||||||
|
getTd := func(hash common.Hash, number uint64) *big.Int {
|
||||||
|
return big.NewInt(int64(number))
|
||||||
|
}
|
||||||
|
validate := func(currentHeader *types.Header, chain []*types.Header) bool {
|
||||||
|
// Put all explicit conditions here
|
||||||
|
// If canonical chain is empty and we're importing a chain of 64 blocks
|
||||||
|
if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If length of future chains > some value, they should not be accepted
|
||||||
|
if currentHeader.Number.Uint64() == uint64(64) && len(chain) <= 10 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mockChainReader := newChainReaderFake(getTd)
|
||||||
|
mockChainValidator := newChainValidatorFake(validate)
|
||||||
|
mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator)
|
||||||
|
|
||||||
|
// chain A: G->A1->A2...A64
|
||||||
|
chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 64 headers on an empty chain
|
||||||
|
// expecting 1 write status with no error
|
||||||
|
testInsert(t, hc, chainA, CanonStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain B: G->A1->A2...A64->B65->B66...B84
|
||||||
|
chainB := makeHeaderChain(chainA[63], 20, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 20 headers on the canonical chain
|
||||||
|
// expecting 0 write status with no error
|
||||||
|
testInsert(t, hc, chainB, SideStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain C: G->A1->A2...A64->C65->C66...C74
|
||||||
|
chainC := makeHeaderChain(chainA[63], 10, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 10 headers on the canonical chain
|
||||||
|
// expecting 0 write status with no error
|
||||||
|
testInsert(t, hc, chainC, CanonStatTy, nil, mockForker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOverlappingChainInsert(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
|
||||||
|
)
|
||||||
|
|
||||||
|
hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false })
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create mocks for forker
|
||||||
|
getTd := func(hash common.Hash, number uint64) *big.Int {
|
||||||
|
return big.NewInt(int64(number))
|
||||||
|
}
|
||||||
|
validate := func(currentHeader *types.Header, chain []*types.Header) bool {
|
||||||
|
// Put all explicit conditions here
|
||||||
|
// If canonical chain is empty and we're importing a chain of 64 blocks
|
||||||
|
if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If length of chain is > some fixed value then don't accept it
|
||||||
|
if currentHeader.Number.Uint64() == uint64(64) && len(chain) <= 20 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mockChainReader := newChainReaderFake(getTd)
|
||||||
|
mockChainValidator := newChainValidatorFake(validate)
|
||||||
|
mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator)
|
||||||
|
|
||||||
|
// chain A: G->A1->A2...A64
|
||||||
|
chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 64 headers on an empty chain
|
||||||
|
// expecting 1 write status with no error
|
||||||
|
testInsert(t, hc, chainA, CanonStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain B: G->A1->A2...A54->B55->B56...B84
|
||||||
|
chainB := makeHeaderChain(chainA[53], 30, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 20 blocks on canonical chain
|
||||||
|
// expecting 2 write status with no error
|
||||||
|
testInsert(t, hc, chainB, SideStatTy, nil, mockForker)
|
||||||
|
|
||||||
|
// The current chain is: G->A1->A2...A64
|
||||||
|
// chain C: G->A1->A2...A54->C55->C56...C74
|
||||||
|
chainC := makeHeaderChain(chainA[53], 20, ethash.NewFaker(), db, 10)
|
||||||
|
|
||||||
|
// Inserting 10 blocks on canonical chain
|
||||||
|
// expecting 1 write status with no error
|
||||||
|
testInsert(t, hc, chainC, CanonStatTy, nil, mockForker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock chain reader functions
|
||||||
|
func (c *chainReaderFake) Config() *params.ChainConfig {
|
||||||
|
return ¶ms.ChainConfig{TerminalTotalDifficulty: nil}
|
||||||
|
}
|
||||||
|
func (c *chainReaderFake) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||||
|
return c.getTd(hash, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock chain validator functions
|
||||||
|
func (w *chainValidatorFake) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) IsValidChain(current *types.Header, headers []*types.Header) bool {
|
||||||
|
return w.validate(current, headers)
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {}
|
||||||
|
func (w *chainValidatorFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) PurgeCheckpointWhitelist() {}
|
||||||
|
func (w *chainValidatorFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||||
|
return map[uint64]*types.Header{}, nil
|
||||||
|
}
|
||||||
|
|
@ -117,7 +117,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
genesis := oldcustomg.MustCommit(db)
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
|
||||||
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,10 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
|
||||||
lastHeader: lastHeader,
|
lastHeader: lastHeader,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ask the fork choicer if the reorg is necessary
|
// Ask the fork choicer if the reorg is necessary
|
||||||
if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
|
reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !reorg {
|
} else if !reorg {
|
||||||
if inserted != 0 {
|
if inserted != 0 {
|
||||||
|
|
@ -292,6 +294,16 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValid, err := forker.ValidateReorg(hc.CurrentHeader(), headers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !isValid {
|
||||||
|
if inserted != 0 {
|
||||||
|
result.status = SideStatTy
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
// Special case, all the inserted headers are already on the canonical
|
// Special case, all the inserted headers are already on the canonical
|
||||||
// header chain, skip the reorg operation.
|
// header chain, skip the reorg operation.
|
||||||
if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
|
if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func TestHeaderInsertion(t *testing.T) {
|
||||||
chainB := makeHeaderChain(chainA[0], 128, ethash.NewFaker(), db, 10)
|
chainB := makeHeaderChain(chainA[0], 128, ethash.NewFaker(), db, 10)
|
||||||
log.Root().SetHandler(log.StdoutHandler)
|
log.Root().SetHandler(log.StdoutHandler)
|
||||||
|
|
||||||
forker := NewForkChoice(hc, nil)
|
forker := NewForkChoice(hc, nil, nil)
|
||||||
// Inserting 64 headers on an empty chain, expecting
|
// Inserting 64 headers on an empty chain, expecting
|
||||||
// 1 callbacks, 1 canon-status, 0 sidestatus,
|
// 1 callbacks, 1 canon-status, 0 sidestatus,
|
||||||
testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker)
|
testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ var (
|
||||||
getDerivedBorTxHash = types.GetDerivedBorTxHash
|
getDerivedBorTxHash = types.GetDerivedBorTxHash
|
||||||
|
|
||||||
// borTxLookupPrefix + hash -> transaction/receipt lookup metadata
|
// borTxLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||||
borTxLookupPrefix = []byte("matic-bor-tx-lookup-")
|
borTxLookupPrefix = []byte(borTxLookupPrefixStr)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
borTxLookupPrefixStr = "matic-bor-tx-lookup-"
|
||||||
|
|
||||||
// freezerBorReceiptTable indicates the name of the freezer bor receipts table.
|
// freezerBorReceiptTable indicates the name of the freezer bor receipts table.
|
||||||
freezerBorReceiptTable = "matic-bor-receipts"
|
freezerBorReceiptTable = "matic-bor-receipts"
|
||||||
|
|
|
||||||
|
|
@ -601,8 +601,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
|
||||||
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
|
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
|
||||||
// a contract does the following:
|
// a contract does the following:
|
||||||
//
|
//
|
||||||
// 1. sends funds to sha(account ++ (nonce + 1))
|
// 1. sends funds to sha(account ++ (nonce + 1))
|
||||||
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
||||||
//
|
//
|
||||||
// Carrying over the balance ensures that Ether doesn't disappear.
|
// Carrying over the balance ensures that Ether doesn't disappear.
|
||||||
func (s *StateDB) CreateAccount(addr common.Address) {
|
func (s *StateDB) CreateAccount(addr common.Address) {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
||||||
|
|
@ -235,7 +235,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
|
@ -275,7 +275,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
|
|
||||||
|
|
@ -1891,7 +1891,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1969,7 +1969,7 @@ func TestIssue23496(t *testing.T) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2024,7 +2024,7 @@ func TestIssue23496(t *testing.T) {
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1987,7 +1987,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
config.SnapshotWait = true
|
config.SnapshotWait = true
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*core.BlockChain, []*type
|
||||||
cacheConfig = core.DefaultCacheConfig
|
cacheConfig = core.DefaultCacheConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -246,7 +246,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||||
// Restart the chain normally
|
// Restart the chain normally
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -283,13 +283,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
// the crash, we do restart twice here: one after the crash and one
|
// the crash, we do restart twice here: one after the crash and one
|
||||||
// after the normal stop. It's used to ensure the broken snapshot
|
// after the normal stop. It's used to ensure the broken snapshot
|
||||||
// can be detected all the time.
|
// can be detected all the time.
|
||||||
newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +327,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -336,7 +336,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain with enabling the snapshot
|
// Restart the chain with enabling the snapshot
|
||||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||||
chain.SetHead(snaptest.setHead)
|
chain.SetHead(snaptest.setHead)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +396,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -414,7 +414,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// journal and latest state will be committed
|
// journal and latest state will be committed
|
||||||
|
|
||||||
// Restart the chain after the crash
|
// Restart the chain after the crash
|
||||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -449,8 +449,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
|
newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -467,14 +466,13 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
SnapshotLimit: 256,
|
SnapshotLimit: 256,
|
||||||
SnapshotWait: false, // Don't wait rebuild
|
SnapshotWait: false, // Don't wait rebuild
|
||||||
}
|
}
|
||||||
|
_, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
_, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
// Simulate the blockchain crash.
|
// Simulate the blockchain crash.
|
||||||
|
|
||||||
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
- ```chain```: Name of the chain to sync
|
- ```chain```: Name of the chain to sync
|
||||||
|
|
||||||
- ```name```: Name/Identity of the node
|
- ```identity```: Name/Identity of the node
|
||||||
|
|
||||||
- ```log-level```: Set log level for the server
|
- ```log-level```: Set log level for the server
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
- ```requiredblocks```: Comma separated block number-to-hash mappings to enforce (<number>=<hash>)
|
- ```requiredblocks```: Comma separated block number-to-hash mappings to enforce (<number>=<hash>)
|
||||||
|
|
||||||
- ```no-snapshot```: Disables the snapshot-database mode (default = false)
|
- ```snapshot```: Disables/Enables the snapshot-database mode (default = true)
|
||||||
|
|
||||||
- ```bor.heimdall```: URL of Heimdall service
|
- ```bor.heimdall```: URL of Heimdall service
|
||||||
|
|
||||||
|
|
@ -88,9 +88,17 @@ The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
- ```ipcpath```: Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
- ```ipcpath```: Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
||||||
|
|
||||||
- ```jsonrpc.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
- ```http.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||||
|
|
||||||
- ```jsonrpc.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
- ```http.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||||
|
|
||||||
|
- ```ws.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||||
|
|
||||||
|
- ```ws.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||||
|
|
||||||
|
- ```graphql.corsdomain```: Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||||
|
|
||||||
|
- ```graphql.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
|
||||||
|
|
||||||
- ```http```: Enable the HTTP-RPC server
|
- ```http```: Enable the HTTP-RPC server
|
||||||
|
|
||||||
|
|
@ -100,7 +108,7 @@ The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
- ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
- ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
||||||
|
|
||||||
- ```http.modules```: API's offered over the HTTP-RPC interface
|
- ```http.api```: API's offered over the HTTP-RPC interface
|
||||||
|
|
||||||
- ```ws```: Enable the WS-RPC server
|
- ```ws```: Enable the WS-RPC server
|
||||||
|
|
||||||
|
|
@ -110,7 +118,7 @@ The ```bor server``` command runs the Bor client.
|
||||||
|
|
||||||
- ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
- ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
|
||||||
|
|
||||||
- ```ws.modules```: API's offered over the WS-RPC interface
|
- ```ws.api```: API's offered over the WS-RPC interface
|
||||||
|
|
||||||
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader/whitelist"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -219,7 +220,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
Preimages: config.Preimages,
|
Preimages: config.Preimages,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit)
|
|
||||||
|
checker := whitelist.NewService(10)
|
||||||
|
|
||||||
|
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, checker)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -260,6 +264,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
Checkpoint: checkpoint,
|
Checkpoint: checkpoint,
|
||||||
EthAPI: ethAPI,
|
EthAPI: ethAPI,
|
||||||
PeerRequiredBlocks: config.PeerRequiredBlocks,
|
PeerRequiredBlocks: config.PeerRequiredBlocks,
|
||||||
|
checker: checker,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -622,6 +627,13 @@ func (s *Ethereum) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNotBorConsensus = errors.New("not bor consensus was given")
|
||||||
|
ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall")
|
||||||
|
|
||||||
|
whitelistTimeout = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the
|
// StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the
|
||||||
// checkpoint whitelist map.
|
// checkpoint whitelist map.
|
||||||
func (s *Ethereum) startCheckpointWhitelistService() {
|
func (s *Ethereum) startCheckpointWhitelistService() {
|
||||||
|
|
@ -633,8 +645,11 @@ func (s *Ethereum) startCheckpointWhitelistService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// first run the checkpoint whitelist
|
// first run the checkpoint whitelist
|
||||||
// TODO: add context timeout if needed
|
firstCtx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
||||||
err := s.handleWhitelistCheckpoint(context.Background())
|
err := s.handleWhitelistCheckpoint(firstCtx, true)
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrBorConsensusWithoutHeimdall) || errors.Is(err, ErrNotBorConsensus) {
|
if errors.Is(err, ErrBorConsensusWithoutHeimdall) || errors.Is(err, ErrNotBorConsensus) {
|
||||||
return
|
return
|
||||||
|
|
@ -649,8 +664,11 @@ func (s *Ethereum) startCheckpointWhitelistService() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
// TODO: add context timeout if needed
|
ctx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
||||||
err = s.handleWhitelistCheckpoint(context.Background())
|
err := s.handleWhitelistCheckpoint(ctx, false)
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("unable to whitelist checkpoint", "err", err)
|
log.Warn("unable to whitelist checkpoint", "err", err)
|
||||||
}
|
}
|
||||||
|
|
@ -660,13 +678,8 @@ func (s *Ethereum) startCheckpointWhitelistService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
ErrNotBorConsensus = errors.New("not bor consensus was given")
|
|
||||||
ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall")
|
|
||||||
)
|
|
||||||
|
|
||||||
// handleWhitelistCheckpoint handles the checkpoint whitelist mechanism.
|
// handleWhitelistCheckpoint handles the checkpoint whitelist mechanism.
|
||||||
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context) error {
|
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, first bool) error {
|
||||||
ethHandler := (*ethHandler)(s.handler)
|
ethHandler := (*ethHandler)(s.handler)
|
||||||
|
|
||||||
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
||||||
|
|
@ -678,13 +691,18 @@ func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context) error {
|
||||||
return ErrBorConsensusWithoutHeimdall
|
return ErrBorConsensusWithoutHeimdall
|
||||||
}
|
}
|
||||||
|
|
||||||
endBlockNum, endBlockHash, err := ethHandler.fetchWhitelistCheckpoint(ctx, bor)
|
blockNums, blockHashes, err := ethHandler.fetchWhitelistCheckpoints(ctx, bor, first)
|
||||||
if err != nil {
|
// If the array is empty, we're bound to receive an error. Non-nill error and non-empty array
|
||||||
|
// means that array has partial elements and it failed for some block. We'll add those partial
|
||||||
|
// elements anyway.
|
||||||
|
if len(blockNums) == 0 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the checkpoint whitelist map.
|
// Update the checkpoint whitelist map.
|
||||||
ethHandler.downloader.ProcessCheckpoint(endBlockNum, endBlockHash)
|
for i := 0; i < len(blockNums); i++ {
|
||||||
|
ethHandler.downloader.ProcessCheckpoint(blockNums[i], blockHashes[i])
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ type Downloader struct {
|
||||||
quitCh chan struct{} // Quit channel to signal termination
|
quitCh chan struct{} // Quit channel to signal termination
|
||||||
quitLock sync.Mutex // Lock to prevent double closes
|
quitLock sync.Mutex // Lock to prevent double closes
|
||||||
|
|
||||||
ChainValidator
|
ethereum.ChainValidator
|
||||||
|
|
||||||
// Testing hooks
|
// Testing hooks
|
||||||
syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run
|
syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run
|
||||||
|
|
@ -153,14 +153,6 @@ type Downloader struct {
|
||||||
chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations)
|
chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations)
|
||||||
}
|
}
|
||||||
|
|
||||||
// interface for whitelist service
|
|
||||||
type ChainValidator interface {
|
|
||||||
IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
|
||||||
ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash)
|
|
||||||
GetCheckpointWhitelist() map[uint64]common.Hash
|
|
||||||
PurgeCheckpointWhitelist()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LightChain encapsulates functions required to synchronise a light chain.
|
// LightChain encapsulates functions required to synchronise a light chain.
|
||||||
type LightChain interface {
|
type LightChain interface {
|
||||||
// HasHeader verifies a header's presence in the local chain.
|
// HasHeader verifies a header's presence in the local chain.
|
||||||
|
|
@ -216,7 +208,7 @@ type BlockChain interface {
|
||||||
|
|
||||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||||
//nolint: staticcheck
|
//nolint: staticcheck
|
||||||
func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ChainValidator) *Downloader {
|
func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ethereum.ChainValidator) *Downloader {
|
||||||
if lightchain == nil {
|
if lightchain == nil {
|
||||||
lightchain = chain
|
lightchain = chain
|
||||||
}
|
}
|
||||||
|
|
@ -799,9 +791,11 @@ func (d *Downloader) getFetchHeadersByNumber(p *peerConnection) func(number uint
|
||||||
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
||||||
// the head links match), we do a binary search to find the common ancestor.
|
// the head links match), we do a binary search to find the common ancestor.
|
||||||
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
||||||
// Check the validity of chain to be downloaded
|
// Check the validity of peer from which the chain is to be downloaded
|
||||||
if _, err := d.IsValidChain(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil {
|
if d.ChainValidator != nil {
|
||||||
return 0, err
|
if _, err := d.IsValidPeer(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out the valid ancestor range to prevent rewrite attacks
|
// Figure out the valid ancestor range to prevent rewrite attacks
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func newTester() *downloadTester {
|
||||||
|
|
||||||
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ func newTester() *downloadTester {
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dl *downloadTester) setWhitelist(w ChainValidator) {
|
func (dl *downloadTester) setWhitelist(w ethereum.ChainValidator) {
|
||||||
dl.downloader.ChainValidator = w
|
dl.downloader.ChainValidator = w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1416,9 +1416,9 @@ func newWhitelistFake(validate func(count int) (bool, error)) *whitelistFake {
|
||||||
return &whitelistFake{0, validate}
|
return &whitelistFake{0, validate}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidChain is the mock function which the downloader will use to validate the chain
|
// IsValidPeer is the mock function which the downloader will use to validate the chain
|
||||||
// to be received from a peer.
|
// to be received from a peer.
|
||||||
func (w *whitelistFake) IsValidChain(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *whitelistFake) IsValidPeer(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
w.count++
|
w.count++
|
||||||
}()
|
}()
|
||||||
|
|
@ -1426,13 +1426,18 @@ func (w *whitelistFake) IsValidChain(_ *types.Header, _ func(number uint64, amou
|
||||||
return w.validate(w.count)
|
return w.validate(w.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *whitelistFake) IsValidChain(current *types.Header, headers []*types.Header) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
||||||
|
|
||||||
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *whitelistFake) PurgeCheckpointWhitelist() {}
|
func (w *whitelistFake) PurgeCheckpointWhitelist() {}
|
||||||
|
func (w *whitelistFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||||
|
return map[uint64]*types.Header{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
||||||
// checkpoint mismatch with opposite peer, the sync should fail.
|
// checkpoint mismatch with opposite peer, the sync should fail.
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain {
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000))
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ type Service struct {
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
checkpointWhitelist map[uint64]common.Hash // Checkpoint whitelist, populated by reaching out to heimdall
|
checkpointWhitelist map[uint64]common.Hash // Checkpoint whitelist, populated by reaching out to heimdall
|
||||||
checkpointOrder []uint64 // Checkpoint order, populated by reaching out to heimdall
|
checkpointOrder []uint64 // Checkpoint order, populated by reaching out to heimdall
|
||||||
maxCapacity uint
|
maxCapacity uint // Max capacity of the whitelist
|
||||||
|
checkpointInterval uint64 // Checkpoint interval, until which we can allow importing
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(maxCapacity uint) *Service {
|
func NewService(maxCapacity uint) *Service {
|
||||||
|
|
@ -23,6 +24,7 @@ func NewService(maxCapacity uint) *Service {
|
||||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
checkpointWhitelist: make(map[uint64]common.Hash),
|
||||||
checkpointOrder: []uint64{},
|
checkpointOrder: []uint64{},
|
||||||
maxCapacity: maxCapacity,
|
maxCapacity: maxCapacity,
|
||||||
|
checkpointInterval: 256, // TODO: make it configurable through params?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,9 +33,9 @@ var (
|
||||||
ErrNoRemoteCheckoint = errors.New("remote peer doesn't have a checkoint")
|
ErrNoRemoteCheckoint = errors.New("remote peer doesn't have a checkoint")
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsValidChain checks if the chain we're about to receive from this peer is valid or not
|
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||||
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain.
|
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain.
|
||||||
func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *Service) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
// We want to validate the chain by comparing the last checkpointed block
|
// We want to validate the chain by comparing the last checkpointed block
|
||||||
// we're storing in `checkpointWhitelist` with the peer's block.
|
// we're storing in `checkpointWhitelist` with the peer's block.
|
||||||
//
|
//
|
||||||
|
|
@ -70,6 +72,84 @@ func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber
|
||||||
return false, ErrCheckpointMismatch
|
return false, ErrCheckpointMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsValidChain checks the validity of chain by comparing it
|
||||||
|
// against the local checkpoint entries
|
||||||
|
func (w *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) bool {
|
||||||
|
// Check if we have checkpoints to validate incoming chain in memory
|
||||||
|
if len(w.checkpointWhitelist) == 0 {
|
||||||
|
// We don't have any entries, no additional validation will be possible
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if we've received empty chain
|
||||||
|
if len(chain) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
oldestCheckpointNumber uint64 = w.checkpointOrder[0]
|
||||||
|
current uint64 = currentHeader.Number.Uint64()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if we have whitelist entries in required range
|
||||||
|
if chain[len(chain)-1].Number.Uint64() < oldestCheckpointNumber {
|
||||||
|
// We have future whitelisted entries, so no additional validation will be possible
|
||||||
|
// This case will occur when bor is in middle of sync, but heimdall is ahead/fully synced.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the chain into past and future chain
|
||||||
|
pastChain, futureChain := splitChain(current, chain)
|
||||||
|
|
||||||
|
// Add an offset to future chain if it's not in continuity
|
||||||
|
offset := 0
|
||||||
|
if len(futureChain) != 0 {
|
||||||
|
offset += int(futureChain[0].Number.Uint64()-currentHeader.Number.Uint64()) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't accept future chain of unacceptable length (from current block)
|
||||||
|
if len(futureChain)+offset > int(w.checkpointInterval) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the chain and validate against the last checkpoint
|
||||||
|
// It will handle all cases where the incoming chain has atleast one checkpoint
|
||||||
|
for i := len(pastChain) - 1; i >= 0; i-- {
|
||||||
|
if _, ok := w.checkpointWhitelist[pastChain[i].Number.Uint64()]; ok {
|
||||||
|
return pastChain[i].Hash() == w.checkpointWhitelist[pastChain[i].Number.Uint64()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*types.Header) {
|
||||||
|
var (
|
||||||
|
pastChain []*types.Header
|
||||||
|
futureChain []*types.Header
|
||||||
|
first uint64 = chain[0].Number.Uint64()
|
||||||
|
last uint64 = chain[len(chain)-1].Number.Uint64()
|
||||||
|
)
|
||||||
|
|
||||||
|
if current >= first {
|
||||||
|
if len(chain) == 1 || current >= last {
|
||||||
|
pastChain = chain
|
||||||
|
} else {
|
||||||
|
pastChain = chain[:current-first+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if current < last {
|
||||||
|
if len(chain) == 1 || current < first {
|
||||||
|
futureChain = chain
|
||||||
|
} else {
|
||||||
|
futureChain = chain[current-first+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pastChain, futureChain
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
func (w *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
w.m.Lock()
|
w.m.Lock()
|
||||||
defer w.m.Unlock()
|
defer w.m.Unlock()
|
||||||
|
|
@ -116,7 +196,7 @@ func (w *Service) dequeueCheckpointWhitelist() {
|
||||||
log.Debug("Dequeing checkpoint whitelist", "block number", w.checkpointOrder[0], "block hash", w.checkpointWhitelist[w.checkpointOrder[0]])
|
log.Debug("Dequeing checkpoint whitelist", "block number", w.checkpointOrder[0], "block hash", w.checkpointWhitelist[w.checkpointOrder[0]])
|
||||||
|
|
||||||
delete(w.checkpointWhitelist, w.checkpointOrder[0])
|
delete(w.checkpointWhitelist, w.checkpointOrder[0])
|
||||||
w.checkpointOrder = w.checkpointOrder[1:]
|
w.checkpointOrder = w.checkpointOrder[1:] // fixme: this slice is growing infinitely and never will be released. also a panic is possible if the last element is going to be removed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,26 @@ package whitelist
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gotest.tools/assert"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewMockService creates a new mock whitelist service
|
// NewMockService creates a new mock whitelist service
|
||||||
func NewMockService(maxCapacity uint) *Service {
|
func NewMockService(maxCapacity uint, checkpointInterval uint64) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
checkpointWhitelist: make(map[uint64]common.Hash),
|
||||||
checkpointOrder: []uint64{},
|
checkpointOrder: []uint64{},
|
||||||
maxCapacity: maxCapacity,
|
maxCapacity: maxCapacity,
|
||||||
|
checkpointInterval: checkpointInterval,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,34 +29,34 @@ func NewMockService(maxCapacity uint) *Service {
|
||||||
func TestWhitelistCheckpoint(t *testing.T) {
|
func TestWhitelistCheckpoint(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s := NewMockService(10)
|
s := NewMockService(10, 10)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{})
|
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{})
|
||||||
}
|
}
|
||||||
assert.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||||
|
|
||||||
s.enqueueCheckpointWhitelist(11, common.Hash{})
|
s.enqueueCheckpointWhitelist(11, common.Hash{})
|
||||||
s.dequeueCheckpointWhitelist()
|
s.dequeueCheckpointWhitelist()
|
||||||
assert.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestIsValidChain checks che IsValidChain function in isolation
|
// TestIsValidPeer checks the IsValidPeer function in isolation
|
||||||
// for different cases by providing a mock fetchHeadersByNumber function
|
// for different cases by providing a mock fetchHeadersByNumber function
|
||||||
func TestIsValidChain(t *testing.T) {
|
func TestIsValidPeer(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s := NewMockService(10)
|
s := NewMockService(10, 10)
|
||||||
|
|
||||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||||
res, err := s.IsValidChain(nil, nil)
|
res, err := s.IsValidPeer(nil, nil)
|
||||||
assert.NilError(t, err, "expected no error")
|
require.NoError(t, err, "expected no error")
|
||||||
assert.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
// add checkpoint entries and mock fetchHeadersByNumber function
|
// add checkpoint entries and mock fetchHeadersByNumber function
|
||||||
s.ProcessCheckpoint(uint64(0), common.Hash{})
|
s.ProcessCheckpoint(uint64(0), common.Hash{})
|
||||||
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
||||||
|
|
||||||
assert.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||||
|
|
||||||
// create a false function, returning absolutely nothing
|
// create a false function, returning absolutely nothing
|
||||||
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
||||||
|
|
@ -60,7 +65,7 @@ func TestIsValidChain(t *testing.T) {
|
||||||
|
|
||||||
// case2: false fetchHeadersByNumber function provided, should consider the chain as invalid
|
// case2: false fetchHeadersByNumber function provided, should consider the chain as invalid
|
||||||
// and throw `ErrNoRemoteCheckoint` error
|
// and throw `ErrNoRemoteCheckoint` error
|
||||||
res, err = s.IsValidChain(nil, falseFetchHeadersByNumber)
|
res, err = s.IsValidPeer(nil, falseFetchHeadersByNumber)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected error, got nil")
|
t.Fatal("expected error, got nil")
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +74,7 @@ func TestIsValidChain(t *testing.T) {
|
||||||
t.Fatalf("expected error ErrNoRemoteCheckoint, got %v", err)
|
t.Fatalf("expected error ErrNoRemoteCheckoint, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, res, false, "expected chain to be invalid")
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||||
// create a mock function, returning a the required header
|
// create a mock function, returning a the required header
|
||||||
|
|
@ -91,17 +96,316 @@ func TestIsValidChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err = s.IsValidChain(nil, fetchHeadersByNumber)
|
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
||||||
assert.NilError(t, err, "expected no error")
|
require.NoError(t, err, "expected no error")
|
||||||
assert.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
// add one more checkpoint whitelist entry
|
// add one more checkpoint whitelist entry
|
||||||
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
||||||
assert.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
require.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
||||||
|
|
||||||
// case4: correct fetchHeadersByNumber function provided with wrong header
|
// case4: correct fetchHeadersByNumber function provided with wrong header
|
||||||
// for block number 2. Should consider the chain as invalid and throw an error
|
// for block number 2. Should consider the chain as invalid and throw an error
|
||||||
res, err = s.IsValidChain(nil, fetchHeadersByNumber)
|
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
||||||
assert.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
||||||
assert.Equal(t, res, false, "expected chain to be invalid")
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestIsValidChain checks the IsValidChain function in isolation
|
||||||
|
// for different cases by providing a mock current header and chain
|
||||||
|
func TestIsValidChain(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
s := NewMockService(10, 10)
|
||||||
|
chainA := createMockChain(1, 20) // A1->A2...A19->A20
|
||||||
|
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||||
|
res := s.IsValidChain(nil, chainA)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
tempChain := createMockChain(21, 22) // A21->A22
|
||||||
|
|
||||||
|
// add mock checkpoint entries
|
||||||
|
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
||||||
|
s.ProcessCheckpoint(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||||
|
|
||||||
|
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||||
|
|
||||||
|
// case2: We're behind the oldest whitelisted block entry, should consider
|
||||||
|
// the chain as valid as we're still far behind the latest blocks
|
||||||
|
res = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// Clear checkpoint whitelist and add blocks A5 and A15 in whitelist
|
||||||
|
s.PurgeCheckpointWhitelist()
|
||||||
|
s.ProcessCheckpoint(chainA[5].Number.Uint64(), chainA[5].Hash())
|
||||||
|
s.ProcessCheckpoint(chainA[15].Number.Uint64(), chainA[15].Hash())
|
||||||
|
|
||||||
|
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||||
|
|
||||||
|
// case3: Try importing a past chain having valid checkpoint, should
|
||||||
|
// consider the chain as valid
|
||||||
|
res = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// Clear checkpoint whitelist and mock blocks in whitelist
|
||||||
|
tempChain = createMockChain(20, 20) // A20
|
||||||
|
|
||||||
|
s.PurgeCheckpointWhitelist()
|
||||||
|
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
||||||
|
|
||||||
|
require.Equal(t, s.length(), 1, "expected 1 items in whitelist")
|
||||||
|
|
||||||
|
// case4: Try importing a past chain having invalid checkpoint
|
||||||
|
res = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
// create a future chain to be imported of length <= `checkpointInterval`
|
||||||
|
chainB := createMockChain(21, 30) // B21->B22...B29->B30
|
||||||
|
|
||||||
|
// case5: Try importing a future chain of acceptable length
|
||||||
|
res = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// create a future chain to be imported of length > `checkpointInterval`
|
||||||
|
chainB = createMockChain(21, 40) // C21->C22...C39->C40
|
||||||
|
|
||||||
|
// case5: Try importing a future chain of unacceptable length
|
||||||
|
res = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitChain(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
pastStart uint64
|
||||||
|
pastEnd uint64
|
||||||
|
futureStart uint64
|
||||||
|
futureEnd uint64
|
||||||
|
pastLength int
|
||||||
|
futureLength int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current chain is at block: X
|
||||||
|
// Incoming chain is represented as [N, M]
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
current uint64
|
||||||
|
chain []*types.Header
|
||||||
|
result Result
|
||||||
|
}{
|
||||||
|
{name: "X = 10, N = 11, M = 20", current: uint64(10), chain: createMockChain(11, 20), result: Result{futureStart: 11, futureEnd: 20, futureLength: 10}},
|
||||||
|
{name: "X = 10, N = 13, M = 20", current: uint64(10), chain: createMockChain(13, 20), result: Result{futureStart: 13, futureEnd: 20, futureLength: 8}},
|
||||||
|
{name: "X = 10, N = 2, M = 10", current: uint64(10), chain: createMockChain(2, 10), result: Result{pastStart: 2, pastEnd: 10, pastLength: 9}},
|
||||||
|
{name: "X = 10, N = 2, M = 9", current: uint64(10), chain: createMockChain(2, 9), result: Result{pastStart: 2, pastEnd: 9, pastLength: 8}},
|
||||||
|
{name: "X = 10, N = 2, M = 8", current: uint64(10), chain: createMockChain(2, 8), result: Result{pastStart: 2, pastEnd: 8, pastLength: 7}},
|
||||||
|
{name: "X = 10, N = 5, M = 15", current: uint64(10), chain: createMockChain(5, 15), result: Result{pastStart: 5, pastEnd: 10, pastLength: 6, futureStart: 11, futureEnd: 15, futureLength: 5}},
|
||||||
|
{name: "X = 10, N = 10, M = 20", current: uint64(10), chain: createMockChain(10, 20), result: Result{pastStart: 10, pastEnd: 10, pastLength: 1, futureStart: 11, futureEnd: 20, futureLength: 10}},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
past, future := splitChain(tc.current, tc.chain)
|
||||||
|
require.Equal(t, len(past), tc.result.pastLength)
|
||||||
|
require.Equal(t, len(future), tc.result.futureLength)
|
||||||
|
|
||||||
|
if len(past) > 0 {
|
||||||
|
// Check if we have expected block/s
|
||||||
|
require.Equal(t, past[0].Number.Uint64(), tc.result.pastStart)
|
||||||
|
require.Equal(t, past[len(past)-1].Number.Uint64(), tc.result.pastEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(future) > 0 {
|
||||||
|
// Check if we have expected block/s
|
||||||
|
require.Equal(t, future[0].Number.Uint64(), tc.result.futureStart)
|
||||||
|
require.Equal(t, future[len(future)-1].Number.Uint64(), tc.result.futureEnd)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gocognit
|
||||||
|
func TestSplitChainProperties(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Current chain is at block: X
|
||||||
|
// Incoming chain is represented as [N, M]
|
||||||
|
|
||||||
|
currentChain := []int{0, 1, 2, 3, 10, 100} // blocks starting from genesis
|
||||||
|
blockDiffs := []int{0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 90, 100, 101, 102}
|
||||||
|
|
||||||
|
caseParams := make(map[int]map[int]map[int]struct{}) // X -> N -> M
|
||||||
|
|
||||||
|
for _, current := range currentChain {
|
||||||
|
// past cases only + past to current
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
from := current - diff
|
||||||
|
|
||||||
|
// use int type for everything to not care about underflow
|
||||||
|
if from < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
to := current - diff
|
||||||
|
|
||||||
|
if to >= from {
|
||||||
|
addTestCaseParams(caseParams, current, from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// future only + current to future
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
from := current + diff
|
||||||
|
|
||||||
|
if from < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
to := current + diff
|
||||||
|
|
||||||
|
if to >= from {
|
||||||
|
addTestCaseParams(caseParams, current, from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// past-current-future
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
from := current - diff
|
||||||
|
|
||||||
|
if from < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, diff := range blockDiffs {
|
||||||
|
to := current + diff
|
||||||
|
|
||||||
|
if to >= from {
|
||||||
|
addTestCaseParams(caseParams, current, from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
current int
|
||||||
|
remoteStart int
|
||||||
|
remoteEnd int
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts []testCase
|
||||||
|
|
||||||
|
// X -> N -> M
|
||||||
|
for x, nm := range caseParams {
|
||||||
|
for n, mMap := range nm {
|
||||||
|
for m := range mMap {
|
||||||
|
ts = append(ts, testCase{x, n, m})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:paralleltest
|
||||||
|
for i, tc := range ts {
|
||||||
|
tc := tc
|
||||||
|
|
||||||
|
name := fmt.Sprintf("test case: index = %d, X = %d, N = %d, M = %d", i, tc.current, tc.remoteStart, tc.remoteEnd)
|
||||||
|
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
chain := createMockChain(uint64(tc.remoteStart), uint64(tc.remoteEnd))
|
||||||
|
|
||||||
|
past, future := splitChain(uint64(tc.current), chain)
|
||||||
|
|
||||||
|
// properties
|
||||||
|
if len(past) > 0 {
|
||||||
|
// Check if the chain is ordered
|
||||||
|
isOrdered := sort.SliceIsSorted(past, func(i, j int) bool {
|
||||||
|
return past[i].Number.Uint64() < past[j].Number.Uint64()
|
||||||
|
})
|
||||||
|
|
||||||
|
require.True(t, isOrdered, "an ordered past chain expected: %v", past)
|
||||||
|
|
||||||
|
isSequential := sort.SliceIsSorted(past, func(i, j int) bool {
|
||||||
|
return past[i].Number.Uint64() == past[j].Number.Uint64()-1
|
||||||
|
})
|
||||||
|
|
||||||
|
require.True(t, isSequential, "a sequential past chain expected: %v", past)
|
||||||
|
|
||||||
|
// Check if current block >= past chain's last block
|
||||||
|
require.Equal(t, past[len(past)-1].Number.Uint64() <= uint64(tc.current), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(future) > 0 {
|
||||||
|
// Check if the chain is ordered
|
||||||
|
isOrdered := sort.SliceIsSorted(future, func(i, j int) bool {
|
||||||
|
return future[i].Number.Uint64() < future[j].Number.Uint64()
|
||||||
|
})
|
||||||
|
|
||||||
|
require.True(t, isOrdered, "an ordered future chain expected: %v", future)
|
||||||
|
|
||||||
|
isSequential := sort.SliceIsSorted(future, func(i, j int) bool {
|
||||||
|
return future[i].Number.Uint64() == future[j].Number.Uint64()-1
|
||||||
|
})
|
||||||
|
|
||||||
|
require.True(t, isSequential, "a sequential future chain expected: %v", future)
|
||||||
|
|
||||||
|
// Check if future chain's first block > current block
|
||||||
|
require.Equal(t, future[len(future)-1].Number.Uint64() > uint64(tc.current), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if both chains are continuous
|
||||||
|
if len(past) > 0 && len(future) > 0 {
|
||||||
|
require.Equal(t, past[len(past)-1].Number.Uint64(), future[0].Number.Uint64()-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we get the original chain on appending both
|
||||||
|
gotChain := append(past, future...)
|
||||||
|
require.Equal(t, reflect.DeepEqual(gotChain, chain), true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// createMockChain returns a chain with dummy headers
|
||||||
|
// starting from `start` to `end` (inclusive)
|
||||||
|
func createMockChain(start, end uint64) []*types.Header {
|
||||||
|
var (
|
||||||
|
i uint64
|
||||||
|
idx uint64
|
||||||
|
chain []*types.Header = make([]*types.Header, end-start+1)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i = start; i <= end; i++ {
|
||||||
|
header := &types.Header{
|
||||||
|
Number: big.NewInt(int64(i)),
|
||||||
|
Time: uint64(time.Now().UnixMicro()) + i,
|
||||||
|
}
|
||||||
|
chain[idx] = header
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain
|
||||||
|
}
|
||||||
|
|
||||||
|
// mXNM should be initialized
|
||||||
|
func addTestCaseParams(mXNM map[int]map[int]map[int]struct{}, x, n, m int) {
|
||||||
|
//nolint:ineffassign
|
||||||
|
mNM, ok := mXNM[x]
|
||||||
|
if !ok {
|
||||||
|
mNM = make(map[int]map[int]struct{})
|
||||||
|
mXNM[x] = mNM
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:ineffassign
|
||||||
|
_, ok = mNM[n]
|
||||||
|
if !ok {
|
||||||
|
mM := make(map[int]struct{})
|
||||||
|
mNM[n] = mM
|
||||||
|
}
|
||||||
|
|
||||||
|
mXNM[x][n][m] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/contract"
|
"github.com/ethereum/go-ethereum/consensus/bor/contract"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,9 @@ func (api *PublicFilterAPI) NewDeposits(ctx context.Context, crit ethereum.State
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcSub := notifier.CreateSubscription()
|
rpcSub := notifier.CreateSubscription()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stateSyncData := make(chan *types.StateSyncData)
|
stateSyncData := make(chan *types.StateSyncData, 10)
|
||||||
stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData)
|
stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
|
||||||
// Construct testing chain
|
// Construct testing chain
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.Commit(diskdb)
|
gspec.Commit(diskdb)
|
||||||
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create local chain, %v", err)
|
t.Fatalf("Failed to create local chain, %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
|
|
@ -31,7 +32,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/forkid"
|
"github.com/ethereum/go-ethereum/core/forkid"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader/whitelist"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/fetcher"
|
"github.com/ethereum/go-ethereum/eth/fetcher"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
|
|
@ -91,6 +91,7 @@ type handlerConfig struct {
|
||||||
EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact
|
EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact
|
||||||
|
|
||||||
PeerRequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
PeerRequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
||||||
|
checker ethereum.ChainValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
|
|
@ -202,7 +203,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||||
// sync is requested. The downloader is responsible for deallocating the state
|
// sync is requested. The downloader is responsible for deallocating the state
|
||||||
// bloom when it's done.
|
// bloom when it's done.
|
||||||
// todo: it'd better to extract maxCapacity into config
|
// todo: it'd better to extract maxCapacity into config
|
||||||
h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success, whitelist.NewService(10))
|
h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success, config.checker)
|
||||||
|
|
||||||
// Construct the fetcher (short sync)
|
// Construct the fetcher (short sync)
|
||||||
validator := func(header *types.Header) error {
|
validator := func(header *types.Header) error {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// errCheckpointCount is returned when we are unable to fetch
|
||||||
|
// the checkpoint count from local heimdall.
|
||||||
|
errCheckpointCount = errors.New("failed to fetch checkpoint count")
|
||||||
|
|
||||||
|
// errNoCheckpoint is returned when there is not checkpoint proposed
|
||||||
|
// by heimdall yet or heimdall is not in sync
|
||||||
|
errNoCheckpoint = errors.New("no checkpoint proposed")
|
||||||
|
|
||||||
// errCheckpoint is returned when we are unable to fetch the
|
// errCheckpoint is returned when we are unable to fetch the
|
||||||
// latest checkpoint from the local heimdall.
|
// latest checkpoint from the local heimdall.
|
||||||
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
||||||
|
|
@ -33,43 +41,78 @@ var (
|
||||||
errEndBlock = errors.New("failed to get end block")
|
errEndBlock = errors.New("failed to get end block")
|
||||||
)
|
)
|
||||||
|
|
||||||
// fetchWhitelistCheckpoint fetched the latest checkpoint from it's local heimdall
|
// fetchWhitelistCheckpoints fetches the latest checkpoint/s from it's local heimdall
|
||||||
// and verifies the data against bor data.
|
// and verifies the data against bor data.
|
||||||
func (h *ethHandler) fetchWhitelistCheckpoint(ctx context.Context, bor *bor.Bor) (uint64, common.Hash, error) {
|
func (h *ethHandler) fetchWhitelistCheckpoints(ctx context.Context, bor *bor.Bor, first bool) ([]uint64, []common.Hash, error) {
|
||||||
// check for checkpoint whitelisting: bor
|
// Create an array for block number and block hashes
|
||||||
checkpoint, err := bor.HeimdallClient.FetchLatestCheckpoint(ctx)
|
//nolint:prealloc
|
||||||
|
var (
|
||||||
|
blockNums []uint64 = make([]uint64, 0)
|
||||||
|
blockHashes []common.Hash = make([]common.Hash, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fetch the checkpoint count from heimdall
|
||||||
|
count, err := bor.HeimdallClient.FetchCheckpointCount(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to fetch latest checkpoint for whitelisting")
|
log.Debug("Failed to fetch checkpoint count for whitelisting", "err", err)
|
||||||
return 0, common.Hash{}, errCheckpoint
|
return blockNums, blockHashes, errCheckpointCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we have the checkpoint blocks
|
if count == 0 {
|
||||||
head := h.ethAPI.BlockNumber()
|
return blockNums, blockHashes, errNoCheckpoint
|
||||||
if head < hexutil.Uint64(checkpoint.EndBlock.Uint64()) {
|
|
||||||
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", checkpoint.EndBlock)
|
|
||||||
return 0, common.Hash{}, errMissingCheckpoint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the root hash of checkpoint
|
// If we're in the first iteration, we'll fetch last 10 checkpoints, else only the latest one
|
||||||
roothash, err := h.ethAPI.GetRootHash(ctx, checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64())
|
iterations := 1
|
||||||
if err != nil {
|
if first {
|
||||||
log.Debug("Failed to get root hash of checkpoint while whitelisting")
|
iterations = 10
|
||||||
return 0, common.Hash{}, errRootHash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if roothash != checkpoint.RootHash.String()[2:] {
|
for i := 0; i < iterations; i++ {
|
||||||
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
|
// If we don't have any checkpoints in heimdall, break
|
||||||
return 0, common.Hash{}, errCheckpointRootHashMismatch
|
if count == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch `count` indexed checkpoint from heimdall
|
||||||
|
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, count)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err)
|
||||||
|
return blockNums, blockHashes, errCheckpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we have the checkpoint blocks
|
||||||
|
head := h.ethAPI.BlockNumber()
|
||||||
|
if head < hexutil.Uint64(checkpoint.EndBlock.Uint64()) {
|
||||||
|
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", checkpoint.EndBlock)
|
||||||
|
return blockNums, blockHashes, errMissingCheckpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the root hash of checkpoint
|
||||||
|
roothash, err := h.ethAPI.GetRootHash(ctx, checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64())
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err)
|
||||||
|
return blockNums, blockHashes, errRootHash
|
||||||
|
}
|
||||||
|
|
||||||
|
if roothash != checkpoint.RootHash.String()[2:] {
|
||||||
|
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
|
||||||
|
return blockNums, blockHashes, errCheckpointRootHashMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the end checkpoint block hash
|
||||||
|
block, err := h.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(checkpoint.EndBlock.Uint64()), false)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err)
|
||||||
|
return blockNums, blockHashes, errEndBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := fmt.Sprintf("%v", block["hash"])
|
||||||
|
|
||||||
|
blockNums = append(blockNums, checkpoint.EndBlock.Uint64())
|
||||||
|
blockHashes = append(blockHashes, common.HexToHash(hash))
|
||||||
|
count--
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the end checkpoint block hash
|
return blockNums, blockHashes, nil
|
||||||
block, err := h.ethAPI.GetBlockByNumber(context.Background(), rpc.BlockNumber(checkpoint.EndBlock.Uint64()), false)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to get end block hash of checkpoint while whitelisting")
|
|
||||||
return 0, common.Hash{}, errEndBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
hash := fmt.Sprintf("%v", block["hash"])
|
|
||||||
|
|
||||||
return checkpoint.EndBlock.Uint64(), common.HexToHash(hash), nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ func testForkIDSplit(t *testing.T, protocol uint) {
|
||||||
genesisNoFork = gspecNoFork.MustCommit(dbNoFork)
|
genesisNoFork = gspecNoFork.MustCommit(dbNoFork)
|
||||||
genesisProFork = gspecProFork.MustCommit(dbProFork)
|
genesisProFork = gspecProFork.MustCommit(dbProFork)
|
||||||
|
|
||||||
chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil)
|
chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil, nil)
|
||||||
chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil)
|
chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil, nil)
|
||||||
|
|
||||||
blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil)
|
blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil)
|
||||||
blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil)
|
blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil)
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler {
|
||||||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
|
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
|
||||||
}).MustCommit(db)
|
}).MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
|
|
||||||
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil)
|
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil)
|
||||||
if _, err := chain.InsertChain(bs); err != nil {
|
if _, err := chain.InsertChain(bs); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)
|
||||||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
||||||
}).MustCommit(db)
|
}).MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
|
|
||||||
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator)
|
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator)
|
||||||
if _, err := chain.InsertChain(bs); err != nil {
|
if _, err := chain.InsertChain(bs); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
TrieDirtyDisabled: true, // Archive mode
|
TrieDirtyDisabled: true, // Archive mode
|
||||||
}
|
}
|
||||||
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,3 +238,12 @@ type StateSyncFilter struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
Contract common.Address
|
Contract common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interface for whitelist service
|
||||||
|
type ChainValidator interface {
|
||||||
|
IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||||
|
IsValidChain(currentHeader *types.Header, chain []*types.Header) bool
|
||||||
|
ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash)
|
||||||
|
GetCheckpointWhitelist() map[uint64]common.Hash
|
||||||
|
PurgeCheckpointWhitelist()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
@ -162,7 +161,7 @@ func (b *BootnodeCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
// save the public key
|
// save the public key
|
||||||
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
||||||
if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
if err := os.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil {
|
||||||
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cli/server"
|
"github.com/ethereum/go-ethereum/internal/cli/server"
|
||||||
)
|
)
|
||||||
|
|
@ -30,7 +30,7 @@ func TestCommand_DebugBlock(t *testing.T) {
|
||||||
|
|
||||||
// start the mock server
|
// start the mock server
|
||||||
srv, err := server.CreateMockServer(config)
|
srv, err := server.CreateMockServer(config)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
defer server.CloseMockServer(srv)
|
defer server.CloseMockServer(srv)
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ func TestCommand_DebugBlock(t *testing.T) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
||||||
res := traceBlock(port, 1, output)
|
res := traceBlock(port, 1, output)
|
||||||
assert.Equal(t, 0, res)
|
require.Equal(t, 0, res)
|
||||||
t.Logf("Completed trace of block %d in %d ms at %s", 1, time.Since(start).Milliseconds(), dst1)
|
t.Logf("Completed trace of block %d in %d ms at %s", 1, time.Since(start).Milliseconds(), dst1)
|
||||||
|
|
||||||
// adding this to avoid debug directory name conflicts
|
// adding this to avoid debug directory name conflicts
|
||||||
|
|
@ -64,14 +64,14 @@ func TestCommand_DebugBlock(t *testing.T) {
|
||||||
latestBlock := srv.GetLatestBlockNumber().Int64()
|
latestBlock := srv.GetLatestBlockNumber().Int64()
|
||||||
dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json")
|
||||||
res = traceBlock(port, latestBlock, output)
|
res = traceBlock(port, latestBlock, output)
|
||||||
assert.Equal(t, 0, res)
|
require.Equal(t, 0, res)
|
||||||
t.Logf("Completed trace of block %d in %d ms at %s", latestBlock, time.Since(start).Milliseconds(), dst2)
|
t.Logf("Completed trace of block %d in %d ms at %s", latestBlock, time.Since(start).Milliseconds(), dst2)
|
||||||
|
|
||||||
// verify if the trace files are created
|
// verify if the trace files are created
|
||||||
done := verify(dst1)
|
done := verify(dst1)
|
||||||
assert.Equal(t, true, done)
|
require.Equal(t, true, done)
|
||||||
done = verify(dst2)
|
done = verify(dst2)
|
||||||
assert.Equal(t, true, done)
|
require.Equal(t, true, done)
|
||||||
|
|
||||||
// delete the traces
|
// delete the traces
|
||||||
deleteTraces(output)
|
deleteTraces(output)
|
||||||
|
|
|
||||||
|
|
@ -202,10 +202,11 @@ func (f *Flagset) BigIntFlag(b *BigIntFlag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SliceStringFlag struct {
|
type SliceStringFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Usage string
|
Usage string
|
||||||
Value *[]string
|
Value *[]string
|
||||||
Group string
|
Default []string
|
||||||
|
Group string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *SliceStringFlag) String() string {
|
func (i *SliceStringFlag) String() string {
|
||||||
|
|
@ -217,8 +218,8 @@ func (i *SliceStringFlag) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *SliceStringFlag) Set(value string) error {
|
func (i *SliceStringFlag) Set(value string) error {
|
||||||
*i.Value = append(*i.Value, strings.Split(value, ",")...)
|
// overwritting insted of appending
|
||||||
|
*i.Value = strings.Split(value, ",")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,17 @@ func TestFlagsetBool(t *testing.T) {
|
||||||
func TestFlagsetSliceString(t *testing.T) {
|
func TestFlagsetSliceString(t *testing.T) {
|
||||||
f := NewFlagSet("")
|
f := NewFlagSet("")
|
||||||
|
|
||||||
value := []string{}
|
value := []string{"a", "b", "c"}
|
||||||
f.SliceStringFlag(&SliceStringFlag{
|
f.SliceStringFlag(&SliceStringFlag{
|
||||||
Name: "flag",
|
Name: "flag",
|
||||||
Value: &value,
|
Value: &value,
|
||||||
|
Default: value,
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NoError(t, f.Parse([]string{"--flag", "a,b", "--flag", "c"}))
|
assert.NoError(t, f.Parse([]string{}))
|
||||||
assert.Equal(t, value, []string{"a", "b", "c"})
|
assert.Equal(t, value, []string{"a", "b", "c"})
|
||||||
|
assert.NoError(t, f.Parse([]string{"--flag", "a,b"}))
|
||||||
|
assert.Equal(t, value, []string{"a", "b"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFlagsetDuration(t *testing.T) {
|
func TestFlagsetDuration(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ package cli
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCodeBlock(t *testing.T) {
|
func TestCodeBlock(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
assert := assert.New(t)
|
assert := require.New(t)
|
||||||
|
|
||||||
lines := []string{
|
lines := []string{
|
||||||
"abc",
|
"abc",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -50,7 +49,7 @@ func GetChain(name string) (*Chain, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportFromFile(filename string) (*Chain, error) {
|
func ImportFromFile(filename string) (*Chain, error) {
|
||||||
data, err := ioutil.ReadFile(filename)
|
data, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ type Config struct {
|
||||||
// Chain is the chain to sync with
|
// Chain is the chain to sync with
|
||||||
Chain string `hcl:"chain,optional"`
|
Chain string `hcl:"chain,optional"`
|
||||||
|
|
||||||
// Name, or identity of the node
|
// Identity of the node
|
||||||
Name string `hcl:"name,optional"`
|
Identity string `hcl:"identity,optional"`
|
||||||
|
|
||||||
// RequiredBlocks is a list of required (block number, hash) pairs to accept
|
// RequiredBlocks is a list of required (block number, hash) pairs to accept
|
||||||
RequiredBlocks map[string]string `hcl:"requiredblocks,optional"`
|
RequiredBlocks map[string]string `hcl:"requiredblocks,optional"`
|
||||||
|
|
@ -61,8 +61,8 @@ type Config struct {
|
||||||
// GcMode selects the garbage collection mode for the trie
|
// GcMode selects the garbage collection mode for the trie
|
||||||
GcMode string `hcl:"gc-mode,optional"`
|
GcMode string `hcl:"gc-mode,optional"`
|
||||||
|
|
||||||
// NoSnapshot disables the snapshot database mode
|
// Snapshot disables/enables the snapshot database mode
|
||||||
NoSnapshot bool `hcl:"no-snapshot,optional"`
|
Snapshot bool `hcl:"snapshot,optional"`
|
||||||
|
|
||||||
// Ethstats is the address of the ethstats server to send telemetry
|
// Ethstats is the address of the ethstats server to send telemetry
|
||||||
Ethstats string `hcl:"ethstats,optional"`
|
Ethstats string `hcl:"ethstats,optional"`
|
||||||
|
|
@ -217,12 +217,6 @@ type JsonRPCConfig struct {
|
||||||
// IPCPath is the path of the ipc endpoint
|
// IPCPath is the path of the ipc endpoint
|
||||||
IPCPath string `hcl:"ipc-path,optional"`
|
IPCPath string `hcl:"ipc-path,optional"`
|
||||||
|
|
||||||
// VHost is the list of valid virtual hosts
|
|
||||||
VHost []string `hcl:"vhost,optional"`
|
|
||||||
|
|
||||||
// Cors is the list of Cors endpoints
|
|
||||||
Cors []string `hcl:"cors,optional"`
|
|
||||||
|
|
||||||
// GasCap is the global gas cap for eth-call variants.
|
// GasCap is the global gas cap for eth-call variants.
|
||||||
GasCap uint64 `hcl:"gas-cap,optional"`
|
GasCap uint64 `hcl:"gas-cap,optional"`
|
||||||
|
|
||||||
|
|
@ -232,10 +226,10 @@ type JsonRPCConfig struct {
|
||||||
// Http has the json-rpc http related settings
|
// Http has the json-rpc http related settings
|
||||||
Http *APIConfig `hcl:"http,block"`
|
Http *APIConfig `hcl:"http,block"`
|
||||||
|
|
||||||
// Http has the json-rpc websocket related settings
|
// Ws has the json-rpc websocket related settings
|
||||||
Ws *APIConfig `hcl:"ws,block"`
|
Ws *APIConfig `hcl:"ws,block"`
|
||||||
|
|
||||||
// Http has the json-rpc graphql related settings
|
// Graphql has the json-rpc graphql related settings
|
||||||
Graphql *APIConfig `hcl:"graphql,block"`
|
Graphql *APIConfig `hcl:"graphql,block"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,7 +252,13 @@ type APIConfig struct {
|
||||||
Host string `hcl:"host,optional"`
|
Host string `hcl:"host,optional"`
|
||||||
|
|
||||||
// Modules is the list of enabled api modules
|
// Modules is the list of enabled api modules
|
||||||
Modules []string `hcl:"modules,optional"`
|
API []string `hcl:"modules,optional"`
|
||||||
|
|
||||||
|
// VHost is the list of valid virtual hosts
|
||||||
|
VHost []string `hcl:"vhost,optional"`
|
||||||
|
|
||||||
|
// Cors is the list of Cors endpoints
|
||||||
|
Cors []string `hcl:"cors,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GpoConfig struct {
|
type GpoConfig struct {
|
||||||
|
|
@ -387,7 +387,7 @@ type DeveloperConfig struct {
|
||||||
func DefaultConfig() *Config {
|
func DefaultConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
Chain: "mainnet",
|
Chain: "mainnet",
|
||||||
Name: Hostname(),
|
Identity: Hostname(),
|
||||||
RequiredBlocks: map[string]string{},
|
RequiredBlocks: map[string]string{},
|
||||||
LogLevel: "INFO",
|
LogLevel: "INFO",
|
||||||
DataDir: defaultDataDir(),
|
DataDir: defaultDataDir(),
|
||||||
|
|
@ -412,9 +412,9 @@ func DefaultConfig() *Config {
|
||||||
URL: "http://localhost:1317",
|
URL: "http://localhost:1317",
|
||||||
Without: false,
|
Without: false,
|
||||||
},
|
},
|
||||||
SyncMode: "full",
|
SyncMode: "full",
|
||||||
GcMode: "full",
|
GcMode: "full",
|
||||||
NoSnapshot: false,
|
Snapshot: true,
|
||||||
TxPool: &TxPoolConfig{
|
TxPool: &TxPoolConfig{
|
||||||
Locals: []string{},
|
Locals: []string{},
|
||||||
NoLocals: false,
|
NoLocals: false,
|
||||||
|
|
@ -444,8 +444,6 @@ func DefaultConfig() *Config {
|
||||||
JsonRPC: &JsonRPCConfig{
|
JsonRPC: &JsonRPCConfig{
|
||||||
IPCDisable: false,
|
IPCDisable: false,
|
||||||
IPCPath: "",
|
IPCPath: "",
|
||||||
Cors: []string{"*"},
|
|
||||||
VHost: []string{"*"},
|
|
||||||
GasCap: ethconfig.Defaults.RPCGasCap,
|
GasCap: ethconfig.Defaults.RPCGasCap,
|
||||||
TxFeeCap: ethconfig.Defaults.RPCTxFeeCap,
|
TxFeeCap: ethconfig.Defaults.RPCTxFeeCap,
|
||||||
Http: &APIConfig{
|
Http: &APIConfig{
|
||||||
|
|
@ -453,17 +451,23 @@ func DefaultConfig() *Config {
|
||||||
Port: 8545,
|
Port: 8545,
|
||||||
Prefix: "",
|
Prefix: "",
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Modules: []string{"eth", "net", "web3", "txpool", "bor"},
|
API: []string{"eth", "net", "web3", "txpool", "bor"},
|
||||||
|
Cors: []string{"*"},
|
||||||
|
VHost: []string{"*"},
|
||||||
},
|
},
|
||||||
Ws: &APIConfig{
|
Ws: &APIConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Port: 8546,
|
Port: 8546,
|
||||||
Prefix: "",
|
Prefix: "",
|
||||||
Host: "localhost",
|
Host: "localhost",
|
||||||
Modules: []string{"web3", "net"},
|
API: []string{"web3", "net"},
|
||||||
|
Cors: []string{"*"},
|
||||||
|
VHost: []string{"*"},
|
||||||
},
|
},
|
||||||
Graphql: &APIConfig{
|
Graphql: &APIConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
|
Cors: []string{"*"},
|
||||||
|
VHost: []string{"*"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ethstats: "",
|
Ethstats: "",
|
||||||
|
|
@ -864,7 +868,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
// snapshot disable check
|
// snapshot disable check
|
||||||
if c.NoSnapshot {
|
if !c.Snapshot {
|
||||||
if n.SyncMode == downloader.SnapSync {
|
if n.SyncMode == downloader.SnapSync {
|
||||||
log.Info("Snap sync requested, enabling --snapshot")
|
log.Info("Snap sync requested, enabling --snapshot")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -908,15 +912,15 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)),
|
ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)),
|
||||||
DiscoveryV5: c.P2P.Discovery.V5Enabled,
|
DiscoveryV5: c.P2P.Discovery.V5Enabled,
|
||||||
},
|
},
|
||||||
HTTPModules: c.JsonRPC.Http.Modules,
|
HTTPModules: c.JsonRPC.Http.API,
|
||||||
HTTPCors: c.JsonRPC.Cors,
|
HTTPCors: c.JsonRPC.Http.Cors,
|
||||||
HTTPVirtualHosts: c.JsonRPC.VHost,
|
HTTPVirtualHosts: c.JsonRPC.Http.VHost,
|
||||||
HTTPPathPrefix: c.JsonRPC.Http.Prefix,
|
HTTPPathPrefix: c.JsonRPC.Http.Prefix,
|
||||||
WSModules: c.JsonRPC.Ws.Modules,
|
WSModules: c.JsonRPC.Ws.API,
|
||||||
WSOrigins: c.JsonRPC.Cors,
|
WSOrigins: c.JsonRPC.Ws.Cors,
|
||||||
WSPathPrefix: c.JsonRPC.Ws.Prefix,
|
WSPathPrefix: c.JsonRPC.Ws.Prefix,
|
||||||
GraphQLCors: c.JsonRPC.Cors,
|
GraphQLCors: c.JsonRPC.Graphql.Cors,
|
||||||
GraphQLVirtualHosts: c.JsonRPC.VHost,
|
GraphQLVirtualHosts: c.JsonRPC.Graphql.VHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
// dev mode
|
// dev mode
|
||||||
|
|
@ -999,7 +1003,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
||||||
|
|
||||||
func (c *Config) Merge(cc ...*Config) error {
|
func (c *Config) Merge(cc ...*Config) error {
|
||||||
for _, elem := range cc {
|
for _, elem := range cc {
|
||||||
if err := mergo.Merge(c, elem, mergo.WithOverwriteWithEmptyValue, mergo.WithAppendSlice); err != nil {
|
if err := mergo.Merge(c, elem, mergo.WithOverwriteWithEmptyValue); err != nil {
|
||||||
return fmt.Errorf("failed to merge configurations: %v", err)
|
return fmt.Errorf("failed to merge configurations: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ func TestConfigDefault(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigMerge(t *testing.T) {
|
func TestConfigMerge(t *testing.T) {
|
||||||
c0 := &Config{
|
c0 := &Config{
|
||||||
Chain: "0",
|
Chain: "0",
|
||||||
NoSnapshot: true,
|
Snapshot: true,
|
||||||
RequiredBlocks: map[string]string{
|
RequiredBlocks: map[string]string{
|
||||||
"a": "b",
|
"a": "b",
|
||||||
},
|
},
|
||||||
|
|
@ -54,8 +54,8 @@ func TestConfigMerge(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := &Config{
|
expected := &Config{
|
||||||
Chain: "1",
|
Chain: "1",
|
||||||
NoSnapshot: false,
|
Snapshot: false,
|
||||||
RequiredBlocks: map[string]string{
|
RequiredBlocks: map[string]string{
|
||||||
"a": "b",
|
"a": "b",
|
||||||
"b": "c",
|
"b": "c",
|
||||||
|
|
@ -64,7 +64,6 @@ func TestConfigMerge(t *testing.T) {
|
||||||
MaxPeers: 10,
|
MaxPeers: 10,
|
||||||
Discovery: &P2PDiscovery{
|
Discovery: &P2PDiscovery{
|
||||||
StaticNodes: []string{
|
StaticNodes: []string{
|
||||||
"a",
|
|
||||||
"b",
|
"b",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Default: c.cliConfig.Chain,
|
Default: c.cliConfig.Chain,
|
||||||
})
|
})
|
||||||
f.StringFlag(&flagset.StringFlag{
|
f.StringFlag(&flagset.StringFlag{
|
||||||
Name: "name",
|
Name: "identity",
|
||||||
Usage: "Name/Identity of the node",
|
Usage: "Name/Identity of the node",
|
||||||
Value: &c.cliConfig.Name,
|
Value: &c.cliConfig.Identity,
|
||||||
Default: c.cliConfig.Name,
|
Default: c.cliConfig.Identity,
|
||||||
})
|
})
|
||||||
f.StringFlag(&flagset.StringFlag{
|
f.StringFlag(&flagset.StringFlag{
|
||||||
Name: "log-level",
|
Name: "log-level",
|
||||||
|
|
@ -61,10 +61,10 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Value: &c.cliConfig.RequiredBlocks,
|
Value: &c.cliConfig.RequiredBlocks,
|
||||||
})
|
})
|
||||||
f.BoolFlag(&flagset.BoolFlag{
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
Name: "no-snapshot",
|
Name: "snapshot",
|
||||||
Usage: `Disables the snapshot-database mode (default = false)`,
|
Usage: `Disables/Enables the snapshot-database mode (default = true)`,
|
||||||
Value: &c.cliConfig.NoSnapshot,
|
Value: &c.cliConfig.Snapshot,
|
||||||
Default: c.cliConfig.NoSnapshot,
|
Default: c.cliConfig.Snapshot,
|
||||||
})
|
})
|
||||||
|
|
||||||
// heimdall
|
// heimdall
|
||||||
|
|
@ -83,10 +83,11 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
|
|
||||||
// txpool options
|
// txpool options
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "txpool.locals",
|
Name: "txpool.locals",
|
||||||
Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
|
Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
|
||||||
Value: &c.cliConfig.TxPool.Locals,
|
Value: &c.cliConfig.TxPool.Locals,
|
||||||
Group: "Transaction Pool",
|
Default: c.cliConfig.TxPool.Locals,
|
||||||
|
Group: "Transaction Pool",
|
||||||
})
|
})
|
||||||
f.BoolFlag(&flagset.BoolFlag{
|
f.BoolFlag(&flagset.BoolFlag{
|
||||||
Name: "txpool.nolocals",
|
Name: "txpool.nolocals",
|
||||||
|
|
@ -329,16 +330,46 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Group: "JsonRPC",
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "jsonrpc.corsdomain",
|
Name: "http.corsdomain",
|
||||||
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
||||||
Value: &c.cliConfig.JsonRPC.Cors,
|
Value: &c.cliConfig.JsonRPC.Http.Cors,
|
||||||
Group: "JsonRPC",
|
Default: c.cliConfig.JsonRPC.Http.Cors,
|
||||||
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "jsonrpc.vhosts",
|
Name: "http.vhosts",
|
||||||
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||||
Value: &c.cliConfig.JsonRPC.VHost,
|
Value: &c.cliConfig.JsonRPC.Http.VHost,
|
||||||
Group: "JsonRPC",
|
Default: c.cliConfig.JsonRPC.Http.VHost,
|
||||||
|
Group: "JsonRPC",
|
||||||
|
})
|
||||||
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
|
Name: "ws.corsdomain",
|
||||||
|
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
||||||
|
Value: &c.cliConfig.JsonRPC.Ws.Cors,
|
||||||
|
Default: c.cliConfig.JsonRPC.Ws.Cors,
|
||||||
|
Group: "JsonRPC",
|
||||||
|
})
|
||||||
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
|
Name: "ws.vhosts",
|
||||||
|
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||||
|
Value: &c.cliConfig.JsonRPC.Ws.VHost,
|
||||||
|
Default: c.cliConfig.JsonRPC.Ws.VHost,
|
||||||
|
Group: "JsonRPC",
|
||||||
|
})
|
||||||
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
|
Name: "graphql.corsdomain",
|
||||||
|
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
||||||
|
Value: &c.cliConfig.JsonRPC.Graphql.Cors,
|
||||||
|
Default: c.cliConfig.JsonRPC.Graphql.Cors,
|
||||||
|
Group: "JsonRPC",
|
||||||
|
})
|
||||||
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
|
Name: "graphql.vhosts",
|
||||||
|
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||||
|
Value: &c.cliConfig.JsonRPC.Graphql.VHost,
|
||||||
|
Default: c.cliConfig.JsonRPC.Graphql.VHost,
|
||||||
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
|
|
||||||
// http options
|
// http options
|
||||||
|
|
@ -371,10 +402,11 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Group: "JsonRPC",
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "http.modules",
|
Name: "http.api",
|
||||||
Usage: "API's offered over the HTTP-RPC interface",
|
Usage: "API's offered over the HTTP-RPC interface",
|
||||||
Value: &c.cliConfig.JsonRPC.Http.Modules,
|
Value: &c.cliConfig.JsonRPC.Http.API,
|
||||||
Group: "JsonRPC",
|
Default: c.cliConfig.JsonRPC.Http.API,
|
||||||
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
|
|
||||||
// ws options
|
// ws options
|
||||||
|
|
@ -407,10 +439,11 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Group: "JsonRPC",
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "ws.modules",
|
Name: "ws.api",
|
||||||
Usage: "API's offered over the WS-RPC interface",
|
Usage: "API's offered over the WS-RPC interface",
|
||||||
Value: &c.cliConfig.JsonRPC.Ws.Modules,
|
Value: &c.cliConfig.JsonRPC.Ws.API,
|
||||||
Group: "JsonRPC",
|
Default: c.cliConfig.JsonRPC.Ws.API,
|
||||||
|
Group: "JsonRPC",
|
||||||
})
|
})
|
||||||
|
|
||||||
// graphql options
|
// graphql options
|
||||||
|
|
@ -438,10 +471,11 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
Group: "P2P",
|
Group: "P2P",
|
||||||
})
|
})
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "bootnodes",
|
Name: "bootnodes",
|
||||||
Usage: "Comma separated enode URLs for P2P discovery bootstrap",
|
Usage: "Comma separated enode URLs for P2P discovery bootstrap",
|
||||||
Value: &c.cliConfig.P2P.Discovery.Bootnodes,
|
Value: &c.cliConfig.P2P.Discovery.Bootnodes,
|
||||||
Group: "P2P",
|
Default: c.cliConfig.P2P.Discovery.Bootnodes,
|
||||||
|
Group: "P2P",
|
||||||
})
|
})
|
||||||
f.Uint64Flag(&flagset.Uint64Flag{
|
f.Uint64Flag(&flagset.Uint64Flag{
|
||||||
Name: "maxpeers",
|
Name: "maxpeers",
|
||||||
|
|
@ -581,10 +615,11 @@ func (c *Command) Flags() *flagset.Flagset {
|
||||||
|
|
||||||
// account
|
// account
|
||||||
f.SliceStringFlag(&flagset.SliceStringFlag{
|
f.SliceStringFlag(&flagset.SliceStringFlag{
|
||||||
Name: "unlock",
|
Name: "unlock",
|
||||||
Usage: "Comma separated list of accounts to unlock",
|
Usage: "Comma separated list of accounts to unlock",
|
||||||
Value: &c.cliConfig.Accounts.Unlock,
|
Value: &c.cliConfig.Accounts.Unlock,
|
||||||
Group: "Account Management",
|
Default: c.cliConfig.Accounts.Unlock,
|
||||||
|
Group: "Account Management",
|
||||||
})
|
})
|
||||||
f.StringFlag(&flagset.StringFlag{
|
f.StringFlag(&flagset.StringFlag{
|
||||||
Name: "password",
|
Name: "password",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -55,7 +54,7 @@ func CreateMockServer(config *Config) (*Server, error) {
|
||||||
config.GRPC.Addr = fmt.Sprintf(":%d", port)
|
config.GRPC.Addr = fmt.Sprintf(":%d", port)
|
||||||
|
|
||||||
// datadir
|
// datadir
|
||||||
datadir, _ := ioutil.TempDir("/tmp", "bor-cli-test")
|
datadir, _ := os.MkdirTemp("/tmp", "bor-cli-test")
|
||||||
config.DataDir = datadir
|
config.DataDir = datadir
|
||||||
|
|
||||||
// find available port for http server
|
// find available port for http server
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon" //nolint:typecheck
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor" //nolint:typecheck
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
|
|
@ -182,7 +182,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
|
|
||||||
// graphql is started from another place
|
// graphql is started from another place
|
||||||
if config.JsonRPC.Graphql.Enabled {
|
if config.JsonRPC.Graphql.Enabled {
|
||||||
if err := graphql.New(stack, srv.backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil {
|
if err := graphql.New(stack, srv.backend.APIBackend, config.JsonRPC.Graphql.Cors, config.JsonRPC.Graphql.VHost); err != nil {
|
||||||
return nil, fmt.Errorf("failed to register the GraphQL service: %v", err)
|
return nil, fmt.Errorf("failed to register the GraphQL service: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +201,7 @@ func NewServer(config *Config) (*Server, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := srv.setupMetrics(config.Telemetry, config.Name); err != nil {
|
if err := srv.setupMetrics(config.Telemetry, config.Identity); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/tyler-smith/go-bip39"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
|
@ -47,7 +49,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/tyler-smith/go-bip39"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicEthereumAPI provides an API to access Ethereum related information.
|
// PublicEthereumAPI provides an API to access Ethereum related information.
|
||||||
|
|
@ -829,10 +830,10 @@ func (s *PublicBlockChainAPI) getAuthor(head *types.Header) *common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByNumber returns the requested canonical block.
|
// GetBlockByNumber returns the requested canonical block.
|
||||||
// * When blockNr is -1 the chain head is returned.
|
// - When blockNr is -1 the chain head is returned.
|
||||||
// * When blockNr is -2 the pending chain head is returned.
|
// - When blockNr is -2 the pending chain head is returned.
|
||||||
// * When fullTx is true all transactions in the block are returned, otherwise
|
// - When fullTx is true all transactions in the block are returned, otherwise
|
||||||
// only the transaction hash is returned.
|
// only the transaction hash is returned.
|
||||||
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||||
block, err := s.b.BlockByNumber(ctx, number)
|
block, err := s.b.BlockByNumber(ctx, number)
|
||||||
if block != nil && err == nil {
|
if block != nil && err == nil {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader/whitelist"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -145,7 +146,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
|
||||||
}
|
}
|
||||||
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
|
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
|
||||||
// indexers already set but not started yet
|
// indexers already set but not started yet
|
||||||
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil {
|
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint, whitelist.NewService(10)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
leth.chainReader = leth.blockchain
|
leth.chainReader = leth.blockchain
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index
|
||||||
oracle *checkpointoracle.CheckpointOracle
|
oracle *checkpointoracle.CheckpointOracle
|
||||||
)
|
)
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil)
|
chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil, nil)
|
||||||
if indexers != nil {
|
if indexers != nil {
|
||||||
checkpointConfig := ¶ms.CheckpointOracleConfig{
|
checkpointConfig := ¶ms.CheckpointOracleConfig{
|
||||||
Address: crypto.CreateAddress(bankAddr, 0),
|
Address: crypto.CreateAddress(bankAddr, 0),
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -37,7 +40,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -81,7 +83,7 @@ type LightChain struct {
|
||||||
// NewLightChain returns a fully initialised light chain using information
|
// NewLightChain returns a fully initialised light chain using information
|
||||||
// available in the database. It initialises the default Ethereum header
|
// available in the database. It initialises the default Ethereum header
|
||||||
// validator.
|
// validator.
|
||||||
func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) {
|
func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint, checker ethereum.ChainValidator) (*LightChain, error) {
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||||
blockCache, _ := lru.New(blockCacheLimit)
|
blockCache, _ := lru.New(blockCacheLimit)
|
||||||
|
|
@ -96,7 +98,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.
|
||||||
blockCache: blockCache,
|
blockCache: blockCache,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
}
|
}
|
||||||
bc.forker = core.NewForkChoice(bc, nil)
|
bc.forker = core.NewForkChoice(bc, nil, checker)
|
||||||
var err error
|
var err error
|
||||||
bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt)
|
bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
gspec := core.Genesis{Config: params.TestChainConfig}
|
gspec := core.Genesis{Config: params.TestChainConfig}
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil)
|
blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil, nil)
|
||||||
|
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
|
@ -76,7 +76,7 @@ func newTestLightChain() *LightChain {
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
}
|
}
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil)
|
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +347,7 @@ func TestReorgBadHeaderHashes(t *testing.T) {
|
||||||
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
|
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
|
||||||
|
|
||||||
// Create a new LightChain and check that it rolled back the state.
|
// Create a new LightChain and check that it rolled back the state.
|
||||||
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil)
|
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -261,14 +261,14 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig}
|
odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig}
|
||||||
lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil)
|
lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ func TestNodeIterator(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(fulldb)
|
genesis = gspec.MustCommit(fulldb)
|
||||||
)
|
)
|
||||||
gspec.MustCommit(lightdb)
|
gspec.MustCommit(lightdb)
|
||||||
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func TestTxPool(t *testing.T) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -103,7 +103,7 @@ func TestTxPool(t *testing.T) {
|
||||||
discard: make(chan int, 1),
|
discard: make(chan int, 1),
|
||||||
mined: make(chan int, 1),
|
mined: make(chan int, 1),
|
||||||
}
|
}
|
||||||
lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil)
|
lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil, nil)
|
||||||
txPermanent = 50
|
txPermanent = 50
|
||||||
pool := NewTxPool(params.TestChainConfig, lightchain, relay)
|
pool := NewTxPool(params.TestChainConfig, lightchain, relay)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, he
|
||||||
engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock)
|
||||||
|
|
||||||
// Create Ethereum backend
|
// Create Ethereum backend
|
||||||
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil)
|
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("can't create new chain %v", err)
|
t.Fatalf("can't create new chain %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func newTestWorkerBackend(t TensingObject, chainConfig *params.ChainConfig, engi
|
||||||
|
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
||||||
|
|
||||||
// Generate a small n-block chain and an uncle block for it
|
// Generate a small n-block chain and an uncle block for it
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) {
|
||||||
db2 := rawdb.NewMemoryDatabase()
|
db2 := rawdb.NewMemoryDatabase()
|
||||||
b.Genesis.MustCommit(db2)
|
b.Genesis.MustCommit(db2)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
@ -650,7 +650,7 @@ func BenchmarkBorMining(b *testing.B) {
|
||||||
db2 := rawdb.NewMemoryDatabase()
|
db2 := rawdb.NewMemoryDatabase()
|
||||||
back.Genesis.MustCommit(db2)
|
back.Genesis.MustCommit(db2)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db2, nil, back.chain.Config(), engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db2, nil, back.chain.Config(), engine, vm.Config{}, nil, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,8 @@ func (t *BlockTest) Run(snapshotter bool) error {
|
||||||
cache.SnapshotLimit = 1
|
cache.SnapshotLimit = 1
|
||||||
cache.SnapshotWait = true
|
cache.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil)
|
|
||||||
|
chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
168
tests/bor/bor_api_test.go
Normal file
168
tests/bor/bor_api_test.go
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetTransactionReceiptsByBlock(t *testing.T) {
|
||||||
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||||
|
chain := init.ethereum.BlockChain()
|
||||||
|
engine := init.ethereum.Engine()
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
_bor := engine.(*bor.Bor)
|
||||||
|
defer _bor.Close()
|
||||||
|
|
||||||
|
// Mock /bor/span/1
|
||||||
|
res, _ := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
|
|
||||||
|
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).MinTimes(1)
|
||||||
|
h.EXPECT().Close().MinTimes(1)
|
||||||
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{
|
||||||
|
Proposer: res.Result.SelectedProducers[0].Address,
|
||||||
|
StartBlock: big.NewInt(0),
|
||||||
|
EndBlock: big.NewInt(int64(spanSize)),
|
||||||
|
}, nil).AnyTimes()
|
||||||
|
|
||||||
|
// Mock State Sync events
|
||||||
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||||
|
fromID := uint64(1)
|
||||||
|
to := int64(chain.GetHeaderByNumber(0).Time)
|
||||||
|
sample := getSampleEventRecord(t)
|
||||||
|
|
||||||
|
// First query will be from [id=1, (block-sprint).Time]
|
||||||
|
eventRecords := []*clerk.EventRecordWithTime{
|
||||||
|
buildStateEvent(sample, 1, 1),
|
||||||
|
buildStateEvent(sample, 2, 2),
|
||||||
|
buildStateEvent(sample, 3, 3),
|
||||||
|
}
|
||||||
|
|
||||||
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||||
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
|
// Insert blocks for 0th sprint
|
||||||
|
db := init.ethereum.ChainDb()
|
||||||
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
signer := types.LatestSigner(init.genesis.Config)
|
||||||
|
toAddress := common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
|
||||||
|
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
txHashes := map[int]common.Hash{} // blockNumber -> txHash
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
nonce uint64
|
||||||
|
tx *types.Transaction
|
||||||
|
txs []*types.Transaction
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := uint64(1); i <= sprintSize; i++ {
|
||||||
|
if IsSpanEnd(i) {
|
||||||
|
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i%3 == 0 {
|
||||||
|
txdata := &types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &toAddress,
|
||||||
|
Gas: 30000,
|
||||||
|
GasPrice: newGwei(5),
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce++
|
||||||
|
|
||||||
|
tx = types.NewTx(txdata)
|
||||||
|
tx, err = types.SignTx(tx, signer, key)
|
||||||
|
require.Nil(t, err, "an incorrect transaction or signer")
|
||||||
|
|
||||||
|
txs = []*types.Transaction{tx}
|
||||||
|
} else {
|
||||||
|
txs = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, txs, currentValidators)
|
||||||
|
insertNewBlock(t, chain, block)
|
||||||
|
|
||||||
|
if len(txs) != 0 {
|
||||||
|
txHashes[int(block.Number().Uint64())] = tx.Hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// state 6 was not written
|
||||||
|
//
|
||||||
|
fromID = uint64(4)
|
||||||
|
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
|
||||||
|
|
||||||
|
eventRecords = []*clerk.EventRecordWithTime{
|
||||||
|
buildStateEvent(sample, 4, 4),
|
||||||
|
buildStateEvent(sample, 5, 5),
|
||||||
|
}
|
||||||
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).MinTimes(1)
|
||||||
|
|
||||||
|
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||||
|
insertNewBlock(t, chain, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
ethAPI := ethapi.NewPublicBlockChainAPI(init.ethereum.APIBackend)
|
||||||
|
txPoolAPI := ethapi.NewPublicTransactionPoolAPI(init.ethereum.APIBackend, nil)
|
||||||
|
|
||||||
|
for n := 0; n < int(spanSize)+1; n++ {
|
||||||
|
rpcNumber := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(n))
|
||||||
|
|
||||||
|
txs, err := ethAPI.GetTransactionReceiptsByBlock(context.Background(), rpcNumber)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
tx := txPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(n), 0)
|
||||||
|
|
||||||
|
blockMap, err := ethAPI.GetBlockByNumber(context.Background(), rpc.BlockNumber(n), true)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
expectedTxHash, ok := txHashes[n]
|
||||||
|
// FIXME: add `IsSprintStart(uint64(n)) || IsSpanStart(uint64(n))` after adding a full state receiver contract
|
||||||
|
if ok {
|
||||||
|
require.Len(t, txs, 1)
|
||||||
|
|
||||||
|
require.NotNil(t, tx, "not nil receipt expected")
|
||||||
|
|
||||||
|
require.Equal(t, expectedTxHash, tx.Hash, "got different from expected receipt")
|
||||||
|
|
||||||
|
blockTxs, ok := blockMap["transactions"].([]interface{})
|
||||||
|
require.Len(t, blockTxs, 1)
|
||||||
|
|
||||||
|
blockTx, ok := blockTxs[0].(*ethapi.RPCTransaction)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, expectedTxHash, blockTx.Hash)
|
||||||
|
} else {
|
||||||
|
require.Len(t, txs, 0)
|
||||||
|
|
||||||
|
require.Nil(t, tx, "nil receipt expected")
|
||||||
|
|
||||||
|
blockTxs, _ := blockMap["transactions"].([]interface{})
|
||||||
|
require.Len(t, blockTxs, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,14 +11,15 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
|
@ -38,13 +39,13 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
|
|
||||||
defer _bor.Close()
|
defer _bor.Close()
|
||||||
|
|
||||||
h, heimdallSpan, ctrl := getMockedHeimdallClient(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
_, currentSpan := loadSpanFromFile(t)
|
_, currentSpan := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
h, ctrl := getMockedHeimdallClient(t, currentSpan)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
h.EXPECT().FetchLatestCheckpoint(gomock.Any()).Return(&checkpoint.Checkpoint{
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{
|
||||||
Proposer: currentSpan.SelectedProducers[0].Address,
|
Proposer: currentSpan.SelectedProducers[0].Address,
|
||||||
StartBlock: big.NewInt(0),
|
StartBlock: big.NewInt(0),
|
||||||
EndBlock: big.NewInt(int64(spanSize)),
|
EndBlock: big.NewInt(int64(spanSize)),
|
||||||
|
|
@ -56,9 +57,11 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
// to := int64(block.Header().Time)
|
// to := int64(block.Header().Time)
|
||||||
|
|
||||||
|
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
|
||||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||||
for i := uint64(1); i <= spanSize; i++ {
|
for i := uint64(1); i <= spanSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,10 +70,10 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, 3, len(validators))
|
require.Equal(t, 3, len(validators))
|
||||||
for i, validator := range validators {
|
for i, validator := range validators {
|
||||||
assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
|
require.Equal(t, validator.Address.Bytes(), currentSpan.SelectedProducers[i].Address.Bytes())
|
||||||
assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
|
require.Equal(t, validator.VotingPower, currentSpan.SelectedProducers[i].VotingPower)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,16 +88,23 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
||||||
// A. Insert blocks for 0th sprint
|
// A. Insert blocks for 0th sprint
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
// B.1 Mock /bor/span/1
|
||||||
|
res, _ := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
|
||||||
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
|
||||||
for i := uint64(1); i < sprintSize; i++ {
|
for i := uint64(1); i < sprintSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
if IsSpanEnd(i) {
|
||||||
|
currentValidators = res.Result.ValidatorSet.Validators
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// B. Before inserting 1st block of the next sprint, mock heimdall deps
|
// B. Before inserting 1st block of the next sprint, mock heimdall deps
|
||||||
// B.1 Mock /bor/span/1
|
|
||||||
res, _ := loadSpanFromFile(t)
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
defer ctrl.Finish()
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
|
@ -115,7 +125,7 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
||||||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,6 +140,9 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
// Mock /bor/span/1
|
// Mock /bor/span/1
|
||||||
res, _ := loadSpanFromFile(t)
|
res, _ := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
// add the block producer
|
||||||
|
res.Result.ValidatorSet.Validators = append(res.Result.ValidatorSet.Validators, valset.NewValidator(addr, 4500))
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
defer ctrl.Finish()
|
defer ctrl.Finish()
|
||||||
|
|
||||||
|
|
@ -160,15 +173,24 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
// Insert blocks for 0th sprint
|
// Insert blocks for 0th sprint
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
var currentValidators []*valset.Validator
|
||||||
|
|
||||||
for i := uint64(1); i <= sprintSize; i++ {
|
for i := uint64(1); i <= sprintSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
if IsSpanEnd(i) {
|
||||||
|
currentValidators = res.Result.ValidatorSet.Validators
|
||||||
|
} else {
|
||||||
|
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
|
||||||
|
|
||||||
// state 6 was not written
|
// state 6 was not written
|
||||||
assert.Equal(t, uint64(4), lastStateID.Uint64())
|
require.Equal(t, uint64(4), lastStateID.Uint64())
|
||||||
|
|
||||||
//
|
//
|
||||||
fromID = uint64(5)
|
fromID = uint64(5)
|
||||||
|
|
@ -181,12 +203,18 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes()
|
||||||
|
|
||||||
for i := sprintSize + 1; i <= spanSize; i++ {
|
for i := sprintSize + 1; i <= spanSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
if IsSpanEnd(i) {
|
||||||
|
currentValidators = res.Result.ValidatorSet.Validators
|
||||||
|
} else {
|
||||||
|
currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)}
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
|
||||||
assert.Equal(t, uint64(6), lastStateID.Uint64())
|
require.Equal(t, uint64(6), lastStateID.Uint64())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOutOfTurnSigning(t *testing.T) {
|
func TestOutOfTurnSigning(t *testing.T) {
|
||||||
|
|
@ -197,17 +225,29 @@ func TestOutOfTurnSigning(t *testing.T) {
|
||||||
|
|
||||||
defer _bor.Close()
|
defer _bor.Close()
|
||||||
|
|
||||||
h, _, ctrl := getMockedHeimdallClient(t)
|
_, heimdallSpan := loadSpanFromFile(t)
|
||||||
|
proposer := valset.NewValidator(addr, 10)
|
||||||
|
heimdallSpan.ValidatorSet.Validators = append(heimdallSpan.ValidatorSet.Validators, proposer)
|
||||||
|
|
||||||
|
// add the block producer
|
||||||
|
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
|
||||||
defer ctrl.Finish()
|
defer ctrl.Finish()
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
setDifficulty := func(header *types.Header) {
|
||||||
|
if IsSprintStart(header.Number.Uint64()) {
|
||||||
|
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i := uint64(1); i < spanSize; i++ {
|
for i := uint64(1); i < spanSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setDifficulty)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,36 +255,50 @@ func TestOutOfTurnSigning(t *testing.T) {
|
||||||
// This account is one the out-of-turn validators for 1st (0-indexed) span
|
// This account is one the out-of-turn validators for 1st (0-indexed) span
|
||||||
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
|
||||||
signerKey, _ := hex.DecodeString(signer)
|
signerKey, _ := hex.DecodeString(signer)
|
||||||
key, _ = crypto.HexToECDSA(signer)
|
newKey, _ := crypto.HexToECDSA(signer)
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
|
||||||
expectedSuccessionNumber := 2
|
expectedSuccessionNumber := 2
|
||||||
|
|
||||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
parentTime := block.Time()
|
||||||
_, err := chain.InsertChain([]*types.Block{block})
|
|
||||||
assert.Equal(t,
|
|
||||||
*err.(*bor.BlockTooSoonError),
|
|
||||||
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
|
|
||||||
|
|
||||||
expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
|
setParentTime := func(header *types.Header) {
|
||||||
|
header.Time = parentTime + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const turn = 1
|
||||||
|
|
||||||
|
setDifficulty = func(header *types.Header) {
|
||||||
|
header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)) - turn)
|
||||||
|
}
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setParentTime, setDifficulty)
|
||||||
|
_, err := chain.InsertChain([]*types.Block{block})
|
||||||
|
require.Equal(t,
|
||||||
|
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber},
|
||||||
|
*err.(*bor.BlockTooSoonError))
|
||||||
|
|
||||||
|
expectedDifficulty := uint64(len(heimdallSpan.ValidatorSet.Validators) - expectedSuccessionNumber - turn) // len(validators) - succession
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
|
|
||||||
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
|
diff := bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor)
|
||||||
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor)
|
header.Time += diff
|
||||||
|
|
||||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||||
|
|
||||||
block = types.NewBlockWithHeader(header)
|
block = types.NewBlockWithHeader(header)
|
||||||
|
|
||||||
_, err = chain.InsertChain([]*types.Block{block})
|
_, err = chain.InsertChain([]*types.Block{block})
|
||||||
assert.Equal(t,
|
require.NotNil(t, err)
|
||||||
*err.(*bor.WrongDifficultyError),
|
require.Equal(t,
|
||||||
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
|
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: newAddr.Bytes()},
|
||||||
|
*err.(*bor.WrongDifficultyError))
|
||||||
|
|
||||||
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
||||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||||
block = types.NewBlockWithHeader(header)
|
block = types.NewBlockWithHeader(header)
|
||||||
|
|
||||||
_, err = chain.InsertChain([]*types.Block{block})
|
_, err = chain.InsertChain([]*types.Block{block})
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignerNotFound(t *testing.T) {
|
func TestSignerNotFound(t *testing.T) {
|
||||||
|
|
@ -255,7 +309,9 @@ func TestSignerNotFound(t *testing.T) {
|
||||||
|
|
||||||
defer _bor.Close()
|
defer _bor.Close()
|
||||||
|
|
||||||
h, _, ctrl := getMockedHeimdallClient(t)
|
_, heimdallSpan := loadSpanFromFile(t)
|
||||||
|
|
||||||
|
h, ctrl := getMockedHeimdallClient(t, heimdallSpan)
|
||||||
defer ctrl.Finish()
|
defer ctrl.Finish()
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
@ -266,62 +322,21 @@ func TestSignerNotFound(t *testing.T) {
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
// random signer account that is not a part of the validator set
|
// random signer account that is not a part of the validator set
|
||||||
signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
|
const signer = "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
|
||||||
signerKey, _ := hex.DecodeString(signer)
|
signerKey, _ := hex.DecodeString(signer)
|
||||||
key, _ = crypto.HexToECDSA(signer)
|
newKey, _ := crypto.HexToECDSA(signer)
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
newAddr := crypto.PubkeyToAddress(newKey.PublicKey)
|
||||||
|
|
||||||
|
_bor.Authorize(newAddr, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||||
|
return crypto.Sign(crypto.Keccak256(data), newKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators)
|
||||||
|
|
||||||
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
|
|
||||||
_, err := chain.InsertChain([]*types.Block{block})
|
_, err := chain.InsertChain([]*types.Block{block})
|
||||||
assert.Equal(t,
|
require.Equal(t,
|
||||||
*err.(*bor.UnauthorizedSignerError),
|
*err.(*bor.UnauthorizedSignerError),
|
||||||
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
|
bor.UnauthorizedSignerError{Number: 0, Signer: newAddr.Bytes()})
|
||||||
}
|
|
||||||
|
|
||||||
func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
|
||||||
|
|
||||||
_, heimdallSpan := loadSpanFromFile(t)
|
|
||||||
|
|
||||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
|
||||||
|
|
||||||
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()).
|
|
||||||
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
|
||||||
|
|
||||||
return h, heimdallSpan, ctrl
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
|
||||||
events := make([]*clerk.EventRecordWithTime, count)
|
|
||||||
event := *sample
|
|
||||||
event.ID = 1
|
|
||||||
events[0] = &clerk.EventRecordWithTime{}
|
|
||||||
*events[0] = event
|
|
||||||
for i := 1; i < count; i++ {
|
|
||||||
event.ID = uint64(i)
|
|
||||||
event.Time = event.Time.Add(1 * time.Second)
|
|
||||||
events[i] = &clerk.EventRecordWithTime{}
|
|
||||||
*events[i] = event
|
|
||||||
}
|
|
||||||
return events
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
|
||||||
event := *sample
|
|
||||||
event.ID = id
|
|
||||||
event.Time = time.Unix(timeStamp, 0)
|
|
||||||
return &event
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
|
||||||
eventRecords := stateSyncEventsPayload(t)
|
|
||||||
eventRecords.Result[0].Time = time.Unix(1, 0)
|
|
||||||
return eventRecords.Result[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEventRecords(t *testing.T) []*clerk.EventRecordWithTime {
|
|
||||||
return stateSyncEventsPayload(t).Result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEIP1559Transition tests the following:
|
// TestEIP1559Transition tests the following:
|
||||||
|
|
@ -351,7 +366,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||||
gspec = &core.Genesis{
|
gspec = &core.Genesis{
|
||||||
Config: params.BorTestChainConfig,
|
Config: params.BorUnittestChainConfig,
|
||||||
Alloc: core.GenesisAlloc{
|
Alloc: core.GenesisAlloc{
|
||||||
addr1: {Balance: funds},
|
addr1: {Balance: funds},
|
||||||
addr2: {Balance: funds},
|
addr2: {Balance: funds},
|
||||||
|
|
@ -403,7 +418,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -433,7 +448,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check burnt contract balance
|
// check burnt contract balance
|
||||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||||
expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
|
expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
|
||||||
burntContractBalance := expected
|
burntContractBalance := expected
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
|
|
@ -481,7 +496,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check burnt contract balance
|
// check burnt contract balance
|
||||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||||
expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
|
expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
|
||||||
burntContractBalance = expected
|
burntContractBalance = expected
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
|
|
@ -539,7 +554,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
state, _ = chain.State()
|
state, _ = chain.State()
|
||||||
|
|
||||||
// check burnt contract balance
|
// check burnt contract balance
|
||||||
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
|
||||||
burntAmount := new(big.Int).Mul(
|
burntAmount := new(big.Int).Mul(
|
||||||
block.BaseFee(),
|
block.BaseFee(),
|
||||||
big.NewInt(int64(block.GasUsed())),
|
big.NewInt(int64(block.GasUsed())),
|
||||||
|
|
@ -550,25 +565,188 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGwei(n int64) *big.Int {
|
// EIP1559 is not supported without EIP155. An error is expected
|
||||||
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
func TestEIP1559TransitionWithEIP155(t *testing.T) {
|
||||||
|
var (
|
||||||
|
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
|
||||||
|
// Generate a canonical chain to act as the main dataset
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
|
||||||
|
// A sender who makes transactions, has some funds
|
||||||
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
|
||||||
|
|
||||||
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
|
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||||
|
gspec = &core.Genesis{
|
||||||
|
Config: params.BorUnittestChainConfig,
|
||||||
|
Alloc: core.GenesisAlloc{
|
||||||
|
addr1: {Balance: funds},
|
||||||
|
addr2: {Balance: funds},
|
||||||
|
addr3: {Balance: funds},
|
||||||
|
// The address 0xAAAA sloads 0x00 and 0x01
|
||||||
|
aa: {
|
||||||
|
Code: []byte{
|
||||||
|
byte(vm.PC),
|
||||||
|
byte(vm.PC),
|
||||||
|
byte(vm.SLOAD),
|
||||||
|
byte(vm.SLOAD),
|
||||||
|
},
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: big.NewInt(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
|
// Use signer without chain ID
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
|
|
||||||
|
_, _ = core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
||||||
|
b.SetCoinbase(common.Address{1})
|
||||||
|
// One transaction to 0xAAAA
|
||||||
|
accesses := types.AccessList{types.AccessTuple{
|
||||||
|
Address: aa,
|
||||||
|
StorageKeys: []common.Hash{{0}},
|
||||||
|
}}
|
||||||
|
|
||||||
|
txdata := &types.DynamicFeeTx{
|
||||||
|
ChainID: gspec.Config.ChainID,
|
||||||
|
Nonce: 0,
|
||||||
|
To: &aa,
|
||||||
|
Gas: 30000,
|
||||||
|
GasFeeCap: newGwei(5),
|
||||||
|
GasTipCap: big.NewInt(2),
|
||||||
|
AccessList: accesses,
|
||||||
|
Data: []byte{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := types.NewTx(txdata)
|
||||||
|
tx, err = types.SignTx(tx, signer, key1)
|
||||||
|
|
||||||
|
require.ErrorIs(t, err, types.ErrTxTypeNotSupported)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is up to a user to use protected transactions. so if a transaction is unprotected no errors related to chainID are expected.
|
||||||
|
// transactions are checked in 2 places: transaction pool and blockchain processor.
|
||||||
|
func TestTransitionWithoutEIP155(t *testing.T) {
|
||||||
|
var (
|
||||||
|
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
|
||||||
|
// Generate a canonical chain to act as the main dataset
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
|
||||||
|
// A sender who makes transactions, has some funds
|
||||||
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
|
||||||
|
|
||||||
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
|
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||||
|
gspec = &core.Genesis{
|
||||||
|
Config: params.BorUnittestChainConfig,
|
||||||
|
Alloc: core.GenesisAlloc{
|
||||||
|
addr1: {Balance: funds},
|
||||||
|
addr2: {Balance: funds},
|
||||||
|
addr3: {Balance: funds},
|
||||||
|
// The address 0xAAAA sloads 0x00 and 0x01
|
||||||
|
aa: {
|
||||||
|
Code: []byte{
|
||||||
|
byte(vm.PC),
|
||||||
|
byte(vm.PC),
|
||||||
|
byte(vm.SLOAD),
|
||||||
|
byte(vm.SLOAD),
|
||||||
|
},
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: big.NewInt(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
|
// Use signer without chain ID
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
|
//signer := types.FrontierSigner{}
|
||||||
|
|
||||||
|
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
|
||||||
|
b.SetCoinbase(common.Address{1})
|
||||||
|
|
||||||
|
txdata := &types.LegacyTx{
|
||||||
|
Nonce: 0,
|
||||||
|
To: &aa,
|
||||||
|
Gas: 30000,
|
||||||
|
GasPrice: newGwei(5),
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := types.NewTx(txdata)
|
||||||
|
tx, err = types.SignTx(tx, signer, key1)
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.False(t, tx.Protected())
|
||||||
|
|
||||||
|
from, err := types.Sender(types.EIP155Signer{}, tx)
|
||||||
|
require.Equal(t, addr1, from)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
b.AddTx(tx)
|
||||||
|
})
|
||||||
|
|
||||||
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
|
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
if n, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block := chain.GetBlockByNumber(1)
|
||||||
|
|
||||||
|
require.Len(t, block.Transactions(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJaipurFork(t *testing.T) {
|
func TestJaipurFork(t *testing.T) {
|
||||||
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||||
chain := init.ethereum.BlockChain()
|
chain := init.ethereum.BlockChain()
|
||||||
engine := init.ethereum.Engine()
|
engine := init.ethereum.Engine()
|
||||||
|
|
||||||
_bor := engine.(*bor.Bor)
|
_bor := engine.(*bor.Bor)
|
||||||
|
defer _bor.Close()
|
||||||
|
|
||||||
db := init.ethereum.ChainDb()
|
db := init.ethereum.ChainDb()
|
||||||
block := init.genesis.ToBlock(db)
|
block := init.genesis.ToBlock(db)
|
||||||
|
|
||||||
|
res, _ := loadSpanFromFile(t)
|
||||||
|
|
||||||
for i := uint64(1); i < sprintSize; i++ {
|
for i := uint64(1); i < sprintSize; i++ {
|
||||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators)
|
||||||
insertNewBlock(t, chain, block)
|
insertNewBlock(t, chain, block)
|
||||||
|
|
||||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
|
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
|
||||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
|
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
|
||||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,63 @@
|
||||||
|
//go:build integration
|
||||||
|
|
||||||
package bor
|
package bor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
|
// Only this account is a validator for the 0th span
|
||||||
|
key, _ = crypto.HexToECDSA(privKey)
|
||||||
|
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
|
||||||
|
|
||||||
|
// This account is one the validators for 1st span (0-indexed)
|
||||||
|
key2, _ = crypto.HexToECDSA(privKey2)
|
||||||
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||||
|
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
||||||
|
|
||||||
// The genesis for tests was generated with following parameters
|
// The genesis for tests was generated with following parameters
|
||||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||||
|
|
||||||
// Only this account is a validator for the 0th span
|
sprintSize uint64 = 4
|
||||||
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
spanSize uint64 = 8
|
||||||
key, _ = crypto.HexToECDSA(privKey)
|
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
|
|
||||||
|
|
||||||
// This account is one the validators for 1st span (0-indexed)
|
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
||||||
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
|
||||||
key2, _ = crypto.HexToECDSA(privKey2)
|
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
|
|
||||||
|
|
||||||
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
|
|
||||||
sprintSize uint64 = 4
|
|
||||||
spanSize uint64 = 8
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type initializeData struct {
|
type initializeData struct {
|
||||||
|
|
@ -49,8 +66,6 @@ type initializeData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
|
|
@ -64,6 +79,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||||
|
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
Genesis: gen,
|
Genesis: gen,
|
||||||
|
BorLogs: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ethConf.Genesis.MustCommit(db)
|
ethConf.Genesis.MustCommit(db)
|
||||||
|
|
@ -75,6 +91,10 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
|
||||||
|
|
||||||
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
ethConf.Genesis.MustCommit(ethereum.ChainDb())
|
||||||
|
|
||||||
|
ethereum.Engine().(*bor.Bor).Authorize(addr, func(account accounts.Account, s string, data []byte) ([]byte, error) {
|
||||||
|
return crypto.Sign(crypto.Keccak256(data), key)
|
||||||
|
})
|
||||||
|
|
||||||
return &initializeData{
|
return &initializeData{
|
||||||
genesis: gen,
|
genesis: gen,
|
||||||
ethereum: ethereum,
|
ethereum: ethereum,
|
||||||
|
|
@ -89,33 +109,31 @@ func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block {
|
type Option func(header *types.Header)
|
||||||
|
|
||||||
|
func buildNextBlock(t *testing.T, _bor consensus.Engine, chain *core.BlockChain, parentBlock *types.Block, signer []byte, borConfig *params.BorConfig, txs []*types.Transaction, currentValidators []*valset.Validator, opts ...Option) *types.Block {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
header := block.Header()
|
header := &types.Header{
|
||||||
header.Number.Add(header.Number, big.NewInt(1))
|
Number: big.NewInt(int64(parentBlock.Number().Uint64() + 1)),
|
||||||
|
Difficulty: big.NewInt(int64(parentBlock.Difficulty().Uint64())),
|
||||||
|
GasLimit: parentBlock.GasLimit(),
|
||||||
|
ParentHash: parentBlock.Hash(),
|
||||||
|
}
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
if signer == nil {
|
if signer == nil {
|
||||||
signer = getSignerKey(header.Number.Uint64())
|
signer = getSignerKey(header.Number.Uint64())
|
||||||
}
|
}
|
||||||
|
|
||||||
header.ParentHash = block.Hash()
|
header.Time = parentBlock.Time() + bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
||||||
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
|
|
||||||
header.Extra = make([]byte, 32+65) // vanity + extraSeal
|
header.Extra = make([]byte, 32+65) // vanity + extraSeal
|
||||||
|
|
||||||
currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)}
|
isSpanStart := IsSpanStart(number)
|
||||||
|
isSprintEnd := IsSprintEnd(number)
|
||||||
|
|
||||||
isSpanEnd := (number+1)%spanSize == 0
|
if isSpanStart {
|
||||||
isSpanStart := number%spanSize == 0
|
header.Difficulty = new(big.Int).SetInt64(int64(len(currentValidators)))
|
||||||
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
|
|
||||||
|
|
||||||
if isSpanEnd {
|
|
||||||
_, heimdallSpan := loadSpanFromFile(t)
|
|
||||||
// this is to stash the validator bytes in the header
|
|
||||||
currentValidators = heimdallSpan.ValidatorSet.Validators
|
|
||||||
} else if isSpanStart {
|
|
||||||
header.Difficulty = new(big.Int).SetInt64(3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSprintEnd {
|
if isSprintEnd {
|
||||||
|
|
@ -132,27 +150,87 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
||||||
}
|
}
|
||||||
|
|
||||||
if chain.Config().IsLondon(header.Number) {
|
if chain.Config().IsLondon(header.Number) {
|
||||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
header.BaseFee = misc.CalcBaseFee(chain.Config(), parentBlock.Header())
|
||||||
|
|
||||||
if !chain.Config().IsLondon(block.Number()) {
|
if !chain.Config().IsLondon(parentBlock.Number()) {
|
||||||
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
parentGasLimit := parentBlock.GasLimit() * params.ElasticityMultiplier
|
||||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(header)
|
||||||
|
}
|
||||||
|
|
||||||
state, err := chain.State()
|
state, err := chain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
|
b := &blockGen{header: header}
|
||||||
if err != nil {
|
for _, tx := range txs {
|
||||||
t.Fatalf("%s", err)
|
b.addTxWithChain(chain, state, tx, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
sign(t, header, signer, borConfig)
|
// Finalize and seal the block
|
||||||
|
block, _ := _bor.FinalizeAndAssemble(chain, b.header, state, b.txs, nil, b.receipts)
|
||||||
|
|
||||||
return types.NewBlockWithHeader(header)
|
// Write state changes to db
|
||||||
|
root, err := state.Commit(chain.Config().IsEIP158(b.header.Number))
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("state write error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.Database().TrieDB().Commit(root, false, nil); err != nil {
|
||||||
|
panic(fmt.Sprintf("trie write error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make(chan *types.Block, 1)
|
||||||
|
|
||||||
|
err = _bor.Seal(chain, block, res, nil)
|
||||||
|
if err != nil {
|
||||||
|
// an error case - sign manually
|
||||||
|
sign(t, header, signer, borConfig)
|
||||||
|
return types.NewBlockWithHeader(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <-res
|
||||||
|
}
|
||||||
|
|
||||||
|
type blockGen struct {
|
||||||
|
txs []*types.Transaction
|
||||||
|
receipts []*types.Receipt
|
||||||
|
gasPool *core.GasPool
|
||||||
|
header *types.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockGen) addTxWithChain(bc *core.BlockChain, statedb *state.StateDB, tx *types.Transaction, coinbase common.Address) {
|
||||||
|
if b.gasPool == nil {
|
||||||
|
b.setCoinbase(coinbase)
|
||||||
|
}
|
||||||
|
|
||||||
|
statedb.Prepare(tx.Hash(), len(b.txs))
|
||||||
|
|
||||||
|
receipt, err := core.ApplyTransaction(bc.Config(), bc, &b.header.Coinbase, b.gasPool, statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.txs = append(b.txs, tx)
|
||||||
|
b.receipts = append(b.receipts, receipt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blockGen) setCoinbase(addr common.Address) {
|
||||||
|
if b.gasPool != nil {
|
||||||
|
if len(b.txs) > 0 {
|
||||||
|
panic("coinbase must be set before adding transactions")
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("coinbase can only be set once")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.header.Coinbase = addr
|
||||||
|
b.gasPool = new(core.GasPool).AddGas(b.header.GasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
||||||
|
|
@ -204,13 +282,80 @@ func loadSpanFromFile(t *testing.T) (*heimdall.SpanResponse, *span.HeimdallSpan)
|
||||||
func getSignerKey(number uint64) []byte {
|
func getSignerKey(number uint64) []byte {
|
||||||
signerKey := privKey
|
signerKey := privKey
|
||||||
|
|
||||||
isSpanStart := number%spanSize == 0
|
if IsSpanStart(number) {
|
||||||
if isSpanStart {
|
|
||||||
// validator set in the new span has changed
|
// validator set in the new span has changed
|
||||||
signerKey = privKey2
|
signerKey = privKey2
|
||||||
}
|
}
|
||||||
|
|
||||||
_key, _ := hex.DecodeString(signerKey)
|
newKey, _ := hex.DecodeString(signerKey)
|
||||||
|
|
||||||
return _key
|
return newKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMockedHeimdallClient(t *testing.T, heimdallSpan *span.HeimdallSpan) (*mocks.MockIHeimdallClient, *gomock.Controller) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
|
|
||||||
|
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(heimdallSpan, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
|
Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes()
|
||||||
|
|
||||||
|
return h, ctrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime {
|
||||||
|
events := make([]*clerk.EventRecordWithTime, count)
|
||||||
|
event := *sample
|
||||||
|
event.ID = 1
|
||||||
|
events[0] = &clerk.EventRecordWithTime{}
|
||||||
|
*events[0] = event
|
||||||
|
|
||||||
|
for i := 1; i < count; i++ {
|
||||||
|
event.ID = uint64(i)
|
||||||
|
event.Time = event.Time.Add(1 * time.Second)
|
||||||
|
events[i] = &clerk.EventRecordWithTime{}
|
||||||
|
*events[i] = event
|
||||||
|
}
|
||||||
|
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime {
|
||||||
|
event := *sample
|
||||||
|
event.ID = id
|
||||||
|
event.Time = time.Unix(timeStamp, 0)
|
||||||
|
|
||||||
|
return &event
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
eventRecords := stateSyncEventsPayload(t)
|
||||||
|
eventRecords.Result[0].Time = time.Unix(1, 0)
|
||||||
|
|
||||||
|
return eventRecords.Result[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGwei(n int64) *big.Int {
|
||||||
|
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSpanEnd(number uint64) bool {
|
||||||
|
return (number+1)%spanSize == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSpanStart(number uint64) bool {
|
||||||
|
return number%spanSize == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSprintStart(number uint64) bool {
|
||||||
|
return number%sprintSize == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSprintEnd(number uint64) bool {
|
||||||
|
return (number+1)%sprintSize == 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,19 +49,34 @@ func (mr *MockIHeimdallClientMockRecorder) Close() *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchLatestCheckpoint mocks base method.
|
// FetchCheckpoint mocks base method.
|
||||||
func (m *MockIHeimdallClient) FetchLatestCheckpoint(arg0 context.Context) (*checkpoint.Checkpoint, error) {
|
func (m *MockIHeimdallClient) FetchCheckpoint(arg0 context.Context, arg1 int64) (*checkpoint.Checkpoint, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchLatestCheckpoint", arg0)
|
ret := m.ctrl.Call(m, "FetchCheckpoint", arg0, arg1)
|
||||||
ret0, _ := ret[0].(*checkpoint.Checkpoint)
|
ret0, _ := ret[0].(*checkpoint.Checkpoint)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchLatestCheckpoint indicates an expected call of FetchLatestCheckpoint.
|
// FetchCheckpoint indicates an expected call of FetchCheckpoint.
|
||||||
func (mr *MockIHeimdallClientMockRecorder) FetchLatestCheckpoint(arg0 interface{}) *gomock.Call {
|
func (mr *MockIHeimdallClientMockRecorder) FetchCheckpoint(arg0, arg1 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchLatestCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchLatestCheckpoint), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpoint), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchCheckpointCount mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchCheckpointCount(arg0 context.Context) (int64, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchCheckpointCount", arg0)
|
||||||
|
ret0, _ := ret[0].(int64)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchCheckpointCount indicates an expected call of FetchCheckpointCount.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchCheckpointCount(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpointCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpointCount), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Span mocks base method.
|
// Span mocks base method.
|
||||||
|
|
|
||||||
3
tests/bor/testdata/genesis.json
vendored
3
tests/bor/testdata/genesis.json
vendored
|
|
@ -52,6 +52,9 @@
|
||||||
},
|
},
|
||||||
"71562b71999873DB5b286dF957af199Ec94617F7": {
|
"71562b71999873DB5b286dF957af199Ec94617F7": {
|
||||||
"balance": "0x3635c9adc5dea00000"
|
"balance": "0x3635c9adc5dea00000"
|
||||||
|
},
|
||||||
|
"9fB29AAc15b9A4B7F17c3385939b007540f4d791": {
|
||||||
|
"balance": "0x3635c9adc5dea00000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"number": "0x0",
|
"number": "0x0",
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) {
|
||||||
addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:]))
|
addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:]))
|
||||||
txHashes = append(txHashes, tx.Hash())
|
txHashes = append(txHashes, tx.Hash())
|
||||||
})
|
})
|
||||||
bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func getChain() *core.BlockChain {
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
}
|
}
|
||||||
trieRoot = blocks[len(blocks)-1].Root()
|
trieRoot = blocks[len(blocks)-1].Root()
|
||||||
bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue