diff --git a/.gitignore b/.gitignore index ae1daec466..56d22509a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ peers.json genesis.json +manifest.json secretsManagerConfig.json *-packr.go config*.json diff --git a/command/genesis/genesis.go b/command/genesis/genesis.go index 28d7ded4e4..6816466303 100644 --- a/command/genesis/genesis.go +++ b/command/genesis/genesis.go @@ -150,56 +150,49 @@ func setFlags(cmd *cobra.Command) { // PolyBFT { + cmd.Flags().StringVar( + ¶ms.manifestPath, + manifestPathFlag, + defaultManifestPath, + "the manifest file path, which contains genesis metadata", + ) + cmd.Flags().IntVar( ¶ms.validatorSetSize, validatorSetSizeFlag, defaultValidatorSetSize, "the total number of validators", ) - cmd.Flags().StringVar( - ¶ms.polyBftValidatorPrefixPath, - polyBftValidatorPrefixPathFlag, - defaultPolyBftValidatorPrefixPath, - "prefix path for polybft validator folder directory", - ) + cmd.Flags().Uint64Var( ¶ms.sprintSize, sprintSizeFlag, defaultSprintSize, "the number of block included into a sprint", ) + cmd.Flags().DurationVar( ¶ms.blockTime, blockTimeFlag, defaultBlockTime, "the predefined period which determines block creation frequency", ) - cmd.Flags().StringArrayVar( - ¶ms.validators, - validatorsFlag, - []string{}, - "validators defined by user throughout a parameter (format:
:)", - ) - cmd.Flags().StringVar( - ¶ms.premineValidators, - premineValidatorsFlag, - command.DefaultPremineBalance, - "the amount which will be premined to all the validators", - ) + cmd.Flags().StringVar( ¶ms.smartContractsRootPath, smartContractsRootPathFlag, contracts.ContractsRootFolder, "the smart contracts folder", ) + cmd.Flags().StringVar( ¶ms.bridgeJSONRPCAddr, bridgeFlag, "", "the rootchain JSON RPC IP address. If present, node is running in bridge mode.", ) + cmd.Flags().Lookup(bridgeFlag).NoOptDefVal = "http://127.0.0.1:8545" - cmd.MarkFlagsMutuallyExclusive(validatorsFlag, premineValidatorsFlag) } } @@ -234,7 +227,7 @@ func runCommand(cmd *cobra.Command, _ []string) { var err error if params.isPolyBFTConsensus() { - err = params.generatePolyBftGenesis() + err = params.generatePolyBftChainConfig() } else { err = params.generateGenesis() } diff --git a/command/genesis/params.go b/command/genesis/params.go index f0c08aebfc..281683491e 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -75,15 +75,12 @@ type genesisParams struct { genesisConfig *chain.Chain // PolyBFT - validatorSetSize int - sprintSize uint64 - blockTime time.Duration - validators []string - - polyBftValidatorPrefixPath string - premineValidators string - smartContractsRootPath string - bridgeJSONRPCAddr string + manifestPath string + smartContractsRootPath string + validatorSetSize int + sprintSize uint64 + blockTime time.Duration + bridgeJSONRPCAddr string } func (p *genesisParams) validateFlags() error { @@ -336,19 +333,17 @@ func (p *genesisParams) initGenesisConfig() error { chainConfig.Genesis.Alloc[staking.AddrStakingContract] = stakingAccount } - premineInfos := make([]*premineInfo, len(p.premine)) - - for i, premineRaw := range p.premine { + for _, premineRaw := range p.premine { premineInfo, err := parsePremineInfo(premineRaw) if err != nil { return err } - premineInfos[i] = premineInfo + chainConfig.Genesis.Alloc[premineInfo.address] = &chain.GenesisAccount{ + Balance: premineInfo.balance, + } } - fillPremineMap(chainConfig.Genesis.Alloc, premineInfos) - p.genesisConfig = chainConfig return nil diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 266b8fbfd2..f9a2033253 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -5,9 +5,7 @@ import ( "errors" "fmt" "math/big" - "path" "sort" - "strings" "time" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" @@ -16,7 +14,6 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" - rootchain "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/contracts" @@ -25,22 +22,19 @@ import ( ) const ( - premineValidatorsFlag = "premine-validators" - polyBftValidatorPrefixPathFlag = "validator-prefix" - smartContractsRootPathFlag = "contracts-path" - - validatorSetSizeFlag = "validator-set-size" - sprintSizeFlag = "sprint-size" - blockTimeFlag = "block-time" - validatorsFlag = "polybft-validators" - bridgeFlag = "bridge-json-rpc" - - defaultEpochSize = uint64(10) - defaultSprintSize = uint64(5) - defaultValidatorSetSize = 100 - defaultBlockTime = 2 * time.Second - defaultPolyBftValidatorPrefixPath = "test-chain-" - defaultBridge = false + smartContractsRootPathFlag = "contracts-path" + manifestPathFlag = "manifest" + validatorSetSizeFlag = "validator-set-size" + sprintSizeFlag = "sprint-size" + blockTimeFlag = "block-time" + bridgeFlag = "bridge-json-rpc" + + defaultManifestPath = "./manifest.json" + defaultEpochSize = uint64(10) + defaultSprintSize = uint64(5) + defaultValidatorSetSize = 100 + defaultBlockTime = 2 * time.Second + defaultBridge = false bootnodePortStart = 30301 ) @@ -49,115 +43,116 @@ var ( errNoGenesisValidators = errors.New("genesis validators aren't provided") ) -func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { - // set initial validator set - genesisValidators, err := p.getGenesisValidators() +// generatePolyBftChainConfig creates and persists polybft chain configuration to the provided file path +func (p *genesisParams) generatePolyBftChainConfig() error { + // load manifest file + manifest, err := polybft.LoadManifest(p.manifestPath) if err != nil { - return nil, err + return fmt.Errorf("failed to load manifest file from provided path '%s': %w", p.manifestPath, err) } - if len(genesisValidators) == 0 { - return nil, errNoGenesisValidators + if len(manifest.GenesisValidators) == 0 { + return errNoGenesisValidators + } + + var bridge *polybft.BridgeConfig + + // populate bridge configuration + if p.bridgeJSONRPCAddr != "" && manifest.RootchainConfig != nil { + bridge = manifest.RootchainConfig.ToBridgeConfig() + bridge.JSONRPCEndpoint = p.bridgeJSONRPCAddr + } + + polyBftConfig := &polybft.PolyBFTConfig{ + InitialValidatorSet: manifest.GenesisValidators, + BlockTime: p.blockTime, + EpochSize: p.epochSize, + SprintSize: p.sprintSize, + // use 1st account as governance address + Governance: manifest.GenesisValidators[0].Address, + Bridge: bridge, + ValidatorSetAddr: contracts.ValidatorSetContract, + StateReceiverAddr: contracts.StateReceiverContract, + } + + chainConfig := &chain.Chain{ + Name: p.name, + Params: &chain.Params{ + ChainID: int(p.chainID), + Forks: chain.AllForksEnabled, + Engine: map[string]interface{}{ + string(server.PolyBFTConsensus): polyBftConfig, + }, + }, + Bootnodes: p.bootnodes, } // deploy genesis contracts allocs, err := p.deployContracts() if err != nil { - return nil, err + return err } - // premine accounts with some tokens - var ( - validatorPreminesMap map[types.Address]int - premineInfos []*premineInfo - ) - - if p.premineValidators != "" { - validatorPreminesMap = make(map[types.Address]int, len(genesisValidators)) + premineInfos := make([]*premineInfo, len(manifest.GenesisValidators)) + validatorPreminesMap := make(map[types.Address]int, len(manifest.GenesisValidators)) - for i, vi := range genesisValidators { - premineInfo, err := parsePremineInfo(fmt.Sprintf("%s:%s", vi.Address, p.premineValidators)) - if err != nil { - return nil, err - } - - premineInfos = append(premineInfos, premineInfo) - validatorPreminesMap[premineInfo.address] = i - } + // populate premine info for validator accounts + for i, validator := range manifest.GenesisValidators { + premineInfo := &premineInfo{address: validator.Address, balance: validator.Balance} + premineInfos[i] = premineInfo + validatorPreminesMap[premineInfo.address] = i } + // either premine non-validator or override validator accounts balance for _, premine := range p.premine { premineInfo, err := parsePremineInfo(premine) if err != nil { - return nil, err + return err } if i, ok := validatorPreminesMap[premineInfo.address]; ok { premineInfos[i] = premineInfo } else { - premineInfos = append(premineInfos, premineInfo) + premineInfos = append(premineInfos, premineInfo) //nolint:makezero } } // premine accounts - fillPremineMap(allocs, premineInfos) + for _, premine := range premineInfos { + allocs[premine.address] = &chain.GenesisAccount{ + Balance: premine.balance, + } + } + + validatorMetadata := make([]*polybft.ValidatorMetadata, len(manifest.GenesisValidators)) - // populate genesis validators balances - for _, validator := range genesisValidators { + for i, validator := range manifest.GenesisValidators { + // update balance of genesis validator, because it could be changed via premine flag balance, err := chain.GetGenesisAccountBalance(validator.Address, allocs) if err != nil { - return nil, err + return err } validator.Balance = balance - } - polyBftConfig := &polybft.PolyBFTConfig{ - BlockTime: p.blockTime, - EpochSize: p.epochSize, - SprintSize: p.sprintSize, - ValidatorSetSize: p.validatorSetSize, - ValidatorSetAddr: contracts.ValidatorSetContract, - StateReceiverAddr: contracts.StateReceiverContract, - // use 1st account as governance address - Governance: genesisValidators[0].Address, - } - - // populate bridge configuration - if p.bridgeJSONRPCAddr != "" { - polyBftConfig.Bridge = &polybft.BridgeConfig{ - // TODO: Figure out population of rootchain contracts and whether those should be part of genesis configuration - BridgeAddr: rootchain.StateSenderAddress, - CheckpointAddr: rootchain.CheckpointManagerAddress, - JSONRPCEndpoint: p.bridgeJSONRPCAddr, + // create validator metadata instance + metadata, err := validator.ToValidatorMetadata() + if err != nil { + return err } - } - chainConfig := &chain.Chain{ - Name: p.name, - Params: &chain.Params{ - ChainID: int(p.chainID), - Forks: chain.AllForksEnabled, - Engine: map[string]interface{}{ - string(server.PolyBFTConsensus): polyBftConfig, - }, - }, - Bootnodes: p.bootnodes, - } + validatorMetadata[i] = metadata - // set generic validators as bootnodes if needed - if len(p.bootnodes) == 0 { - for i, validator := range genesisValidators { - bootNode := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", "127.0.0.1", bootnodePortStart+i, validator.NodeID) - chainConfig.Bootnodes = append(chainConfig.Bootnodes, bootNode) + // set genesis validators as boot nodes if boot nodes not provided via CLI + if len(p.bootnodes) == 0 { + bootNodeMultiAddr := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", "127.0.0.1", bootnodePortStart+i, validator.NodeID) + chainConfig.Bootnodes = append(chainConfig.Bootnodes, bootNodeMultiAddr) } } - polyBftConfig.InitialValidatorSet = genesisValidators - - genesisExtraData, err := generateExtraDataPolyBft(genesisValidators) + genesisExtraData, err := generateExtraDataPolyBft(validatorMetadata) if err != nil { - return nil, err + return err } // populate genesis parameters @@ -170,52 +165,7 @@ func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { Mixhash: polybft.PolyBFTMixDigest, } - return chainConfig, nil -} - -func (p *genesisParams) getGenesisValidators() ([]*polybft.Validator, error) { - if len(p.validators) > 0 { - validators := make([]*polybft.Validator, len(p.validators)) - for i, validator := range p.validators { - parts := strings.Split(validator, ":") - - if len(parts) != 3 { - return nil, fmt.Errorf("expected 3 parts provided in the following format , but got %d", - len(parts)) - } - - if len(parts[0]) != 53 { - return nil, fmt.Errorf("invalid node id: %s", parts[0]) - } - - if len(parts[1]) != 42 { - return nil, fmt.Errorf("invalid address: %s", parts[1]) - } - - if len(parts[2]) < 2 { - return nil, fmt.Errorf("invalid bls key: %s", parts[2]) - } - - validators[i] = &polybft.Validator{ - NodeID: parts[0], - Address: types.StringToAddress(parts[1]), - BlsKey: parts[2], - } - } - - return validators, nil - } - - return ReadValidatorsByRegexp(path.Dir(p.genesisPath), p.polyBftValidatorPrefixPath) -} - -func (p *genesisParams) generatePolyBftGenesis() error { - config, err := params.generatePolyBFTConfig() - if err != nil { - return err - } - - return helper.WriteGenesisConfigToDisk(config, params.genesisPath) + return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath) } func (p *genesisParams) deployContracts() (map[types.Address]*chain.GenesisAccount, error) { @@ -280,25 +230,12 @@ func (p *genesisParams) deployContracts() (map[types.Address]*chain.GenesisAccou } // generateExtraDataPolyBft populates Extra with specific fields required for polybft consensus protocol -func generateExtraDataPolyBft(validators []*polybft.Validator) ([]byte, error) { +func generateExtraDataPolyBft(validators []*polybft.ValidatorMetadata) ([]byte, error) { delta := &polybft.ValidatorSetDelta{ - Added: make(polybft.AccountSet, len(validators)), + Added: validators, Removed: bitmap.Bitmap{}, } - for i, validator := range validators { - blsKey, err := validator.UnmarshalBLSPublicKey() - if err != nil { - return nil, err - } - - delta.Added[i] = &polybft.ValidatorMetadata{ - Address: validator.Address, - BlsKey: blsKey, - VotingPower: chain.ConvertWeiToTokensAmount(validator.Balance).Uint64(), - } - } - // Order validators based on its addresses sort.Slice(delta.Added, func(i, j int) bool { return bytes.Compare(delta.Added[i].Address[:], delta.Added[j].Address[:]) < 0 diff --git a/command/genesis/utils.go b/command/genesis/utils.go index be63f2726d..81d7af8bda 100644 --- a/command/genesis/utils.go +++ b/command/genesis/utils.go @@ -11,7 +11,6 @@ import ( "strconv" "strings" - "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" @@ -68,15 +67,6 @@ func verifyGenesisExistence(genesisPath string) *GenesisGenError { return nil } -// fillPremineMap fills the premine map for the genesis.json file with passed in balances and accounts -func fillPremineMap(premineMap map[types.Address]*chain.GenesisAccount, premineInfos []*premineInfo) { - for _, premine := range premineInfos { - premineMap[premine.address] = &chain.GenesisAccount{ - Balance: premine.balance, - } - } -} - // parsePremineInfo parses provided premine information and returns premine address and premine balance func parsePremineInfo(premineInfoRaw string) (*premineInfo, error) { address := types.ZeroAddress diff --git a/command/polybftmanifest/manifest_init.go b/command/polybftmanifest/manifest_init.go new file mode 100644 index 0000000000..5bf0b3e0c5 --- /dev/null +++ b/command/polybftmanifest/manifest_init.go @@ -0,0 +1,210 @@ +package polybftmanifest + +import ( + "bytes" + "errors" + "fmt" + "os" + "path" + "strings" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/genesis" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" +) + +const ( + manifestPathFlag = "path" + premineValidatorsFlag = "premine-validators" + validatorsFlag = "validators" + validatorsPathFlag = "validators-path" + validatorsPrefixFlag = "validators-prefix" + + defaultValidatorPrefixPath = "test-chain-" + defaultManifestPath = "./manifest.json" + + nodeIDLength = 53 + ecdsaAddressLength = 42 + blsKeyLength = 2 +) + +var ( + params = &manifestInitParams{} +) + +func GetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "manifest", + Short: "Initializes manifest file. It is applicable only to polybft consensus protocol.", + PreRunE: runPreRun, + Run: runCommand, + } + + setFlags(cmd) + + return cmd +} + +func runPreRun(_ *cobra.Command, _ []string) error { + return params.validateFlags() +} + +func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.manifestPath, + manifestPathFlag, + defaultManifestPath, + "the file path where manifest file is going to be stored", + ) + + cmd.Flags().StringVar( + ¶ms.validatorsPath, + validatorsPathFlag, + "./", + "root path containing polybft validator keys", + ) + + cmd.Flags().StringVar( + ¶ms.validatorsPrefixPath, + validatorsPrefixFlag, + defaultValidatorPrefixPath, + "folder prefix names for polybft validator keys", + ) + + cmd.Flags().StringArrayVar( + ¶ms.validators, + validatorsFlag, + []string{}, + "validators defined by user (format: ::)", + ) + + cmd.Flags().StringVar( + ¶ms.premineValidators, + premineValidatorsFlag, + command.DefaultPremineBalance, + "the amount which will be pre-mined to all the validators", + ) + + cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPathFlag) + cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPrefixFlag) +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + validators, err := params.getValidatorAccounts() + if err != nil { + outputter.SetError(fmt.Errorf("failed to get validator accounts: %w", err)) + + return + } + + manifest := &polybft.Manifest{GenesisValidators: validators} + if err = manifest.Save(params.manifestPath); err != nil { + outputter.SetError(fmt.Errorf("failed to save manifest file '%s': %w", params.manifestPath, err)) + + return + } + + outputter.SetCommandResult(params.getResult()) +} + +type manifestInitParams struct { + manifestPath string + validatorsPath string + validatorsPrefixPath string + premineValidators string + validators []string +} + +func (p *manifestInitParams) validateFlags() error { + if _, err := os.Stat(p.validatorsPath); errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("provided validators path '%s' doesn't exist", p.validatorsPath) + } + + if _, err := types.ParseUint256orHex(&p.premineValidators); err != nil { + return fmt.Errorf("invalid premine validators balance provided '%s': %w", p.premineValidators, err) + } + + return nil +} + +// getValidatorAccounts gathers validator accounts info either from CLI or from provided local storage +func (p *manifestInitParams) getValidatorAccounts() ([]*polybft.Validator, error) { + balance, err := types.ParseUint256orHex(¶ms.premineValidators) + if err != nil { + return nil, fmt.Errorf("provided invalid premine validators balance: %s", params.premineValidators) + } + + if len(p.validators) > 0 { + validators := make([]*polybft.Validator, len(p.validators)) + for i, validator := range p.validators { + parts := strings.Split(validator, ":") + + if len(parts) != 3 { + return nil, fmt.Errorf("expected 3 parts provided in the following format "+ + ", but got %d part(s)", + len(parts)) + } + + if len(parts[0]) != nodeIDLength { + return nil, fmt.Errorf("invalid node id: %s", parts[0]) + } + + if len(parts[1]) != ecdsaAddressLength { + return nil, fmt.Errorf("invalid address: %s", parts[1]) + } + + if len(parts[2]) < blsKeyLength { + return nil, fmt.Errorf("invalid bls key: %s", parts[2]) + } + + validators[i] = &polybft.Validator{ + NodeID: parts[0], + Address: types.StringToAddress(parts[1]), + BlsKey: parts[2], + Balance: balance, + } + } + + return validators, nil + } + + validatorsPath := p.validatorsPath + if validatorsPath == "" { + validatorsPath = path.Dir(p.manifestPath) + } + + validators, err := genesis.ReadValidatorsByRegexp(validatorsPath, p.validatorsPrefixPath) + if err != nil { + return nil, err + } + + for _, v := range validators { + v.Balance = balance + } + + return validators, nil +} + +func (p *manifestInitParams) getResult() command.CommandResult { + return &result{ + message: fmt.Sprintf("Manifest file written to %s\n", p.manifestPath), + } +} + +type result struct { + message string +} + +func (r *result) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[MANIFEST INITIALIZATION SUCCESS]\n") + buffer.WriteString(r.message) + + return buffer.String() +} diff --git a/command/root/root.go b/command/root/root.go index aa946f0eb5..fb3d6e7a6d 100644 --- a/command/root/root.go +++ b/command/root/root.go @@ -15,6 +15,7 @@ import ( "github.com/0xPolygon/polygon-edge/command/monitor" "github.com/0xPolygon/polygon-edge/command/peers" "github.com/0xPolygon/polygon-edge/command/polybft" + "github.com/0xPolygon/polygon-edge/command/polybftmanifest" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" "github.com/0xPolygon/polygon-edge/command/rootchain" "github.com/0xPolygon/polygon-edge/command/secrets" @@ -61,6 +62,7 @@ func (rc *RootCommand) registerSubCommands() { license.GetCommand(), polybftsecrets.GetCommand(), polybft.GetCommand(), + polybftmanifest.GetCommand(), ) } diff --git a/command/rootchain/emit/emit.go b/command/rootchain/emit/emit.go index 5c7ca19468..62560f8f49 100644 --- a/command/rootchain/emit/emit.go +++ b/command/rootchain/emit/emit.go @@ -10,6 +10,7 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -18,8 +19,6 @@ import ( var ( params emitParams - jsonRPCAddress string - contractsToParamTypes = map[string]string{ contracts.NativeTokenContract.String(): "tuple(address,uint256)", } @@ -42,6 +41,13 @@ func GetCommand() *cobra.Command { } func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.manifestPath, + manifestPathFlag, + "./manifest.json", + "the manifest file path, which contains genesis metadata", + ) + cmd.Flags().StringVar( ¶ms.address, contractFlag, @@ -64,11 +70,18 @@ func setFlags(cmd *cobra.Command) { ) cmd.Flags().StringVar( - &jsonRPCAddress, + ¶ms.jsonRPCAddress, jsonRPCFlag, "http://127.0.0.1:8545", "the JSON RPC rootchain IP address (e.g. http://127.0.0.1:8545)", ) + + cmd.Flags().StringVar( + ¶ms.adminKey, + adminKeyFlag, + helper.DefaultPrivateKeyRaw, + "Hex encoded private key of the account which sends rootchain transactions", + ) } func runPreRun(_ *cobra.Command, _ []string) error { @@ -79,6 +92,20 @@ func runCommand(cmd *cobra.Command, _ []string) { outputter := command.InitializeOutputter(cmd) defer outputter.WriteOutput() + err := helper.InitRootchainAdminKey(params.adminKey) + if err != nil { + outputter.SetError(err) + + return + } + + manifest, err := polybft.LoadManifest(params.manifestPath) + if err != nil { + outputter.SetError(fmt.Errorf("failed to load manifest file from '%s': %w", params.manifestPath, err)) + + return + } + paramsType, exists := contractsToParamTypes[params.address] if !exists { outputter.SetError(fmt.Errorf("no parameter types for given contract address: %v", params.address)) @@ -86,7 +113,7 @@ func runCommand(cmd *cobra.Command, _ []string) { return } - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(jsonRPCAddress)) + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPCAddress)) if err != nil { outputter.SetError(fmt.Errorf("could not create rootchain interactor: %w", err)) @@ -104,7 +131,7 @@ func runCommand(cmd *cobra.Command, _ []string) { case <-ctx.Done(): return ctx.Err() default: - txn, err := createEmitTxn(paramsType, wallet, amount) + txn, err := createEmitTxn(manifest.RootchainConfig.StateSenderAddress, paramsType, wallet, amount) if err != nil { return fmt.Errorf("failed to create tx input: %w", err) } @@ -133,7 +160,10 @@ func runCommand(cmd *cobra.Command, _ []string) { }) } -func createEmitTxn(paramsType string, parameters ...interface{}) (*ethgo.Transaction, error) { +func createEmitTxn( + stateSenderAddr types.Address, + paramsType string, + parameters ...interface{}) (*ethgo.Transaction, error) { var prms []interface{} prms = append(prms, parameters...) @@ -150,7 +180,7 @@ func createEmitTxn(paramsType string, parameters ...interface{}) (*ethgo.Transac } return ðgo.Transaction{ - To: (*ethgo.Address)(&helper.StateSenderAddress), + To: (*ethgo.Address)(&stateSenderAddr), Input: input, }, nil } diff --git a/command/rootchain/emit/params.go b/command/rootchain/emit/params.go index 7590005a2d..afc8b7f6fe 100644 --- a/command/rootchain/emit/params.go +++ b/command/rootchain/emit/params.go @@ -1,12 +1,18 @@ package emit -import "errors" +import ( + "errors" + "fmt" + "os" +) const ( - contractFlag = "contract" - walletsFlag = "wallets" - amountsFlag = "amounts" - jsonRPCFlag = "json-rpc" + manifestPathFlag = "manifest" + contractFlag = "contract" + walletsFlag = "wallets" + amountsFlag = "amounts" + jsonRPCFlag = "json-rpc" + adminKeyFlag = "admin-key" ) var ( @@ -16,12 +22,19 @@ var ( ) type emitParams struct { - address string - wallets []string - amounts []string + manifestPath string + address string + wallets []string + amounts []string + jsonRPCAddress string + adminKey string } func (ep *emitParams) validateFlags() error { + if _, err := os.Stat(ep.manifestPath); errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("provided manifest path '%s' doesn't exist", ep.manifestPath) + } + if len(ep.wallets) == 0 { return errWalletsMissing } diff --git a/command/rootchain/helper/metadata.go b/command/rootchain/helper/metadata.go index 11585c253c..85154ed38a 100644 --- a/command/rootchain/helper/metadata.go +++ b/command/rootchain/helper/metadata.go @@ -2,32 +2,52 @@ package helper import ( "context" + "encoding/hex" "errors" "fmt" - "github.com/umbracle/ethgo" - - "github.com/0xPolygon/polygon-edge/types" dockertypes "github.com/docker/docker/api/types" "github.com/docker/docker/client" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/wallet" ) -var ( - // StateSenderAddress is an address of StateSender.sol smart contract - StateSenderAddress = types.StringToAddress("0x6FE03c2768C9d800AF3Dedf1878b5687FE120a27") - // CheckpointManagerAddress is an address of CheckpointManager.sol smart contract - CheckpointManagerAddress = types.StringToAddress("0x3d46A809D5767B81a8836f0E79145ba615A2Dd61") - // BLSAddress is an address of BLS.sol smart contract - BLSAddress = types.StringToAddress("0x72E1C51FE6dABF2e3d5701170cf5aD3620E6B8ba") - // BN256G2Address is an address of BN256G2Address.sol smart contract - BN256G2Address = types.StringToAddress("0x436604426F31A05f905C64edc973E575BdB46471") - // ExitHelperAddress is an address of ExitHelper.sol smart contract - ExitHelperAddress = ethgo.Address(types.StringToAddress("0x947a581B2713F58A8145201DA41BCb6aAE90196B")) +const DefaultPrivateKeyRaw = "aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d" +var ( ErrRootchainNotFound = errors.New("rootchain not found") ErrRootchainPortBind = errors.New("port 8545 is not bind with localhost") + + // rootchainAdminKey is a private key of account which is rootchain administrator + // namely it represents account which deploys rootchain smart contracts + rootchainAdminKey *wallet.Key ) +// InitRootchainAdminKey initializes a private key instance from provided hex encoded private key +func InitRootchainAdminKey(rawKey string) error { + privateKeyRaw := DefaultPrivateKeyRaw + if rawKey != "" { + privateKeyRaw = rawKey + } + + dec, err := hex.DecodeString(privateKeyRaw) + if err != nil { + return fmt.Errorf("failed to decode private key string '%s': %w", privateKeyRaw, err) + } + + rootchainAdminKey, err = wallet.NewWalletFromPrivKey(dec) + if err != nil { + return fmt.Errorf("failed to initialize key from provided private key '%s': %w", privateKeyRaw, err) + } + + return nil +} + +// GetRootchainAdminKey returns rootchain admin private key +func GetRootchainAdminKey() ethgo.Key { + return rootchainAdminKey +} + func GetRootchainID() (string, error) { cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { diff --git a/command/rootchain/helper/txn.go b/command/rootchain/helper/txn.go deleted file mode 100644 index c82cb0c622..0000000000 --- a/command/rootchain/helper/txn.go +++ /dev/null @@ -1,42 +0,0 @@ -package helper - -import ( - "encoding/hex" - - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/wallet" - - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - defaultGasPrice = 1879048192 // 0x70000000 - defaultGasLimit = 5242880 // 0x500000 -) - -var ( - // TODO: @Stefan-Ethernal Use either private key provided through CLI input or this (denoting dev vs prod mode) - // use a deterministic wallet/private key so that the address of the deployed contracts - // are deterministic - rootchainAdminKey *wallet.Key -) - -func init() { - dec, err := hex.DecodeString("aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d") - if err != nil { - panic(err) - } - - rootchainAdminKey, err = wallet.NewWalletFromPrivKey(dec) - if err != nil { - panic(err) - } -} - -func GetRootchainAdminAddr() types.Address { - return types.Address(rootchainAdminKey.Address()) -} - -func GetRootchainAdminKey() ethgo.Key { - return rootchainAdminKey -} diff --git a/command/rootchain/initcontracts/init_contracts.go b/command/rootchain/initcontracts/init_contracts.go index af155a2b0f..5b843c7c5e 100644 --- a/command/rootchain/initcontracts/init_contracts.go +++ b/command/rootchain/initcontracts/init_contracts.go @@ -7,7 +7,6 @@ import ( "fmt" "io/ioutil" "math/big" - "os" "path/filepath" "sort" "strings" @@ -21,7 +20,6 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/genesis" "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" @@ -32,6 +30,16 @@ import ( "github.com/0xPolygon/polygon-edge/types" ) +const ( + contractsDeploymentTitle = "[ROOTCHAIN - CONTRACTS DEPLOYMENT]" + + stateSenderName = "StateSender" + checkpointManagerName = "CheckpointManager" + blsName = "BLS" + bn256G2Name = "BN256G2" + exitHelperName = "ExitHelper" +) + var ( params initContractsParams @@ -42,12 +50,28 @@ var ( "address newBn256G2," + // domain used for BLS signing "bytes32 newDomain," + - // RootValidatorSet contract address + // rootchain validator set "tuple(address _address, uint256[4] blsKey, uint256 votingPower)[] newValidatorSet)") -) -const ( - contractsDeploymentTitle = "[ROOTCHAIN - CONTRACTS DEPLOYMENT]" + // metadataPopulatorMap maps rootchain contract names to callback + // which populates appropriate field in the RootchainMetadata + metadataPopulatorMap = map[string]func(*polybft.RootchainConfig, types.Address){ + stateSenderName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.StateSenderAddress = addr + }, + checkpointManagerName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.CheckpointManagerAddress = addr + }, + blsName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.BLSAddress = addr + }, + bn256G2Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.BN256G2Address = addr + }, + exitHelperName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ExitHelperAddress = addr + }, + } ) // GetCommand returns the rootchain emit command @@ -69,26 +93,23 @@ func setFlags(cmd *cobra.Command) { ¶ms.contractsPath, contractsPathFlag, contracts.ContractsRootFolder, - "Root path for the smart contracts", - ) - cmd.Flags().StringVar( - ¶ms.validatorPath, - validatorPathFlag, - defaultValidatorPath, - "Validators path", + "Root directory path containing POS smart contracts", ) + cmd.Flags().StringVar( - ¶ms.validatorPrefixPath, - validatorPrefixPathFlag, - defaultValidatorPrefixPath, - "Validators prefix path", + ¶ms.manifestPath, + manifestPathFlag, + defaultManifestPath, + "Manifest file path, which contains metadata", ) + cmd.Flags().StringVar( - ¶ms.genesisPath, - genesisPathFlag, - defaultGenesisPath, - "Genesis configuration path", + ¶ms.adminKey, + adminKeyFlag, + helper.DefaultPrivateKeyRaw, + "Hex encoded private key of the account which deploys rootchain contracts", ) + cmd.Flags().StringVar( ¶ms.jsonRPCAddress, jsonRPCFlag, @@ -97,7 +118,7 @@ func setFlags(cmd *cobra.Command) { ) } -func runPreRun(_ *cobra.Command, _ []string) error { +func runPreRun(cmd *cobra.Command, _ []string) error { return params.validateFlags() } @@ -117,20 +138,35 @@ func runCommand(cmd *cobra.Command, _ []string) { return } - code, err := client.Eth().GetCode(ethgo.Address(helper.StateSenderAddress), ethgo.Latest) + manifest, err := polybft.LoadManifest(params.manifestPath) if err != nil { - outputter.SetError(fmt.Errorf("failed to check if rootchain contracts are deployed: %w", err)) + outputter.SetError(fmt.Errorf("failed to read manifest: %w", err)) return - } else if code != "0x" { - outputter.SetCommandResult(&messageResult{ - Message: fmt.Sprintf("%s contracts are already deployed. Aborting.", contractsDeploymentTitle), - }) + } + + if manifest.RootchainConfig != nil { + code, err := client.Eth().GetCode(ethgo.Address(manifest.RootchainConfig.StateSenderAddress), ethgo.Latest) + if err != nil { + outputter.SetError(fmt.Errorf("failed to check if rootchain contracts are deployed: %w", err)) + + return + } else if code != "0x" { + outputter.SetCommandResult(&messageResult{ + Message: fmt.Sprintf("%s contracts are already deployed. Aborting.", contractsDeploymentTitle), + }) + + return + } + } + + if err := helper.InitRootchainAdminKey(params.adminKey); err != nil { + outputter.SetError(err) return } - if err := deployContracts(outputter); err != nil { + if err := deployContracts(outputter, client, manifest); err != nil { outputter.SetError(fmt.Errorf("failed to deploy rootchain contracts: %w", err)) return @@ -142,98 +178,85 @@ func runCommand(cmd *cobra.Command, _ []string) { }) } -func getGenesisAlloc() (map[types.Address]*chain.GenesisAccount, error) { - genesisFile, err := os.Open(params.genesisPath) - if err != nil { - return nil, fmt.Errorf("failed to open genesis config file: %w", err) - } - - genesisRaw, err := ioutil.ReadAll(genesisFile) - if err != nil { - return nil, fmt.Errorf("failed to read genesis config file: %w", err) - } - - var chain *chain.Chain - if err := json.Unmarshal(genesisRaw, &chain); err != nil { - return nil, fmt.Errorf("failed to unmarshal genesis configuration: %w", err) - } - - return chain.Genesis.Alloc, nil -} - -func deployContracts(outputter command.OutputFormatter) error { +func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client, manifest *polybft.Manifest) error { // if the bridge contract is not created, we have to deploy all the contracts - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPCAddress)) + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(client)) if err != nil { return fmt.Errorf("failed to initialize tx relayer: %w", err) } - // TODO: @Stefan-Ethernal Skip FundAccount part in follow up PR if in "dev" mode - // fund account - rootchainAdminAddr := ethgo.Address(helper.GetRootchainAdminAddr()) - txn := ðgo.Transaction{To: &rootchainAdminAddr, Value: big.NewInt(1000000000000000000)} + rootchainAdminKey := helper.GetRootchainAdminKey() + // if admin key is equal to the test private key, then we assume we are working in dev mode + // and therefore need to fund that account + if params.adminKey == helper.DefaultPrivateKeyRaw { + // fund account + rootchainAdminAddr := rootchainAdminKey.Address() + txn := ðgo.Transaction{To: &rootchainAdminAddr, Value: big.NewInt(1000000000000000000)} + _, err = txRelayer.SendTransactionLocal(txn) - _, err = txRelayer.SendTransactionLocal(txn) - if err != nil { - return err + if err != nil { + return err + } } deployContracts := []struct { name string artifact *artifact.Artifact - expected types.Address }{ { name: "StateSender", artifact: contractsapi.StateSender, - expected: helper.StateSenderAddress, }, { name: "CheckpointManager", artifact: contractsapi.CheckpointManager, - expected: helper.CheckpointManagerAddress, }, { name: "BLS", artifact: contractsapi.BLS, - expected: helper.BLSAddress, }, { name: "BN256G2", artifact: contractsapi.BLS256, - expected: helper.BN256G2Address, }, { name: "ExitHelper", artifact: contractsapi.ExitHelper, - expected: types.Address(helper.ExitHelperAddress), }, } + rootchainConfig := &polybft.RootchainConfig{} + manifest.RootchainConfig = rootchainConfig + rootchainConfig.AdminAddress = types.Address(rootchainAdminKey.Address()) + for _, contract := range deployContracts { txn := ðgo.Transaction{ To: nil, // contract deployment Input: contract.artifact.Bytecode, } - receipt, err := txRelayer.SendTransaction(txn, helper.GetRootchainAdminKey()) + receipt, err := txRelayer.SendTransaction(txn, rootchainAdminKey) if err != nil { return err } - if types.Address(receipt.ContractAddress) != contract.expected { - return fmt.Errorf("wrong deployed address for contract %s: expected %s but found %s", - contract.name, contract.expected, receipt.ContractAddress) + contractAddr := types.Address(receipt.ContractAddress) + + populatorFn, ok := metadataPopulatorMap[contract.name] + if !ok { + return fmt.Errorf("rootchain metadata populator not registered for contract '%s'", contract.name) } - outputter.WriteCommandResult(newDeployContractsResult(contract.name, contract.expected, receipt.TransactionHash)) + populatorFn(manifest.RootchainConfig, contractAddr) + + outputter.WriteCommandResult(newDeployContractsResult(contract.name, contractAddr, receipt.TransactionHash)) } - if err := initializeCheckpointManager(txRelayer); err != nil { - return err + if err := manifest.Save(params.manifestPath); err != nil { + return fmt.Errorf("failed to save manifest data: %w", err) } - if err := initializeExitHelper(txRelayer, ethgo.Address(helper.CheckpointManagerAddress)); err != nil { + if err := initializeCheckpointManager(txRelayer, rootchainAdminKey, manifest); err != nil { return err } @@ -241,26 +264,31 @@ func deployContracts(outputter command.OutputFormatter) error { Message: fmt.Sprintf("%s CheckpointManager contract is initialized", contractsDeploymentTitle), }) - return nil -} - -// initializeCheckpointManager invokes initialize function on CheckpointManager smart contract -func initializeCheckpointManager(txRelayer txrelayer.TxRelayer) error { - allocs, err := getGenesisAlloc() - if err != nil { + if err := initializeExitHelper(txRelayer, rootchainConfig); err != nil { return err } - validatorSetMap, err := validatorSetToABISlice(allocs) + outputter.WriteCommandResult(&messageResult{ + Message: fmt.Sprintf("%s ExitHelper contract is initialized", contractsDeploymentTitle), + }) + + return nil +} +// initializeCheckpointManager invokes initialize function on CheckpointManager smart contract +func initializeCheckpointManager( + txRelayer txrelayer.TxRelayer, + rootchainAdminKey ethgo.Key, + manifest *polybft.Manifest) error { + validatorSetMap, err := validatorSetToABISlice(manifest.GenesisValidators) if err != nil { return fmt.Errorf("failed to convert validators to map: %w", err) } initCheckpointInput, err := initCheckpointManager.Encode( []interface{}{ - helper.BLSAddress, - helper.BN256G2Address, + manifest.RootchainConfig.BLSAddress, + manifest.RootchainConfig.BN256G2Address, bls.GetDomain(), validatorSetMap, }) @@ -269,13 +297,13 @@ func initializeCheckpointManager(txRelayer txrelayer.TxRelayer) error { return fmt.Errorf("failed to encode parameters for CheckpointManager.initialize. error: %w", err) } - checkpointManagerAddress := ethgo.Address(helper.CheckpointManagerAddress) + checkpointManagerAddress := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) txn := ðgo.Transaction{ To: &checkpointManagerAddress, Input: initCheckpointInput, } - receipt, err := txRelayer.SendTransaction(txn, helper.GetRootchainAdminKey()) + receipt, err := txRelayer.SendTransaction(txn, rootchainAdminKey) if err != nil { return fmt.Errorf("failed to send transaction to CheckpointManager. error: %w", err) } @@ -287,15 +315,16 @@ func initializeCheckpointManager(txRelayer txrelayer.TxRelayer) error { return nil } -func initializeExitHelper(txRelayer txrelayer.TxRelayer, checkpointManagerAddress ethgo.Address) error { +func initializeExitHelper(txRelayer txrelayer.TxRelayer, rootchainConfig *polybft.RootchainConfig) error { input, err := contractsapi.ExitHelper.Abi.GetMethod("initialize"). - Encode([]interface{}{checkpointManagerAddress}) + Encode([]interface{}{rootchainConfig.CheckpointManagerAddress}) if err != nil { return fmt.Errorf("failed to encode parameters for ExitHelper.initialize. error: %w", err) } + exitHelperAddr := ethgo.Address(rootchainConfig.ExitHelperAddress) txn := ðgo.Transaction{ - To: &helper.ExitHelperAddress, + To: &exitHelperAddr, Input: input, } @@ -312,30 +341,26 @@ func initializeExitHelper(txRelayer txrelayer.TxRelayer, checkpointManagerAddres } // initializeCheckpointManager invokes initialize function on CheckpointManager smart contract -func validatorSetToABISlice(allocs map[types.Address]*chain.GenesisAccount) ([]map[string]interface{}, error) { - validatorsInfo, err := genesis.ReadValidatorsByRegexp(params.validatorPath, params.validatorPrefixPath) - if err != nil { - return nil, err - } - - sort.Slice(validatorsInfo, func(i, j int) bool { - return bytes.Compare(validatorsInfo[i].Address.Bytes(), - validatorsInfo[j].Address.Bytes()) < 0 +func validatorSetToABISlice(validators []*polybft.Validator) ([]map[string]interface{}, error) { + genesisValidators := make([]*polybft.Validator, len(validators)) + copy(genesisValidators, validators) + sort.Slice(genesisValidators, func(i, j int) bool { + return bytes.Compare(genesisValidators[i].Address.Bytes(), genesisValidators[j].Address.Bytes()) < 0 }) - accSet := polybft.AccountSet{} + accSet := make(polybft.AccountSet, len(genesisValidators)) - for _, validatorInfo := range validatorsInfo { + for i, validatorInfo := range genesisValidators { blsKey, err := validatorInfo.UnmarshalBLSPublicKey() if err != nil { return nil, err } - accSet = append(accSet, &polybft.ValidatorMetadata{ + accSet[i] = &polybft.ValidatorMetadata{ Address: validatorInfo.Address, BlsKey: blsKey, - VotingPower: allocs[validatorInfo.Address].Balance.Uint64(), - }) + VotingPower: chain.ConvertWeiToTokensAmount(validatorInfo.Balance).Uint64(), + } } return accSet.AsGenericMaps(), nil diff --git a/command/rootchain/initcontracts/params.go b/command/rootchain/initcontracts/params.go index c01a1610dc..cbdbf8ce3e 100644 --- a/command/rootchain/initcontracts/params.go +++ b/command/rootchain/initcontracts/params.go @@ -7,23 +7,19 @@ import ( ) const ( - contractsPathFlag = "path" - validatorPrefixPathFlag = "validator-prefix" - validatorPathFlag = "validator-path" - genesisPathFlag = "genesis-path" - jsonRPCFlag = "json-rpc" + contractsPathFlag = "path" + manifestPathFlag = "manifest" + jsonRPCFlag = "json-rpc" + adminKeyFlag = "admin-key" - defaultValidatorPrefixPath = "test-chain-" - defaultValidatorPath = "./" - defaultGenesisPath = "./genesis.json" + defaultManifestPath = "./manifest.json" ) type initContractsParams struct { - contractsPath string - validatorPrefixPath string - validatorPath string - genesisPath string - jsonRPCAddress string + contractsPath string + manifestPath string + adminKey string + jsonRPCAddress string } func (ip *initContractsParams) validateFlags() error { @@ -31,12 +27,8 @@ func (ip *initContractsParams) validateFlags() error { return fmt.Errorf("provided smart contracts directory '%s' doesn't exist", ip.contractsPath) } - if _, err := os.Stat(ip.validatorPath); errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("provided validators data directory '%s' doesn't exist", ip.validatorPath) - } - - if _, err := os.Stat(ip.genesisPath); errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("provided genesis path '%s' doesn't exist", ip.genesisPath) + if _, err := os.Stat(ip.manifestPath); errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("provided manifest path '%s' doesn't exist", ip.manifestPath) } return nil diff --git a/consensus/polybft/README.md b/consensus/polybft/README.md new file mode 100644 index 0000000000..c1b5f1935d --- /dev/null +++ b/consensus/polybft/README.md @@ -0,0 +1,84 @@ + +# Polybft consensus protocol + +Polybft is a consensus protocol, which runs [go-ibft](https://github.com/0xPolygon/go-ibft) consensus engine. + +It has native support for running bridge, which enables running cross-chain transactions with Ethereum-compatible blockchains. + +## Setup local testing environment + +### Precondition + +Smart contracts in the `core-contracts` submodule must be compiled before running following commands. +In order to do so, run `make compile-core-contracts`. + +1. Build binary + + ```bash + go build -o polygon-edge . + ``` + +2. Init secrets - this command is used to generate private keys (ECDSA, BLS as well as P2P networking node id). `--data-dir` denotes folder prefix names and `--num` how many accounts need to be created. **This command is for testing purposes only.** + + ```bash + polygon-edge polybft-secrets --data-dir test-chain- --num 4 + ``` + +3. Start rootchain server - rootchain server is a Geth instance running in dev mode, which simulates Ethereum network. **This command is for testing purposes only.** + + ```bash + polygon-edge rootchain server + ``` + +4. Generate manifest file - manifest file contains public validator information as well as bridge configuration. It is intermediary file which is later used for genesis specification generation as well as rootchain contracts deployment. + + There are two ways to provide validators information: + + - all the validators information is present in local storage of single host and therefore directory if provided using `--validators-path` flag and validators folder prefix names using `--validators-prefix` flag + + ```bash + polygon-edge manifest [--validators-path ./] [--validators-prefix test-chain-] + [--path ./manifest.json] [--premine-validators 100] + ``` + + - validators information are scafollded on multiple hosts and therefore we supply necessary information using `--validators` flag. Validator information needs to be supplied in the strictly following format: + `::`. + + ```bash + polygon-edge manifest + --validators 16Uiu2HAmTkqGixWVxshMbbgtXhTUP8zLCZZiG1UyCNtxLhCkZJuv:0xDcBe0024206ec42b0Ef4214Ac7B71aeae1A11af0:1cf134e02c6b2afb2ceda50bf2c9a01da367ac48f7783ee6c55444e1cab418ec0f52837b90a4d8cf944814073fc6f2bd96f35366a3846a8393e3cb0b19197cde23e2b40c6401fa27ff7d0c36779d9d097d1393cab6fc1d332f92fb3df850b78703b2989d567d1344e219f0667a1863f52f7663092276770cf513f9704b5351c4 + [--validators 16Uiu2HAm1kVEh4uVw41WuhDfreCaVuj3kiWZy44kbnJrZnwnMKDW:0x2da750eD4AE1D5A7F7c996Faec592F3d44060e90:088d92c25b5f278750534e8a902da604a1aa39b524b4511f5f47c3a386374ca3031b667beb424faef068a01cee3428a1bc8c1c8bab826f30a1ee03fbe90cb5f01abcf4abd7af3bbe83eaed6f82179b9cbdc417aad65d919b802d91c2e1aaefec27ba747158bc18a0556e39bfc9175c099dd77517a85731894bbea3d191a622bc] + [--path ./manifest.json] [--premine-validators 100] + ``` + +5. Deploy and initialize rootchain contracts - this command deploys rootchain smart contracts and initializes them. It also updates manifest configuration with rootchain contract addresses and rootchain default sender address. + + ```bash + polygon-edge rootchain init-contracts [--manifest ./manifest.json] [--contracts-path ./core-contracts/artifacts] + [--json-rpc http://127.0.0.1:8545] [--admin-key ] + ``` + +6. Create chain configuration - this command creates chain configuration, which is needed to run a blockchain + + ```bash + polygon-edge genesis --consensus polybft --block-gas-limit 10000000 --epoch-size 10 + [--bridge-json-rpc ] [--contracts-path ./core-contracts/artifacts] [--manifest ./manifest.json] + ``` + +7. Fund validators on rootchain - in order for validators to be able to send transactions to Ethereum, they need to be funded in order to be able to cover gas cost. **This command is for testing purposes only.** + + ```bash + polygon-edge rootchain fund --data-dir test-chain- --num 4 + ``` + +8. Run (sidechain) cluster, consisting of 4 Edge clients in this particular example + + ```bash + polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :5001 --libp2p :30301 --jsonrpc :9545 --seal --log-level DEBUG + + polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :5002 --libp2p :30302 --jsonrpc :10002 --seal --log-level DEBUG + + polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :5003 --libp2p :30303 --jsonrpc :10003 --seal --log-level DEBUG + + polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :5004 --libp2p :30304 --jsonrpc :10004 --seal --log-level DEBUG + ``` diff --git a/consensus/polybft/checkpoint_manager.go b/consensus/polybft/checkpoint_manager.go index aa128ec62e..235d7d3184 100644 --- a/consensus/polybft/checkpoint_manager.go +++ b/consensus/polybft/checkpoint_manager.go @@ -5,7 +5,6 @@ import ( "math/big" "strconv" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -46,6 +45,8 @@ type checkpointManager struct { txRelayer txrelayer.TxRelayer // checkpointsOffset represents offset between checkpoint blocks (applicable only for non-epoch ending blocks) checkpointsOffset uint64 + // checkpointManagerAddr is address of CheckpointManager smart contract + checkpointManagerAddr types.Address // latestCheckpointID represents last checkpointed block number latestCheckpointID uint64 // logger instance @@ -53,15 +54,17 @@ type checkpointManager struct { } // newCheckpointManager creates a new instance of checkpointManager -func newCheckpointManager(key ethgo.Key, checkpointOffset uint64, txRelayer txrelayer.TxRelayer, +func newCheckpointManager(key ethgo.Key, checkpointOffset uint64, + checkpointManagerSC types.Address, txRelayer txrelayer.TxRelayer, blockchain blockchainBackend, backend polybftBackend, logger hclog.Logger) *checkpointManager { return &checkpointManager{ - key: key, - blockchain: blockchain, - consensusBackend: backend, - txRelayer: txRelayer, - checkpointsOffset: checkpointOffset, - logger: logger, + key: key, + blockchain: blockchain, + consensusBackend: backend, + txRelayer: txRelayer, + checkpointsOffset: checkpointOffset, + checkpointManagerAddr: checkpointManagerSC, + logger: logger, } } @@ -74,7 +77,7 @@ func (c *checkpointManager) getLatestCheckpointBlock() (uint64, error) { latestCheckpointBlockRaw, err := c.txRelayer.Call( c.key.Address(), - ethgo.Address(helper.CheckpointManagerAddress), + ethgo.Address(c.checkpointManagerAddr), checkpointBlockNumMethodEncoded) if err != nil { return 0, fmt.Errorf("failed to invoke currentCheckpointId function on the rootchain: %w", err) @@ -100,7 +103,7 @@ func (c *checkpointManager) submitCheckpoint(latestHeader types.Header, isEndOfE "latest checkpoint block", lastCheckpointBlockNumber, "checkpoint block", latestHeader.Number) - checkpointManagerAddr := ethgo.Address(helper.CheckpointManagerAddress) + checkpointManagerAddr := ethgo.Address(c.checkpointManagerAddr) txn := ðgo.Transaction{ To: &checkpointManagerAddr, From: c.key.Address(), diff --git a/consensus/polybft/checkpoint_manager_test.go b/consensus/polybft/checkpoint_manager_test.go index 3d1cad7eba..ecb7ffe6a5 100644 --- a/consensus/polybft/checkpoint_manager_test.go +++ b/consensus/polybft/checkpoint_manager_test.go @@ -267,7 +267,7 @@ func TestCheckpointManager_isCheckpointBlock(t *testing.T) { t.Run(c.name, func(t *testing.T) { t.Parallel() - checkpointMgr := newCheckpointManager(wallet.NewEcdsaSigner(createTestKey(t)), c.checkpointsOffset, nil, nil, nil, hclog.NewNullLogger()) + checkpointMgr := newCheckpointManager(wallet.NewEcdsaSigner(createTestKey(t)), c.checkpointsOffset, types.ZeroAddress, nil, nil, nil, hclog.NewNullLogger()) require.Equal(t, c.isCheckpointBlock, checkpointMgr.isCheckpointBlock(c.blockNumber)) }) } diff --git a/consensus/polybft/consensus_runtime.go b/consensus/polybft/consensus_runtime.go index 3ad0e645b7..95d0fa9de9 100644 --- a/consensus/polybft/consensus_runtime.go +++ b/consensus/polybft/consensus_runtime.go @@ -129,6 +129,7 @@ func newConsensusRuntime(log hcf.Logger, config *runtimeConfig) (*consensusRunti runtime.checkpointManager = newCheckpointManager( wallet.NewEcdsaSigner(config.Key), defaultCheckpointsOffset, + config.PolyBFTConfig.Bridge.CheckpointAddr, txRelayer, config.blockchain, config.polybftBackend, diff --git a/consensus/polybft/consensus_runtime_test.go b/consensus/polybft/consensus_runtime_test.go index 0fc69c9bf2..766b7049c4 100644 --- a/consensus/polybft/consensus_runtime_test.go +++ b/consensus/polybft/consensus_runtime_test.go @@ -1620,7 +1620,7 @@ func TestConsensusRuntime_FSM_EndOfEpoch_OnBlockInserted(t *testing.T) { epoch: metadata, config: config, lastBuiltBlock: lastBuiltBlock, - checkpointManager: newCheckpointManager(wallet.NewEcdsaSigner(signer), 5, nil, nil, nil, hclog.NewNullLogger()), + checkpointManager: newCheckpointManager(wallet.NewEcdsaSigner(signer), 5, types.ZeroAddress, nil, nil, nil, hclog.NewNullLogger()), } err = runtime.FSM() diff --git a/consensus/polybft/contractsapi/gen_sc_data.go b/consensus/polybft/contractsapi/gen_sc_data.go index cbade664ec..daba2bae92 100644 --- a/consensus/polybft/contractsapi/gen_sc_data.go +++ b/consensus/polybft/contractsapi/gen_sc_data.go @@ -1,6 +1,6 @@ package contractsapi -// This is generated file don't change it manually. DO NOT EDIT. +// This is auto-generated file. DO NOT EDIT. var CheckpointManagerArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"CheckpointManager\",\n \"sourceName\": \"contracts/root/CheckpointManager.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"bls\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bn256G2\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpointBlockNumbers\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpoints\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentCheckpointBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"currentValidatorSet\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentValidatorSetLength\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"domain\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getEventRootByBlock\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"newBls\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"newBn256G2\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"newDomain\",\n \"type\": \"bytes32\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"chainId\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"blockHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockRound\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"currentValidatorSetHash\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.CheckpointMetadata\",\n \"name\": \"checkpointMetadata\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Checkpoint\",\n \"name\": \"checkpoint\",\n \"type\": \"tuple\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"submit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalVotingPower\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611565806100206000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80637667180811610097578063c2fb26a611610066578063c2fb26a614610260578063d4c8e3e814610269578063e416d6771461027c578063e9193d2b1461028557600080fd5b806376671808146101cf57806395b0b027146101d8578063b8a2425214610203578063bb1853ca1461024d57600080fd5b806361a02208116100d357806361a022081461013e578063671b3793146101615780636969a25c1461016a578063729e7c6e146101bc57600080fd5b80631d1d4f26146100fa5780633569ed93146101165780635036759a14610129575b600080fd5b61010360025481565b6040519081526020015b60405180910390f35b610103610124366004610e7b565b610298565b61013c610137366004610ef8565b6102cc565b005b61015161014c366004610f6b565b610423565b604051901515815260200161010d565b61010360045481565b61019d610178366004610e7b565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161010d565b6101516101ca366004610f6b565b610496565b61010360015481565b6006546101eb906001600160a01b031681565b6040516001600160a01b03909116815260200161010d565b610232610211366004610e7b565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161010d565b61013c61025b366004611013565b6104f5565b61010360055481565b6007546101eb906001600160a01b031681565b61010360035481565b610103610293366004610e7b565b61070b565b60006008816102a8600a8561072c565b6102b390600161110b565b8152602001908152602001600020600201549050919050565b600054610100900460ff16158080156102ec5750600054600160ff909116105b806103065750303b158015610306575060005460ff166001145b61036e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610391576000805461ff0019166101001790555b600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600584905560028290556103d583836107db565b801561041b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008061042f87610298565b90508061047e5760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d42455200006044820152606401610365565b61048b86868387876108b2565b979650505050505050565b6000858152600860205260408120600201548061047e5760405162461bcd60e51b815260206004820152601760248201527f4e4f5f4556454e545f524f4f545f464f525f45504f43480000000000000000006044820152606401610365565b600088876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161052992919061111e565b60408051601f198184030181528282528051602091820120908301999099528101969096526060860194909452608085019290925260a084015260c083015260e08201526101008101919091526101200160408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065460055463a850a90960e01b8452919350610628926001600160a01b039091169163a850a909916105e091908690600401611181565b6040805180830381865afa1580156105fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062091906111d7565b8785856109cb565b600180546000918261063983611265565b9190505590506106498189610d0b565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156106b957600a805460018101825560009190915260208901357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8909101556106ed565b600a805460208a013591906106d09060019061127e565b815481106106e0576106e0611291565b6000918252602090912001555b60208801356003556106ff86866107db565b50505050505050505050565b600a818154811061071b57600080fd5b600091825260209091200154905081565b8154600090810361073f575060006107d5565b82546000905b8082101561078c5760006107598383610dd2565b6000878152602090209091508590820154111561077857809150610786565b61078381600161110b565b92505b50610745565b6000821180156107b85750836107b5866107a760018661127e565b600091825260209091200190565b54145b156107d1576107c860018361127e565b925050506107d5565b5090505b92915050565b6002819055806000805b828110156108a957600085858381811061080157610801611291565b905060c0020160a001359050600081116108515760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b6044820152606401610365565b61085b818461110b565b925085858381811061086f5761086f611291565b905060c0020160096000848152602001908152602001600020818161089491906112be565b90505050806108a290611265565b90506107e5565b50600455505050565b6000816108c0816002611401565b86106109035760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b6044820152606401610365565b8660005b828110156109bd57600086868381811061092357610923611291565b9050602002013590506002896109399190611423565b60000361097157604080516020810185905290810182905260600160405160208183030381529060405280519060200120925061099e565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b6109a960028a611437565b985050806109b690611265565b9050610907565b509094149695505050505050565b6002546109d6610e5d565b6000805b83811015610b81576109ed868683610df4565b15610b795781600003610a41576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610a225750505050509250610b5a565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610a6857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81526004810198909852602488019590955260448701929092526064860191909152608485019390935260a484019190915260c483019190915260e48201529495506001600160a01b03169363cbe96a50935061010401915050608060405180830381865afa158015610b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b47919061144b565b6060880152604087015260208601528452505b600081815260096020526040902060050154610b76908361110b565b91505b6001016109da565b5080600003610bc45760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b6044820152606401610365565b60036004546002610bd591906112a7565b610bdf9190611437565b8111610c2d5760405162461bcd60e51b815260206004820152601960248201527f494e53554646494349454e545f564f54494e475f504f574552000000000000006044820152606401610365565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610c66908b9088908e90600401611481565b6040805180830381865afa158015610c82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca691906114fc565b91509150818015610cb45750805b610d005760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610365565b505050505050505050565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351015610d835760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b6044820152606401610365565b8060200151826020013511610dcd5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b6044820152606401610365565b505050565b6000610de16002848418611437565b610ded9084841661110b565b9392505050565b600080610e02600884611437565b90506000610e11600885611423565b9050848210610e2557600092505050610ded565b6000600160ff83161b878785818110610e4057610e40611291565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610e8d57600080fd5b5035919050565b6001600160a01b0381168114610ea957600080fd5b50565b60008083601f840112610ebe57600080fd5b50813567ffffffffffffffff811115610ed657600080fd5b60208301915083602060c083028501011115610ef157600080fd5b9250929050565b600080600080600060808688031215610f1057600080fd5b8535610f1b81610e94565b94506020860135610f2b81610e94565b935060408601359250606086013567ffffffffffffffff811115610f4e57600080fd5b610f5a88828901610eac565b969995985093965092949392505050565b600080600080600060808688031215610f8357600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff80821115610fb057600080fd5b818801915088601f830112610fc457600080fd5b813581811115610fd357600080fd5b8960208260051b8501011115610fe857600080fd5b9699959850939650602001949392505050565b60006060828403121561100d57600080fd5b50919050565b600080600080600080600080610160898b03121561103057600080fd5b883597506110418a60208b01610ffb565b96506110508a60808b01610ffb565b955061012089018a81111561106457600080fd5b60e08a0195503567ffffffffffffffff8082111561108157600080fd5b61108d8c838d01610eac565b90965094506101408b01359150808211156110a757600080fd5b818b0191508b601f8301126110bb57600080fd5b8135818111156110ca57600080fd5b8c60208285010111156110dc57600080fd5b6020830194508093505050509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b808201808211156107d5576107d56110f5565b60208082528181018390526000908460408401835b8681101561117657823561114681610e94565b6001600160a01b0316825260808385018584013760a0838101359083015260c09283019290910190600101611133565b509695505050505050565b82815260006020604081840152835180604085015260005b818110156111b557858101830151858201606001528201611199565b506000606082860101526060601f19601f830116850101925050509392505050565b6000604082840312156111e957600080fd5b82601f8301126111f857600080fd5b6040516040810181811067ffffffffffffffff8211171561122957634e487b7160e01b600052604160045260246000fd5b806040525080604084018581111561124057600080fd5b845b8181101561125a578051835260209283019201611242565b509195945050505050565b600060018201611277576112776110f5565b5060010190565b818103818111156107d5576107d56110f5565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176107d5576107d56110f5565b81356112c981610e94565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b600481101561130c578135600182860181019190915591830191016112ec565b50505060a082013560058201555050565b600181815b8085111561135857816000190482111561133e5761133e6110f5565b8085161561134b57918102915b93841c9390800290611322565b509250929050565b60008261136f575060016107d5565b8161137c575060006107d5565b8160018114611392576002811461139c576113b8565b60019150506107d5565b60ff8411156113ad576113ad6110f5565b50506001821b6107d5565b5060208310610133831016604e8410600b84101617156113db575081810a6107d5565b6113e5838361131d565b80600019048211156113f9576113f96110f5565b029392505050565b6000610ded8383611360565b634e487b7160e01b600052601260045260246000fd5b6000826114325761143261140d565b500690565b6000826114465761144661140d565b500490565b6000806000806080858703121561146157600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b60048110156114b2578151835260209283019290910190600101611493565b50505060c082018360005b60028110156114dc5781518352602092830192909101906001016114bd565b505050949350505050565b805180151581146114f757600080fd5b919050565b6000806040838503121561150f57600080fd5b611518836114e7565b9150611526602084016114e7565b9050925092905056fea2646970667358221220a0c0838b66ae5561939526edc9c8be8257337a63060f8b3cb9c0f83765c9510364736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100f55760003560e01c80637667180811610097578063c2fb26a611610066578063c2fb26a614610260578063d4c8e3e814610269578063e416d6771461027c578063e9193d2b1461028557600080fd5b806376671808146101cf57806395b0b027146101d8578063b8a2425214610203578063bb1853ca1461024d57600080fd5b806361a02208116100d357806361a022081461013e578063671b3793146101615780636969a25c1461016a578063729e7c6e146101bc57600080fd5b80631d1d4f26146100fa5780633569ed93146101165780635036759a14610129575b600080fd5b61010360025481565b6040519081526020015b60405180910390f35b610103610124366004610e7b565b610298565b61013c610137366004610ef8565b6102cc565b005b61015161014c366004610f6b565b610423565b604051901515815260200161010d565b61010360045481565b61019d610178366004610e7b565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161010d565b6101516101ca366004610f6b565b610496565b61010360015481565b6006546101eb906001600160a01b031681565b6040516001600160a01b03909116815260200161010d565b610232610211366004610e7b565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161010d565b61013c61025b366004611013565b6104f5565b61010360055481565b6007546101eb906001600160a01b031681565b61010360035481565b610103610293366004610e7b565b61070b565b60006008816102a8600a8561072c565b6102b390600161110b565b8152602001908152602001600020600201549050919050565b600054610100900460ff16158080156102ec5750600054600160ff909116105b806103065750303b158015610306575060005460ff166001145b61036e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610391576000805461ff0019166101001790555b600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600584905560028290556103d583836107db565b801561041b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008061042f87610298565b90508061047e5760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d42455200006044820152606401610365565b61048b86868387876108b2565b979650505050505050565b6000858152600860205260408120600201548061047e5760405162461bcd60e51b815260206004820152601760248201527f4e4f5f4556454e545f524f4f545f464f525f45504f43480000000000000000006044820152606401610365565b600088876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161052992919061111e565b60408051601f198184030181528282528051602091820120908301999099528101969096526060860194909452608085019290925260a084015260c083015260e08201526101008101919091526101200160408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065460055463a850a90960e01b8452919350610628926001600160a01b039091169163a850a909916105e091908690600401611181565b6040805180830381865afa1580156105fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062091906111d7565b8785856109cb565b600180546000918261063983611265565b9190505590506106498189610d0b565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156106b957600a805460018101825560009190915260208901357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8909101556106ed565b600a805460208a013591906106d09060019061127e565b815481106106e0576106e0611291565b6000918252602090912001555b60208801356003556106ff86866107db565b50505050505050505050565b600a818154811061071b57600080fd5b600091825260209091200154905081565b8154600090810361073f575060006107d5565b82546000905b8082101561078c5760006107598383610dd2565b6000878152602090209091508590820154111561077857809150610786565b61078381600161110b565b92505b50610745565b6000821180156107b85750836107b5866107a760018661127e565b600091825260209091200190565b54145b156107d1576107c860018361127e565b925050506107d5565b5090505b92915050565b6002819055806000805b828110156108a957600085858381811061080157610801611291565b905060c0020160a001359050600081116108515760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b6044820152606401610365565b61085b818461110b565b925085858381811061086f5761086f611291565b905060c0020160096000848152602001908152602001600020818161089491906112be565b90505050806108a290611265565b90506107e5565b50600455505050565b6000816108c0816002611401565b86106109035760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b6044820152606401610365565b8660005b828110156109bd57600086868381811061092357610923611291565b9050602002013590506002896109399190611423565b60000361097157604080516020810185905290810182905260600160405160208183030381529060405280519060200120925061099e565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b6109a960028a611437565b985050806109b690611265565b9050610907565b509094149695505050505050565b6002546109d6610e5d565b6000805b83811015610b81576109ed868683610df4565b15610b795781600003610a41576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610a225750505050509250610b5a565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610a6857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81526004810198909852602488019590955260448701929092526064860191909152608485019390935260a484019190915260c483019190915260e48201529495506001600160a01b03169363cbe96a50935061010401915050608060405180830381865afa158015610b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b47919061144b565b6060880152604087015260208601528452505b600081815260096020526040902060050154610b76908361110b565b91505b6001016109da565b5080600003610bc45760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b6044820152606401610365565b60036004546002610bd591906112a7565b610bdf9190611437565b8111610c2d5760405162461bcd60e51b815260206004820152601960248201527f494e53554646494349454e545f564f54494e475f504f574552000000000000006044820152606401610365565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610c66908b9088908e90600401611481565b6040805180830381865afa158015610c82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca691906114fc565b91509150818015610cb45750805b610d005760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610365565b505050505050505050565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351015610d835760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b6044820152606401610365565b8060200151826020013511610dcd5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b6044820152606401610365565b505050565b6000610de16002848418611437565b610ded9084841661110b565b9392505050565b600080610e02600884611437565b90506000610e11600885611423565b9050848210610e2557600092505050610ded565b6000600160ff83161b878785818110610e4057610e40611291565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610e8d57600080fd5b5035919050565b6001600160a01b0381168114610ea957600080fd5b50565b60008083601f840112610ebe57600080fd5b50813567ffffffffffffffff811115610ed657600080fd5b60208301915083602060c083028501011115610ef157600080fd5b9250929050565b600080600080600060808688031215610f1057600080fd5b8535610f1b81610e94565b94506020860135610f2b81610e94565b935060408601359250606086013567ffffffffffffffff811115610f4e57600080fd5b610f5a88828901610eac565b969995985093965092949392505050565b600080600080600060808688031215610f8357600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff80821115610fb057600080fd5b818801915088601f830112610fc457600080fd5b813581811115610fd357600080fd5b8960208260051b8501011115610fe857600080fd5b9699959850939650602001949392505050565b60006060828403121561100d57600080fd5b50919050565b600080600080600080600080610160898b03121561103057600080fd5b883597506110418a60208b01610ffb565b96506110508a60808b01610ffb565b955061012089018a81111561106457600080fd5b60e08a0195503567ffffffffffffffff8082111561108157600080fd5b61108d8c838d01610eac565b90965094506101408b01359150808211156110a757600080fd5b818b0191508b601f8301126110bb57600080fd5b8135818111156110ca57600080fd5b8c60208285010111156110dc57600080fd5b6020830194508093505050509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b808201808211156107d5576107d56110f5565b60208082528181018390526000908460408401835b8681101561117657823561114681610e94565b6001600160a01b0316825260808385018584013760a0838101359083015260c09283019290910190600101611133565b509695505050505050565b82815260006020604081840152835180604085015260005b818110156111b557858101830151858201606001528201611199565b506000606082860101526060601f19601f830116850101925050509392505050565b6000604082840312156111e957600080fd5b82601f8301126111f857600080fd5b6040516040810181811067ffffffffffffffff8211171561122957634e487b7160e01b600052604160045260246000fd5b806040525080604084018581111561124057600080fd5b845b8181101561125a578051835260209283019201611242565b509195945050505050565b600060018201611277576112776110f5565b5060010190565b818103818111156107d5576107d56110f5565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176107d5576107d56110f5565b81356112c981610e94565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b600481101561130c578135600182860181019190915591830191016112ec565b50505060a082013560058201555050565b600181815b8085111561135857816000190482111561133e5761133e6110f5565b8085161561134b57918102915b93841c9390800290611322565b509250929050565b60008261136f575060016107d5565b8161137c575060006107d5565b8160018114611392576002811461139c576113b8565b60019150506107d5565b60ff8411156113ad576113ad6110f5565b50506001821b6107d5565b5060208310610133831016604e8410600b84101617156113db575081810a6107d5565b6113e5838361131d565b80600019048211156113f9576113f96110f5565b029392505050565b6000610ded8383611360565b634e487b7160e01b600052601260045260246000fd5b6000826114325761143261140d565b500690565b6000826114465761144661140d565b500490565b6000806000806080858703121561146157600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b60048110156114b2578151835260209283019290910190600101611493565b50505060c082018360005b60028110156114dc5781518352602092830192909101906001016114bd565b505050949350505050565b805180151581146114f757600080fd5b919050565b6000806040838503121561150f57600080fd5b611518836114e7565b9150611526602084016114e7565b9050925092905056fea2646970667358221220a0c0838b66ae5561939526edc9c8be8257337a63060f8b3cb9c0f83765c9510364736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" var ExitHelperArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ExitHelper\",\n \"sourceName\": \"contracts/root/ExitHelper.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"success\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"returnData\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"ExitProcessed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"internalType\": \"struct IExitHelper.BatchExitInput[]\",\n \"name\": \"inputs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"batchExit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"checkpointManager\",\n \"outputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"exit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"newCheckpointManager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"processedExits\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610b6f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a36600461070d565b6100fa565b005b61006f61007f36600461074f565b61022c565b6100a7610092366004610800565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f5366004610831565b61029c565b6002546001600160a01b03166101575760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a204e4f545f494e495449414c495a4544000000000060448201526064015b60405180910390fd5b8060005b818110156102265761021e84848381811061017857610178610855565b905060200281019061018a919061086b565b3585858481811061019d5761019d610855565b90506020028101906101af919061086b565b602001358686858181106101c5576101c5610855565b90506020028101906101d7919061086b565b6101e590604081019061088b565b8888878181106101f7576101f7610855565b9050602002810190610209919061086b565b6102179060608101906108d2565b600161042e565b60010161015b565b50505050565b6002546001600160a01b03166102845760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604482015260640161014e565b610294868686868686600061042e565b505050505050565b600054610100900460ff16158080156102bc5750600054600160ff909116105b806102d65750303b1580156102d6575060005460ff166001145b6103395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161014e565b6000805460ff19166001179055801561035c576000805461ff0019166101001790555b6001600160a01b0382161580159061037d57506001600160a01b0382163b15155b6103c95760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f414444524553530000000000604482015260640161014e565b600280546001600160a01b0319166001600160a01b038416179055801561042a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600080808061043f888a018a610932565b935093509350935084156104725760008481526001602052604090205460ff161561046d57505050506106b8565b6104dc565b60008481526001602052604090205460ff16156104dc5760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b606482015260840161014e565b6002546040516001600160a01b03909116906361a02208908d90610503908d908d90610a12565b6040519081900381206001600160e01b031960e085901b16825261053092918f908d908d90600401610a22565b602060405180830381865afa15801561054d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105719190610a6f565b6105bd5760405162461bcd60e51b815260206004820152601960248201527f4578697448656c7065723a20494e56414c49445f50524f4f4600000000000000604482015260640161014e565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b038516906105fa90889088908790602401610ae1565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b1790525161062f9190610b14565b6000604051808303816000865af19150503d806000811461066c576040519150601f19603f3d011682016040523d82523d6000602084013e610671565b606091505b5091509150811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106a99190610b26565b60405180910390a35050505050505b50505050505050565b60008083601f8401126106d357600080fd5b50813567ffffffffffffffff8111156106eb57600080fd5b6020830191508360208260051b850101111561070657600080fd5b9250929050565b6000806020838503121561072057600080fd5b823567ffffffffffffffff81111561073757600080fd5b610743858286016106c1565b90969095509350505050565b6000806000806000806080878903121561076857600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561078e57600080fd5b818901915089601f8301126107a257600080fd5b8135818111156107b157600080fd5b8a60208285010111156107c357600080fd5b6020830196508095505060608901359150808211156107e157600080fd5b506107ee89828a016106c1565b979a9699509497509295939492505050565b60006020828403121561081257600080fd5b5035919050565b6001600160a01b038116811461082e57600080fd5b50565b60006020828403121561084357600080fd5b813561084e81610819565b9392505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261088157600080fd5b9190910192915050565b6000808335601e198436030181126108a257600080fd5b83018035915067ffffffffffffffff8211156108bd57600080fd5b60200191503681900382131561070657600080fd5b6000808335601e198436030181126108e957600080fd5b83018035915067ffffffffffffffff82111561090457600080fd5b6020019150600581901b360382131561070657600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561094857600080fd5b84359350602085013561095a81610819565b9250604085013561096a81610819565b9150606085013567ffffffffffffffff8082111561098757600080fd5b818701915087601f83011261099b57600080fd5b8135818111156109ad576109ad61091c565b604051601f8201601f19908116603f011681019083821181831017156109d5576109d561091c565b816040528281528a60208487010111156109ee57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a5357600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a8157600080fd5b8151801515811461084e57600080fd5b60005b83811015610aac578181015183820152602001610a94565b50506000910152565b60008151808452610acd816020860160208601610a91565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610b0b90830184610ab5565b95945050505050565b60008251610881818460208701610a91565b60208152600061084e6020830184610ab556fea2646970667358221220f024c117ff29e95e3e391e2131ae3a5484ff847b61c45d9cfa75dd4b0eef5f8b64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a36600461070d565b6100fa565b005b61006f61007f36600461074f565b61022c565b6100a7610092366004610800565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f5366004610831565b61029c565b6002546001600160a01b03166101575760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a204e4f545f494e495449414c495a4544000000000060448201526064015b60405180910390fd5b8060005b818110156102265761021e84848381811061017857610178610855565b905060200281019061018a919061086b565b3585858481811061019d5761019d610855565b90506020028101906101af919061086b565b602001358686858181106101c5576101c5610855565b90506020028101906101d7919061086b565b6101e590604081019061088b565b8888878181106101f7576101f7610855565b9050602002810190610209919061086b565b6102179060608101906108d2565b600161042e565b60010161015b565b50505050565b6002546001600160a01b03166102845760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604482015260640161014e565b610294868686868686600061042e565b505050505050565b600054610100900460ff16158080156102bc5750600054600160ff909116105b806102d65750303b1580156102d6575060005460ff166001145b6103395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161014e565b6000805460ff19166001179055801561035c576000805461ff0019166101001790555b6001600160a01b0382161580159061037d57506001600160a01b0382163b15155b6103c95760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f414444524553530000000000604482015260640161014e565b600280546001600160a01b0319166001600160a01b038416179055801561042a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600080808061043f888a018a610932565b935093509350935084156104725760008481526001602052604090205460ff161561046d57505050506106b8565b6104dc565b60008481526001602052604090205460ff16156104dc5760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b606482015260840161014e565b6002546040516001600160a01b03909116906361a02208908d90610503908d908d90610a12565b6040519081900381206001600160e01b031960e085901b16825261053092918f908d908d90600401610a22565b602060405180830381865afa15801561054d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105719190610a6f565b6105bd5760405162461bcd60e51b815260206004820152601960248201527f4578697448656c7065723a20494e56414c49445f50524f4f4600000000000000604482015260640161014e565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b038516906105fa90889088908790602401610ae1565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b1790525161062f9190610b14565b6000604051808303816000865af19150503d806000811461066c576040519150601f19603f3d011682016040523d82523d6000602084013e610671565b606091505b5091509150811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106a99190610b26565b60405180910390a35050505050505b50505050505050565b60008083601f8401126106d357600080fd5b50813567ffffffffffffffff8111156106eb57600080fd5b6020830191508360208260051b850101111561070657600080fd5b9250929050565b6000806020838503121561072057600080fd5b823567ffffffffffffffff81111561073757600080fd5b610743858286016106c1565b90969095509350505050565b6000806000806000806080878903121561076857600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561078e57600080fd5b818901915089601f8301126107a257600080fd5b8135818111156107b157600080fd5b8a60208285010111156107c357600080fd5b6020830196508095505060608901359150808211156107e157600080fd5b506107ee89828a016106c1565b979a9699509497509295939492505050565b60006020828403121561081257600080fd5b5035919050565b6001600160a01b038116811461082e57600080fd5b50565b60006020828403121561084357600080fd5b813561084e81610819565b9392505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261088157600080fd5b9190910192915050565b6000808335601e198436030181126108a257600080fd5b83018035915067ffffffffffffffff8211156108bd57600080fd5b60200191503681900382131561070657600080fd5b6000808335601e198436030181126108e957600080fd5b83018035915067ffffffffffffffff82111561090457600080fd5b6020019150600581901b360382131561070657600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561094857600080fd5b84359350602085013561095a81610819565b9250604085013561096a81610819565b9150606085013567ffffffffffffffff8082111561098757600080fd5b818701915087601f83011261099b57600080fd5b8135818111156109ad576109ad61091c565b604051601f8201601f19908116603f011681019083821181831017156109d5576109d561091c565b816040528281528a60208487010111156109ee57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a5357600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a8157600080fd5b8151801515811461084e57600080fd5b60005b83811015610aac578181015183820152602001610a94565b50506000910152565b60008151808452610acd816020860160208601610a91565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610b0b90830184610ab5565b95945050505050565b60008251610881818460208701610a91565b60208152600061084e6020830184610ab556fea2646970667358221220f024c117ff29e95e3e391e2131ae3a5484ff847b61c45d9cfa75dd4b0eef5f8b64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" var L2StateSenderArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"L2StateSender\",\n \"sourceName\": \"contracts/child/L2StateSender.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"L2StateSynced\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"counter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"syncState\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806316f198311461003b57806361bc221a14610050575b600080fd5b61004e61004936600461011c565b61006b565b005b61005960005481565b60405190815260200160405180910390f35b6108008111156100b65760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b604482015260640160405180910390fd5b826001600160a01b0316336001600160a01b031660008081546100d8906101ad565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161010f9291906101d4565b60405180910390a4505050565b60008060006040848603121561013157600080fd5b83356001600160a01b038116811461014857600080fd5b9250602084013567ffffffffffffffff8082111561016557600080fd5b818601915086601f83011261017957600080fd5b81358181111561018857600080fd5b87602082850101111561019a57600080fd5b6020830194508093505050509250925092565b6000600182016101cd57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122025c8b63e0888fc8f500a5ce6bf1553db80a3f3339c5c12f5ba280a7b7466c5f664736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100365760003560e01c806316f198311461003b57806361bc221a14610050575b600080fd5b61004e61004936600461011c565b61006b565b005b61005960005481565b60405190815260200160405180910390f35b6108008111156100b65760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b604482015260640160405180910390fd5b826001600160a01b0316336001600160a01b031660008081546100d8906101ad565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161010f9291906101d4565b60405180910390a4505050565b60008060006040848603121561013157600080fd5b83356001600160a01b038116811461014857600080fd5b9250602084013567ffffffffffffffff8082111561016557600080fd5b818601915086601f83011261017957600080fd5b81358181111561018857600080fd5b87602082850101111561019a57600080fd5b6020830194508093505050509250925092565b6000600182016101cd57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122025c8b63e0888fc8f500a5ce6bf1553db80a3f3339c5c12f5ba280a7b7466c5f664736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" diff --git a/consensus/polybft/polybft.go b/consensus/polybft/polybft.go index f553df459f..f3b955c072 100644 --- a/consensus/polybft/polybft.go +++ b/consensus/polybft/polybft.go @@ -9,7 +9,6 @@ import ( "time" "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" @@ -112,14 +111,7 @@ type Polybft struct { func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *state.Transition) error { return func(transition *state.Transition) error { - consensusConfigJSON, err := json.Marshal(config.Params.Engine[engineName]) - if err != nil { - return err - } - - var polyBFTConfig PolyBFTConfig - err = json.Unmarshal(consensusConfigJSON, &polyBFTConfig) - + polyBFTConfig, err := GetPolyBFTConfig(config) if err != nil { return err } @@ -134,8 +126,17 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st return err } + if err != nil { + return fmt.Errorf("failed loading rootchain manifest: %w", err) + } + + rootchainAdmin := types.ZeroAddress + if polyBFTConfig.IsBridgeEnabled() { + rootchainAdmin = polyBFTConfig.Bridge.AdminAddress + } + input, err = nativeTokenInitializer.Encode( - []interface{}{helper.GetRootchainAdminAddr(), nativeTokenName, nativeTokenSymbol}) + []interface{}{rootchainAdmin, nativeTokenName, nativeTokenSymbol}) if err != nil { return err } diff --git a/consensus/polybft/polybft_config.go b/consensus/polybft/polybft_config.go index b19f3d2ea5..6d0bc701a3 100644 --- a/consensus/polybft/polybft_config.go +++ b/consensus/polybft/polybft_config.go @@ -3,38 +3,65 @@ package polybft import ( "encoding/hex" "encoding/json" + "fmt" "math/big" + "os" + "path/filepath" "time" + "github.com/0xPolygon/polygon-edge/chain" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/types" ) // PolyBFTConfig is the configuration file for the Polybft consensus protocol. type PolyBFTConfig struct { - InitialValidatorSet []*Validator `json:"initialValidatorSet"` - Bridge *BridgeConfig `json:"bridge"` + // InitialValidatorSet are the genesis validators + InitialValidatorSet []*Validator `json:"initialValidatorSet"` - ValidatorSetSize int `json:"validatorSetSize"` + // Bridge is the rootchain bridge configuration + Bridge *BridgeConfig `json:"bridge"` - // Address of the system contracts, as of now (testing) this is populated automatically during genesis - ValidatorSetAddr types.Address `json:"validatorSetAddr"` - StateReceiverAddr types.Address `json:"stateReceiverAddr"` + // EpochSize is size of epoch + EpochSize uint64 `json:"epochSize"` - // size of the epoch and sprint - EpochSize uint64 `json:"epochSize"` + // SprintSize is size of sprint SprintSize uint64 `json:"sprintSize"` + // BlockTime is target frequency of blocks production BlockTime time.Duration `json:"blockTime"` // Governance is the initial governance address Governance types.Address `json:"governance"` + + // TODO: Remove these two addresses as they are hardcoded and known in advance + // Address of the system contracts, as of now (testing) this is populated automatically during genesis + ValidatorSetAddr types.Address `json:"validatorSetAddr"` + StateReceiverAddr types.Address `json:"stateReceiverAddr"` +} + +// GetPolyBFTConfig deserializes provided chain config and returns PolyBFTConfig +func GetPolyBFTConfig(chainConfig *chain.Chain) (PolyBFTConfig, error) { + consensusConfigJSON, err := json.Marshal(chainConfig.Params.Engine["polybft"]) + if err != nil { + return PolyBFTConfig{}, err + } + + var polyBFTConfig PolyBFTConfig + err = json.Unmarshal(consensusConfigJSON, &polyBFTConfig) + + if err != nil { + return PolyBFTConfig{}, err + } + + return polyBFTConfig, nil } // BridgeConfig is the rootchain bridge configuration type BridgeConfig struct { BridgeAddr types.Address `json:"stateSenderAddr"` CheckpointAddr types.Address `json:"checkpointAddr"` + AdminAddress types.Address `json:"adminAddress"` JSONRPCEndpoint string `json:"jsonRPCEndpoint"` } @@ -42,21 +69,23 @@ func (p *PolyBFTConfig) IsBridgeEnabled() bool { return p.Bridge != nil } +// Validator represents public information about validator accounts which are the part of genesis type Validator struct { - Address types.Address `json:"address"` - BlsKey string `json:"blsKey"` - Balance *big.Int `json:"balance"` - NodeID string `json:"-"` + Address types.Address + BlsKey string + Balance *big.Int + NodeID string } type validatorRaw struct { Address types.Address `json:"address"` BlsKey string `json:"blsKey"` Balance *string `json:"balance"` + NodeID string `json:"nodeId"` } func (v *Validator) MarshalJSON() ([]byte, error) { - raw := &validatorRaw{Address: v.Address, BlsKey: v.BlsKey} + raw := &validatorRaw{Address: v.Address, BlsKey: v.BlsKey, NodeID: v.NodeID} raw.Balance = types.EncodeBigInt(v.Balance) return json.Marshal(raw) @@ -73,6 +102,7 @@ func (v *Validator) UnmarshalJSON(data []byte) error { v.Address = raw.Address v.BlsKey = raw.BlsKey + v.NodeID = raw.NodeID v.Balance, err = types.ParseUint256orHex(raw.Balance) if err != nil { @@ -92,7 +122,74 @@ func (v *Validator) UnmarshalBLSPublicKey() (*bls.PublicKey, error) { return bls.UnmarshalPublicKey(decoded) } -// DebugConfig is a struct used for test configuration in init genesis -type DebugConfig struct { - ValidatorSetSize uint64 `json:"validatorSetSize"` +// ToValidatorMetadata creates ValidatorMetadata instance +func (v *Validator) ToValidatorMetadata() (*ValidatorMetadata, error) { + blsKey, err := v.UnmarshalBLSPublicKey() + if err != nil { + return nil, err + } + + metadata := &ValidatorMetadata{ + Address: v.Address, + BlsKey: blsKey, + VotingPower: chain.ConvertWeiToTokensAmount(v.Balance).Uint64(), + } + + return metadata, nil +} + +// RootchainConfig contains information about rootchain contract addresses +// as well as rootchain admin account address +type RootchainConfig struct { + StateSenderAddress types.Address `json:"stateSenderAddress"` + CheckpointManagerAddress types.Address `json:"checkpointManagerAddress"` + BLSAddress types.Address `json:"blsAddress"` + BN256G2Address types.Address `json:"bn256G2Address"` + ExitHelperAddress types.Address `json:"exitHelperAddress"` + AdminAddress types.Address `json:"adminAddress"` +} + +// ToBridgeConfig creates BridgeConfig instance +func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { + return &BridgeConfig{ + BridgeAddr: r.StateSenderAddress, + CheckpointAddr: r.CheckpointManagerAddress, + AdminAddress: r.AdminAddress, + } +} + +// Manifest holds metadata, such as genesis validators and rootchain configuration +type Manifest struct { + GenesisValidators []*Validator `json:"validators"` + RootchainConfig *RootchainConfig `json:"rootchain"` +} + +// LoadManifest deserializes Manifest instance +func LoadManifest(metadataFile string) (*Manifest, error) { + data, err := os.ReadFile(metadataFile) + if err != nil { + return nil, err + } + + var manifest Manifest + + if err := json.Unmarshal(data, &manifest); err != nil { + return nil, err + } + + return &manifest, nil +} + +// Save marshals RootchainManifest instance to json and persists it to given location +func (m *Manifest) Save(manifestPath string) error { + data, err := json.MarshalIndent(m, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal rootchain manifest to JSON: %w", err) + } + + if err := os.WriteFile(filepath.Clean(manifestPath), data, os.ModePerm); err != nil { + return fmt.Errorf("failed to save rootchain manifest file: %w", err) + } + + return nil } diff --git a/consensus/polybft/polybft_test.go b/consensus/polybft/polybft_test.go index 766f7e7a0c..6096f916f2 100644 --- a/consensus/polybft/polybft_test.go +++ b/consensus/polybft/polybft_test.go @@ -24,10 +24,7 @@ import ( func TestPolybft_VerifyHeader(t *testing.T) { t.Parallel() - const ( - allValidatorsSize = 6 // overall there are 6 validators - validatorSetSize = 5 // only 5 validators are active at the time - ) + const validatorSetSize = 6 // overall there are 6 validators updateHeaderExtra := func(header *types.Header, validators *ValidatorSetDelta, @@ -61,14 +58,13 @@ func TestPolybft_VerifyHeader(t *testing.T) { } // create all valdators - validators := newTestValidators(allValidatorsSize) + validators := newTestValidators(validatorSetSize) // create configuration polyBftConfig := PolyBFTConfig{ InitialValidatorSet: validators.getParamValidators(), EpochSize: 10, SprintSize: 5, - ValidatorSetSize: validatorSetSize, } validatorSet := validators.getPublicIdentities() diff --git a/e2e-polybft/README.md b/e2e-polybft/README.md index 17822a2a0f..a74ceefa23 100644 --- a/e2e-polybft/README.md +++ b/e2e-polybft/README.md @@ -1,7 +1,7 @@ # End-to-End testing -The implemented E2E tests start a local instance of V3. +The implemented E2E tests start a local instance of Polybft consensus protocol. As such, they require the binary 'polygon-edge' to be available in the $PATH variable. diff --git a/e2e-polybft/bridge_test.go b/e2e-polybft/bridge_test.go index e8b442cde6..78e0e8a2a4 100644 --- a/e2e-polybft/bridge_test.go +++ b/e2e-polybft/bridge_test.go @@ -7,14 +7,15 @@ import ( "io" "math/big" "net/http" + "path" "strings" "testing" "time" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" rootchainHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/contracts" @@ -44,6 +45,8 @@ type ResultEventStatus uint8 const ( ResultEventSuccess ResultEventStatus = iota ResultEventFailure + + manifestFileName = "manifest.json" ) // checkLogs is helper function which parses given ResultEvent event's logs, @@ -181,11 +184,6 @@ func TestE2E_Bridge_MainWorkflow(t *testing.T) { } func TestE2E_CheckpointSubmission(t *testing.T) { - var ( - rootchainSender = rootchainHelper.GetRootchainAdminKey().Address() - checkpointManagerAddr = ethgo.Address(rootchainHelper.CheckpointManagerAddress) - ) - // spin up a cluster with epoch size set to 5 blocks cluster := framework.NewTestCluster(t, 5, framework.WithBridge(), framework.WithEpochSize(5)) defer cluster.Stop() @@ -197,6 +195,12 @@ func TestE2E_CheckpointSubmission(t *testing.T) { checkpointBlockNumInput, err := currentCheckpointBlockNumMethod.Encode([]interface{}{}) require.NoError(t, err) + manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + require.NoError(t, err) + + checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) + rootchainSender := ethgo.Address(manifest.RootchainConfig.AdminAddress) + testCheckpointBlockNumber := func(expectedCheckpointBlock int64) (bool, error) { checkpointBlockNumRaw, err := rootchainTxRelayer.Call(rootchainSender, checkpointManagerAddr, checkpointBlockNumInput) if err != nil { @@ -239,36 +243,48 @@ func TestE2E_CheckpointSubmission(t *testing.T) { } func TestE2E_Bridge_L2toL1Exit(t *testing.T) { - key, err := ethgow.GenerateKey() + sidechainKey, err := ethgow.GenerateKey() + require.NoError(t, err) + + // initialize rootchain admin key to default one + err = rootchainHelper.InitRootchainAdminKey("") require.NoError(t, err) cluster := framework.NewTestCluster(t, 5, framework.WithBridge(), - framework.WithPremine(types.Address(key.Address())), + framework.WithPremine(types.Address(sidechainKey.Address())), ) defer cluster.Stop() + manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + require.NoError(t, err) + + checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) + exitHelperAddr := ethgo.Address(manifest.RootchainConfig.ExitHelperAddress) + adminAddr := ethgo.Address(manifest.RootchainConfig.AdminAddress) + // wait for a couple of blocks require.NoError(t, cluster.WaitForBlock(2, 2*time.Minute)) - //init rpc clients - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(txrelayer.DefaultRPCAddress)) + // init rpc clients + l1TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(txrelayer.DefaultRPCAddress)) require.NoError(t, err) - l2Relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + l2TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) require.NoError(t, err) - //deploy l1,l2, ExitHelper contracts - receipt, err := DeployTransaction(txRelayer, rootchainHelper.GetRootchainAdminKey(), contractsapi.L1ExitTestBytecode) + // deploy L1ExitTest contract + receipt, err := l1TxRelayer.SendTransaction(ðgo.Transaction{Input: contractsapi.L1ExitTestBytecode}, + rootchainHelper.GetRootchainAdminKey()) require.NoError(t, err) + require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) - l1ContractAddress := receipt.ContractAddress + l1ExitTestAddr := receipt.ContractAddress l2StateSenderAddress := ethgo.Address(contracts.L2StateSenderContract) - checkpointManagerAddress := ethgo.Address(rootchainHelper.CheckpointManagerAddress) - //Start test - //send crosschain transaction on l2 and get exit id + // Start test + // send crosschain transaction on l2 and get exit id stateSenderData := []byte{123} - receipt, err = ABITransaction(l2Relayer, key, contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ContractAddress, stateSenderData) + receipt, err = ABITransaction(l2TxRelayer, sidechainKey, contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ExitTestAddr, stateSenderData) require.NoError(t, err) require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) l2SenderBlock := receipt.BlockNumber @@ -284,15 +300,15 @@ func TestE2E_Bridge_L2toL1Exit(t *testing.T) { extra, err := polybft.GetIbftExtra(l2SenderBlockData.ExtraData) require.NoError(t, err) - receipt, err = ABITransaction(l2Relayer, key, contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ContractAddress, stateSenderData) + receipt, err = ABITransaction(l2TxRelayer, sidechainKey, contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ExitTestAddr, stateSenderData) require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) require.NoError(t, err) - //wait when a new checkpoint will be accepted + // wait when a new checkpoint will be accepted fail := 0 for range time.Tick(time.Second) { - currentEpochString, err := ABICall(txRelayer, contractsapi.CheckpointManager, checkpointManagerAddress, "currentEpoch") + currentEpochString, err := ABICall(l1TxRelayer, contractsapi.CheckpointManager, checkpointManagerAddr, adminAddr, "currentEpoch") require.NoError(t, err) currentEpoch, err := types.ParseUint64orHex(¤tEpochString) @@ -313,13 +329,13 @@ func TestE2E_Bridge_L2toL1Exit(t *testing.T) { proofExitEventEncoded, err := polybft.ExitEventABIType.Encode(&polybft.ExitEvent{ ID: 1, - Sender: key.Address(), - Receiver: l1ContractAddress, + Sender: sidechainKey.Address(), + Receiver: l1ExitTestAddr, Data: stateSenderData, }) require.NoError(t, err) - _, err = ABITransaction(txRelayer, rootchainHelper.GetRootchainAdminKey(), contractsapi.ExitHelper, rootchainHelper.ExitHelperAddress, + receipt, err = ABITransaction(l1TxRelayer, rootchainHelper.GetRootchainAdminKey(), contractsapi.ExitHelper, exitHelperAddr, "exit", big.NewInt(int64(extra.Checkpoint.EpochNumber*10)), proof.LeafIndex, @@ -327,8 +343,9 @@ func TestE2E_Bridge_L2toL1Exit(t *testing.T) { proof.Proof, ) require.NoError(t, err) + require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) - res, err := ABICall(txRelayer, contractsapi.ExitHelper, rootchainHelper.ExitHelperAddress, "processedExits", big.NewInt(1)) + res, err := ABICall(l1TxRelayer, contractsapi.ExitHelper, exitHelperAddr, adminAddr, "processedExits", big.NewInt(1)) require.NoError(t, err) parserRes, err := types.ParseUint64orHex(&res) require.NoError(t, err) @@ -375,14 +392,15 @@ func getExitProof(rpcAddress string, exitID, epoch, checkpointBlock uint64) (typ return rspProof.Result, nil } -func ABICall(relayer txrelayer.TxRelayer, artifact *artifact.Artifact, contractAddress ethgo.Address, method string, params ...interface{}) (string, error) { +func ABICall(relayer txrelayer.TxRelayer, artifact *artifact.Artifact, contractAddress ethgo.Address, senderAddr ethgo.Address, method string, params ...interface{}) (string, error) { input, err := artifact.Abi.GetMethod(method).Encode(params) if err != nil { return "", err } - return relayer.Call(ethgo.Address(rootchainHelper.GetRootchainAdminAddr()), contractAddress, input) + return relayer.Call(senderAddr, contractAddress, input) } + func ABITransaction(relayer txrelayer.TxRelayer, key ethgo.Key, artifact *artifact.Artifact, contractAddress ethgo.Address, method string, params ...interface{}) (*ethgo.Receipt, error) { input, err := artifact.Abi.GetMethod(method).Encode(params) if err != nil { @@ -394,9 +412,3 @@ func ABITransaction(relayer txrelayer.TxRelayer, key ethgo.Key, artifact *artifa Input: input, }, key) } - -func DeployTransaction(relayer txrelayer.TxRelayer, key ethgo.Key, bytecode []byte) (*ethgo.Receipt, error) { - return relayer.SendTransaction(ðgo.Transaction{ - Input: bytecode, - }, key) -} diff --git a/e2e-polybft/framework/test-bridge.go b/e2e-polybft/framework/test-bridge.go index 98408fdea3..2ce89a0325 100644 --- a/e2e-polybft/framework/test-bridge.go +++ b/e2e-polybft/framework/test-bridge.go @@ -60,14 +60,12 @@ func (t *TestBridge) Start() error { return nil } -func (t *TestBridge) deployRootchainContracts(genesisPath string) error { +func (t *TestBridge) deployRootchainContracts(manifestPath string) error { args := []string{ "rootchain", "init-contracts", "--path", t.clusterConfig.ContractsDir, - "--validator-path", t.clusterConfig.TmpDir, - "--validator-prefix", t.clusterConfig.ValidatorPrefix, - "--genesis-path", genesisPath, + "--manifest", manifestPath, } err := runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("bridge")) diff --git a/e2e-polybft/framework/test-cluster.go b/e2e-polybft/framework/test-cluster.go index 248ecdf779..ad91004a84 100644 --- a/e2e-polybft/framework/test-cluster.go +++ b/e2e-polybft/framework/test-cluster.go @@ -228,6 +228,13 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T require.NoError(t, err) } + manifestPath := path.Join(tmpDir, "manifest.json") + // run manifest file creation + cluster.cmdRun("manifest", + "--path", manifestPath, + "--validators-path", tmpDir, + "--validators-prefix", cluster.Config.ValidatorPrefix) + if cluster.Config.HasBridge { // start bridge cluster.Bridge, err = NewTestBridge(t, cluster.Config) @@ -239,13 +246,21 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T cluster.Config.ValidatorSetSize = uint64(validatorsCount) } - genesisPath := path.Join(tmpDir, "genesis.json") + if cluster.Config.HasBridge { + err := cluster.Bridge.deployRootchainContracts(manifestPath) + require.NoError(t, err) + + err = cluster.Bridge.fundValidators() + require.NoError(t, err) + } + { // run genesis configuration population args := []string{ "genesis", + "--manifest", manifestPath, "--consensus", "polybft", - "--dir", genesisPath, + "--dir", path.Join(tmpDir, "genesis.json"), "--contracts-path", defaultContractsPath, "--epoch-size", strconv.Itoa(cluster.Config.EpochSize), "--premine", "0x0000000000000000000000000000000000000000", @@ -293,14 +308,6 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T require.NoError(t, err) } - if cluster.Config.HasBridge { - err := cluster.Bridge.deployRootchainContracts(genesisPath) - require.NoError(t, err) - - err = cluster.Bridge.fundValidators() - require.NoError(t, err) - } - for i := 1; i <= int(cluster.Config.ValidatorSetSize); i++ { cluster.initTestServer(t, i, true) } @@ -375,6 +382,7 @@ func (c *TestCluster) EmitTransfer(contractAddress, walletAddresses, amounts str return c.cmdRun("rootchain", "emit", + "--manifest", path.Join(c.Config.TmpDir, "manifest.json"), "--contract", contractAddress, "--wallets", walletAddresses, "--amounts", amounts) diff --git a/scripts/cluster b/scripts/cluster index 2cc04c8b08..e941a84996 100755 --- a/scripts/cluster +++ b/scripts/cluster @@ -5,6 +5,7 @@ set -e # Reset test-dirs rm -rf test-chain-* rm -f genesis.json +rm -f manifest.json go build -o polygon-edge . @@ -18,6 +19,7 @@ else echo "Running with polybft consensus" genesis_params="--consensus polybft --validator-set-size=4 --bridge-json-rpc http://127.0.0.1:8545" ./polygon-edge polybft-secrets --data-dir test-chain- --num 4 + ./polygon-edge manifest fi ./polygon-edge genesis $genesis_params \