Skip to content

Commit

Permalink
consortium/mock: implement consortiumv2 mocking logics which mocks al…
Browse files Browse the repository at this point in the history
…l contract interaction code

- This commit also adds `--mock.validators` and `--mock.blspublickeys` to simulate validators set and bls voting public keys
  • Loading branch information
DNK90 committed Nov 14, 2023
1 parent 061ab32 commit 62c9be3
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 46 deletions.
21 changes: 15 additions & 6 deletions cmd/ronin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ import (
"bufio"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"math/big"
"os"
"reflect"
"unicode"

"github.com/ethereum/go-ethereum/common"
consortiumCommon "github.com/ethereum/go-ethereum/consensus/consortium/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"gopkg.in/urfave/cli.v1"

"github.com/ethereum/go-ethereum/accounts/external"
Expand Down Expand Up @@ -88,10 +89,10 @@ type ethstatsConfig struct {
}

type gethConfig struct {
Eth ethconfig.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
Eth ethconfig.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
}

func loadConfig(file string, cfg *gethConfig) error {
Expand Down Expand Up @@ -152,6 +153,14 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
}
applyMetricConfig(ctx, &cfg)

// setup mock config
if ctx.GlobalIsSet(utils.MockValidatorsFlag.Name) && ctx.GlobalIsSet(utils.MockBlsPublicKeysFlag.Name) {
err = consortiumCommon.SetMockValidators(ctx.GlobalString(utils.MockValidatorsFlag.Name), ctx.GlobalString(utils.MockBlsPublicKeysFlag.Name))
if err != nil {
utils.Fatalf("failed on create mock validators %v", err)
}
}

return stack, cfg
}

Expand Down
6 changes: 6 additions & 0 deletions cmd/ronin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ var (
utils.PyroscopeBlockProfileRate,
utils.PyroscopeMutexProfileFraction,
}

mockFlags = []cli.Flag{
utils.MockValidatorsFlag,
utils.MockBlsPublicKeysFlag,
}
)

func init() {
Expand Down Expand Up @@ -281,6 +286,7 @@ func init() {
app.Flags = append(app.Flags, debug.Flags...)
app.Flags = append(app.Flags, metricsFlags...)
app.Flags = append(app.Flags, pyroscopeFlags...)
app.Flags = append(app.Flags, mockFlags...)

app.Before = func(ctx *cli.Context) error {
return debug.Setup(ctx)
Expand Down
7 changes: 7 additions & 0 deletions cmd/ronin/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.BlsWalletPath,
},
},
{
Name: "MOCK",
Flags: []cli.Flag{
utils.MockValidatorsFlag,
utils.MockBlsPublicKeysFlag,
},
},
}

func init() {
Expand Down
10 changes: 10 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,16 @@ var (
Name: "additionalchainevent.enable",
Usage: "Enable additional chain event",
}

MockValidatorsFlag = cli.StringFlag{
Name: "mock.validators",
Usage: "List of mock validators",
}

MockBlsPublicKeysFlag = cli.StringFlag{
Name: "mock.blspublickeys",
Usage: "List of mock bls public keys which are reflect 1:1 with mock.validators",
}
)

// MakeDataDir retrieves the currently requested data directory, terminating
Expand Down
80 changes: 80 additions & 0 deletions consensus/consortium/common/mock_contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package common

import (
"errors"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/bls/blst"
blsCommon "github.com/ethereum/go-ethereum/crypto/bls/common"
"github.com/ethereum/go-ethereum/log"
)

var Validators *MockValidators

type MockValidators struct {
validators []common.Address
blsPublicKeys map[common.Address]blsCommon.PublicKey
}

func SetMockValidators(validators, publicKeys string) error {
vals := strings.Split(validators, ",")
pubs := strings.Split(publicKeys, ",")
if len(vals) != len(pubs) {
return errors.New("mismatch length between mock validators and mock blsPubKey")
}
Validators = &MockValidators{
validators: make([]common.Address, len(vals)),
blsPublicKeys: make(map[common.Address]blsCommon.PublicKey),
}
for i, val := range vals {
Validators.validators[i] = common.HexToAddress(val)
pubKey, err := blst.PublicKeyFromBytes(common.Hex2Bytes(pubs[i]))
if err != nil {
return err
}
Validators.blsPublicKeys[Validators.validators[i]] = pubKey
}
return nil
}

func (m *MockValidators) GetValidators() []common.Address {
return m.validators
}

func (m *MockValidators) GetPublicKey(addr common.Address) (blsCommon.PublicKey, error) {
if key, ok := m.blsPublicKeys[addr]; ok {
return key, nil
}
return nil, errors.New("public key not found")
}

type MockContract struct {
}

func (contract *MockContract) GetValidators(*big.Int) ([]common.Address, error) {
return Validators.GetValidators(), nil
}

func (contract *MockContract) WrapUpEpoch(*ApplyTransactOpts) error {
log.Info("WrapUpEpoch")
return nil
}

func (contract *MockContract) SubmitBlockReward(*ApplyTransactOpts) error {
log.Info("SubmitBlockReward")
return nil
}

func (contract *MockContract) Slash(*ApplyTransactOpts, common.Address) error {
return nil
}

func (contract *MockContract) FinalityReward(*ApplyTransactOpts, []common.Address) error {
return nil
}

func (contract *MockContract) GetBlsPublicKey(_ *big.Int, addr common.Address) (blsCommon.PublicKey, error) {
return Validators.GetPublicKey(addr)
}
29 changes: 20 additions & 9 deletions consensus/consortium/v2/consortium.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,11 +404,20 @@ func (c *Consortium) snapshot(chain consensus.ChainHeaderReader, number uint64,
break
}

// this case is only happened in mock mode
if number == 0 {
validators, err := c.contract.GetValidators(common.Big0)
if err != nil {
return nil, err
}
snap = newSnapshot(c.chainConfig, c.config, c.signatures, number, hash, validators, nil, c.ethAPI)
break
}

// init snapshot if it is at forkedBlock
if number == c.forkedBlock-1 {
var (
err error
validators []common.Address
err error
)
snap, err = loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI, c.chainConfig)
if err == nil {
Expand All @@ -418,11 +427,12 @@ func (c *Consortium) snapshot(chain consensus.ChainHeaderReader, number uint64,

// get validators set from number
_, _, _, contract := c.readSignerAndContract()
validators, err = contract.GetValidators(big.NewInt(0).SetUint64(number))
validators, err := contract.GetValidators(big.NewInt(0).SetUint64(number))
if err != nil {
log.Error("Load validators at the beginning failed", "err", err)
return nil, err
}

snap = newSnapshot(c.chainConfig, c.config, c.signatures, number, hash, validators, nil, c.ethAPI)

// load v1 recent list to prevent recent producing-block-validators produce block again
Expand Down Expand Up @@ -500,6 +510,7 @@ func (c *Consortium) snapshot(chain consensus.ChainHeaderReader, number uint64,
}
log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash)
}
log.Trace("Checking snapshot data", "number", snap.Number, "validators", snap.validators())
return snap, err
}

Expand Down Expand Up @@ -1098,13 +1109,13 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {

// initContract creates NewContractIntegrator instance
func (c *Consortium) initContract(coinbase common.Address, signTxFn consortiumCommon.SignerTxFn) error {
contract, err := consortiumCommon.NewContractIntegrator(c.chainConfig, consortiumCommon.NewConsortiumBackend(c.ethAPI), signTxFn, coinbase)
if err != nil {
return err
if consortiumCommon.Validators != nil {
c.contract = &consortiumCommon.MockContract{}
return nil
}
c.contract = contract

return nil
var err error
c.contract, err = consortiumCommon.NewContractIntegrator(c.chainConfig, consortiumCommon.NewConsortiumBackend(c.ethAPI), signTxFn, coinbase)
return err
}

func (c *Consortium) readSignerAndContract() (
Expand Down
64 changes: 38 additions & 26 deletions consensus/consortium/v2/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
consortiumCommon "github.com/ethereum/go-ethereum/consensus/consortium/common"
v1 "github.com/ethereum/go-ethereum/consensus/consortium/v1"
"github.com/ethereum/go-ethereum/consensus/consortium/v2/finality"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -64,11 +65,13 @@ func newSnapshot(
Number: number,
Hash: hash,
Recents: make(map[uint64]common.Address),
Validators: make(map[common.Address]struct{}),
}

for _, v := range validators {
snap.Validators[v] = struct{}{}
if validators != nil {
snap.Validators = make(map[common.Address]struct{})
for _, v := range validators {
snap.Validators[v] = struct{}{}
}
}

if valWithBlsPub != nil {
Expand Down Expand Up @@ -227,33 +230,42 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
return nil, consensus.ErrUnknownAncestor
}

isShillin := chain.Config().IsShillin(checkpointHeader.Number)
// Get validator set from headers and use that for new validator set
extraData, err := finality.DecodeExtra(checkpointHeader.Extra, isShillin)
if err != nil {
return nil, err
}
// this case is only happened in mock mode
if checkpointHeader.Number.Cmp(common.Big0) == 0 {
snap.Validators = make(map[common.Address]struct{})
for _, validator := range consortiumCommon.Validators.GetValidators() {
snap.Validators[validator] = struct{}{}
}
snap.ValidatorsWithBlsPub = nil
} else {
isShillin := chain.Config().IsShillin(checkpointHeader.Number)
// Get validator set from headers and use that for new validator set
extraData, err := finality.DecodeExtra(checkpointHeader.Extra, isShillin)
if err != nil {
return nil, err
}

oldLimit := len(snap.validators())/2 + 1
newLimit := len(extraData.CheckpointValidators)/2 + 1
if newLimit < oldLimit {
for i := 0; i < oldLimit-newLimit; i++ {
delete(snap.Recents, number-uint64(newLimit)-uint64(i))
oldLimit := len(snap.validators())/2 + 1
newLimit := len(extraData.CheckpointValidators)/2 + 1
if newLimit < oldLimit {
for i := 0; i < oldLimit-newLimit; i++ {
delete(snap.Recents, number-uint64(newLimit)-uint64(i))
}
}
}

if isShillin {
// The validator information in checkpoint header is already sorted,
// we don't need to sort here
snap.ValidatorsWithBlsPub = make([]finality.ValidatorWithBlsPub, len(extraData.CheckpointValidators))
copy(snap.ValidatorsWithBlsPub, extraData.CheckpointValidators)
snap.Validators = nil
} else {
snap.Validators = make(map[common.Address]struct{})
for _, validator := range extraData.CheckpointValidators {
snap.Validators[validator.Address] = struct{}{}
if isShillin {
// The validator information in checkpoint header is already sorted,
// we don't need to sort here
snap.ValidatorsWithBlsPub = make([]finality.ValidatorWithBlsPub, len(extraData.CheckpointValidators))
copy(snap.ValidatorsWithBlsPub, extraData.CheckpointValidators)
snap.Validators = nil
} else {
snap.Validators = make(map[common.Address]struct{})
for _, validator := range extraData.CheckpointValidators {
snap.Validators[validator.Address] = struct{}{}
}
snap.ValidatorsWithBlsPub = nil
}
snap.ValidatorsWithBlsPub = nil
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ var Defaults = Config{
BlockProduceLeftOver: 200 * time.Millisecond,
BlockSizeReserve: 500000,
},
TxPool: core.DefaultTxPoolConfig,
RPCGasCap: 50000000,
RPCEVMTimeout: 5 * time.Second,
GPO: FullNodeGPO,
RPCTxFeeCap: 1, // 1 ether
TxPool: core.DefaultTxPoolConfig,
RPCGasCap: 50000000,
RPCEVMTimeout: 5 * time.Second,
GPO: FullNodeGPO,
RPCTxFeeCap: 1, // 1 ether
}

func init() {
Expand Down

0 comments on commit 62c9be3

Please sign in to comment.