diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d13682d0c3..a7c3b246fe 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, true) } 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/consensus/consortium/main.go b/consensus/consortium/main.go index c8e608de3f..519e4a601a 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, skipV1Check bool) *Consortium { // Set any missing consensus parameters to their defaults - consortiumV1 := v1.New(chainConfig, db, ee) - consortiumV2 := v2.New(chainConfig, db, ee, genesisHash, consortiumV1) + consortiumV1 := v1.New(chainConfig, db, ee, skipV1Check) + consortiumV2 := v2.New(chainConfig, db, ee, consortiumV1) return &Consortium{ chainConfig: chainConfig, 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/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..4f8c10ec45 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 = "" @@ -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 diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b9a999e62b..5681bea965 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, false) } // 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(),