From 3815939f9b13250e0d19e4254bf1035c2dd74ae7 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 18 Oct 2023 18:19:50 +0700 Subject: [PATCH 1/3] consortium: remove unused genesis in consensus engine --- consensus/consortium/main.go | 4 ++-- consensus/consortium/v2/consortium.go | 3 --- eth/backend.go | 2 +- eth/ethconfig/config.go | 12 ++++++++++-- les/client.go | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/consensus/consortium/main.go b/consensus/consortium/main.go index c8e608de3f..b2863c6f44 100644 --- a/consensus/consortium/main.go +++ b/consensus/consortium/main.go @@ -27,10 +27,10 @@ type Consortium struct { } // New creates a Consortium proxy that decides what Consortium version will be called -func New(chainConfig *params.ChainConfig, db ethdb.Database, ee *ethapi.PublicBlockChainAPI, genesisHash common.Hash) *Consortium { +func New(chainConfig *params.ChainConfig, db ethdb.Database, ee *ethapi.PublicBlockChainAPI) *Consortium { // Set any missing consensus parameters to their defaults consortiumV1 := v1.New(chainConfig, db, ee) - consortiumV2 := v2.New(chainConfig, db, ee, genesisHash, consortiumV1) + consortiumV2 := v2.New(chainConfig, db, ee, consortiumV1) return &Consortium{ chainConfig: chainConfig, diff --git a/consensus/consortium/v2/consortium.go b/consensus/consortium/v2/consortium.go index 0b91785870..106b8762ea 100644 --- a/consensus/consortium/v2/consortium.go +++ b/consensus/consortium/v2/consortium.go @@ -94,7 +94,6 @@ type Consortium struct { chainConfig *params.ChainConfig config *params.ConsortiumConfig // Consensus engine configuration parameters forkedBlock uint64 - genesisHash common.Hash db ethdb.Database // Database to store and retrieve snapshot checkpoints recents *lru.ARCCache // Snapshots for recent block to speed up reorgs @@ -120,7 +119,6 @@ func New( chainConfig *params.ChainConfig, db ethdb.Database, ethAPI *ethapi.PublicBlockChainAPI, - genesisHash common.Hash, v1 consortiumCommon.ConsortiumAdapter, ) *Consortium { consortiumConfig := chainConfig.Consortium @@ -136,7 +134,6 @@ func New( consortium := Consortium{ chainConfig: chainConfig, config: consortiumConfig, - genesisHash: genesisHash, db: db, ethAPI: ethAPI, recents: recents, diff --git a/eth/backend.go b/eth/backend.go index ed1132bcc2..bf1c383640 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -163,7 +163,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { log.Info("Unprotected transactions allowed") } ethAPI := ethapi.NewPublicBlockChainAPI(eth.APIBackend) - eth.engine = ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb, ethAPI, genesisHash) + eth.engine = ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb, ethAPI) bcVersion := rawdb.ReadDatabaseVersion(chainDb) var dbVer = "" diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b9a999e62b..870d99bb52 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -225,13 +225,21 @@ type Config struct { } // CreateConsensusEngine creates a consensus engine for the given chain configuration. -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database, ee *ethapi.PublicBlockChainAPI, genesisHash common.Hash) consensus.Engine { +func CreateConsensusEngine( + stack *node.Node, + chainConfig *params.ChainConfig, + config *ethash.Config, + notify []string, + noverify bool, + db ethdb.Database, + ee *ethapi.PublicBlockChainAPI, +) consensus.Engine { // If proof-of-authority is requested, set it up if chainConfig.Clique != nil { return clique.New(chainConfig.Clique, db) } if chainConfig.Consortium != nil { - return consortium.New(chainConfig, db, ee, genesisHash) + return consortium.New(chainConfig, db, ee) } // Otherwise assume proof-of-work switch config.PowMode { diff --git a/les/client.go b/les/client.go index 22ad5bfc82..45f5980068 100644 --- a/les/client.go +++ b/les/client.go @@ -109,7 +109,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { eventMux: stack.EventMux(), reqDist: newRequestDistributor(peers, &mclock.System{}), accountManager: stack.AccountManager(), - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb, nil, genesisHash), + engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb, nil), bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), p2pServer: stack.Server(), From e05432c42d08c53460b57c408a624b95c1ec326e Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 18 Oct 2023 18:24:24 +0700 Subject: [PATCH 2/3] chaincmd: correctly create consortium engine in import chain Currently, when import chain is used, we don't recognize the chain config to create the consortium engine. This commit creates the consortium engine when it is set in the chain config. --- cmd/utils/flags.go | 32 +++++++++++++++++++++++++++++++- eth/backend.go | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d13682d0c3..65e284e746 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -38,9 +38,11 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" + "github.com/ethereum/go-ethereum/consensus/consortium" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -2218,9 +2220,17 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai if err != nil { Fatalf("%v", err) } - var engine consensus.Engine + var ( + engine consensus.Engine + fixupEth func(chain *core.BlockChain, engine consensus.Engine) + ethApiBackend *eth.EthAPIBackend + ) if config.Clique != nil { engine = clique.New(config.Clique, chainDb) + } else if config.Consortium != nil { + ethApiBackend, fixupEth = eth.MakeEthApiBackend(chainDb) + ethApi := ethapi.NewPublicBlockChainAPI(ethApiBackend) + engine = consortium.New(config, chainDb, ethApi) } else { engine = ethash.NewFaker() if !ctx.Bool(FakePoWFlag.Name) { @@ -2269,6 +2279,26 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai if err != nil { Fatalf("Can't create BlockChain: %v", err) } + fixupEth(chain, engine) + if config.Consortium != nil { + c := engine.(*consortium.Consortium) + c.SetGetSCValidatorsFn(func() ([]common.Address, error) { + stateDb, err := chain.State() + if err != nil { + log.Crit("Cannot get state of blockchain", "err", err) + return nil, err + } + return state.GetSCValidators(stateDb), nil + }) + c.SetGetFenixValidators(func() ([]common.Address, error) { + stateDb, err := chain.State() + if err != nil { + log.Crit("Cannot get state of blockchain", "err", err) + return nil, err + } + return state.GetFenixValidators(stateDb, config.FenixValidatorContractAddress), nil + }) + } return chain, chainDb } diff --git a/eth/backend.go b/eth/backend.go index bf1c383640..4f8c10ec45 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -352,6 +352,24 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return eth, nil } +// MakeEthApiBackend is used by MakeChain to create a minimal eth API backend for consortium +// engine. +// This code looks hacky as it returns a function to set the private blockchain, engine field. +// This is due to the circular dependency as blockchain needs consortium engine which requires +// eth API backend. As the eth API backend is not used right after being created, we create a +// eth API backend without blockchain here and set that field later when blockchain is available. +func MakeEthApiBackend(chainDb ethdb.Database) (*EthAPIBackend, func(chain *core.BlockChain, engine consensus.Engine)) { + eth := &Ethereum{ + chainDb: chainDb, + config: ðconfig.Defaults, + } + apiBackend := &EthAPIBackend{eth: eth} + return apiBackend, func(chain *core.BlockChain, engine consensus.Engine) { + eth.blockchain = chain + eth.engine = engine + } +} + func makeExtraData(extra []byte) []byte { if len(extra) == 0 { // create default extradata From edb1059b7b0c74c7e17ab356e26a1cace6c52b82 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Thu, 16 May 2024 11:40:43 +0700 Subject: [PATCH 3/3] consortium-v1: add an option to disable checkpoint header check In version 1, the checkpoint header check happens early in the header verification step. This makes statedb read sometimes happens in incorrect statedb. While full sync, this leads to peer drop but still be able to continue syncing with other peers. However, while running import chain command or fast sync, this could lead to error. Add a option to disable checkpoint header check in these cases. --- cmd/utils/flags.go | 2 +- consensus/consortium/main.go | 4 +-- consensus/consortium/v1/consortium.go | 43 +++++++++++++++------------ eth/ethconfig/config.go | 2 +- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 65e284e746..a7c3b246fe 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2230,7 +2230,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai } else if config.Consortium != nil { ethApiBackend, fixupEth = eth.MakeEthApiBackend(chainDb) ethApi := ethapi.NewPublicBlockChainAPI(ethApiBackend) - engine = consortium.New(config, chainDb, ethApi) + engine = consortium.New(config, chainDb, ethApi, true) } else { engine = ethash.NewFaker() if !ctx.Bool(FakePoWFlag.Name) { diff --git a/consensus/consortium/main.go b/consensus/consortium/main.go index b2863c6f44..519e4a601a 100644 --- a/consensus/consortium/main.go +++ b/consensus/consortium/main.go @@ -27,9 +27,9 @@ type Consortium struct { } // New creates a Consortium proxy that decides what Consortium version will be called -func New(chainConfig *params.ChainConfig, db ethdb.Database, ee *ethapi.PublicBlockChainAPI) *Consortium { +func New(chainConfig *params.ChainConfig, db ethdb.Database, ee *ethapi.PublicBlockChainAPI, skipV1Check bool) *Consortium { // Set any missing consensus parameters to their defaults - consortiumV1 := v1.New(chainConfig, db, ee) + consortiumV1 := v1.New(chainConfig, db, ee, skipV1Check) consortiumV2 := v2.New(chainConfig, db, ee, consortiumV1) return &Consortium{ diff --git a/consensus/consortium/v1/consortium.go b/consensus/consortium/v1/consortium.go index 1adc03054b..e6b0b39c2c 100644 --- a/consensus/consortium/v1/consortium.go +++ b/consensus/consortium/v1/consortium.go @@ -117,11 +117,13 @@ type Consortium struct { getSCValidators func() ([]common.Address, error) // Get the list of validator from contract getFenixValidators func() ([]common.Address, error) // Get the validator list from Ronin Validator contract of Fenix hardfork + + skipCheckpointHeaderCheck bool } // New creates a Consortium proof-of-authority consensus engine with the initial // signers set to the ones provided by the user. -func New(chainConfig *params.ChainConfig, db ethdb.Database, ethAPI *ethapi.PublicBlockChainAPI) *Consortium { +func New(chainConfig *params.ChainConfig, db ethdb.Database, ethAPI *ethapi.PublicBlockChainAPI, skipCheckpointHeaderCheck bool) *Consortium { // Set any missing consensus parameters to their defaults consortiumConfig := *chainConfig.Consortium if consortiumConfig.Epoch == 0 { @@ -132,14 +134,15 @@ func New(chainConfig *params.ChainConfig, db ethdb.Database, ethAPI *ethapi.Publ signatures, _ := lru.NewARC(inmemorySignatures) consortium := Consortium{ - chainConfig: chainConfig, - config: &consortiumConfig, - db: db, - recents: recents, - signatures: signatures, - ethAPI: ethAPI, - proposals: make(map[common.Address]bool), - signer: types.NewEIP155Signer(chainConfig.ChainID), + chainConfig: chainConfig, + config: &consortiumConfig, + db: db, + recents: recents, + signatures: signatures, + ethAPI: ethAPI, + proposals: make(map[common.Address]bool), + signer: types.NewEIP155Signer(chainConfig.ChainID), + skipCheckpointHeaderCheck: skipCheckpointHeaderCheck, } err := consortium.initContract(common.Address{}, nil) @@ -277,17 +280,19 @@ func (c *Consortium) verifyCascadingFields(chain consensus.ChainHeaderReader, he return c.verifySeal(chain, header, parents) } - signers, err := c.getValidatorsFromContract(chain, number-1) - if err != nil { - return err - } + if !c.skipCheckpointHeaderCheck { + signers, err := c.getValidatorsFromContract(chain, number-1) + if err != nil { + return err + } - extraSuffix := len(header.Extra) - consortiumCommon.ExtraSeal - checkpointHeaders := consortiumCommon.ExtractAddressFromBytes(header.Extra[extraVanity:extraSuffix]) - validSigners := consortiumCommon.CompareSignersLists(checkpointHeaders, signers) - if !validSigners { - log.Error("signers lists are different in checkpoint header and snapshot", "number", number, "signersHeader", checkpointHeaders, "signers", signers) - return consortiumCommon.ErrInvalidCheckpointSigners + extraSuffix := len(header.Extra) - consortiumCommon.ExtraSeal + checkpointHeaders := consortiumCommon.ExtractAddressFromBytes(header.Extra[extraVanity:extraSuffix]) + validSigners := consortiumCommon.CompareSignersLists(checkpointHeaders, signers) + if !validSigners { + log.Error("signers lists are different in checkpoint header and snapshot", "number", number, "signersHeader", checkpointHeaders, "signers", signers) + return consortiumCommon.ErrInvalidCheckpointSigners + } } // All basic checks passed, verify the seal and return diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 870d99bb52..5681bea965 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -239,7 +239,7 @@ func CreateConsensusEngine( return clique.New(chainConfig.Clique, db) } if chainConfig.Consortium != nil { - return consortium.New(chainConfig, db, ee) + return consortium.New(chainConfig, db, ee, false) } // Otherwise assume proof-of-work switch config.PowMode {