From e37c748f0afc36d2df75533afeae96dcbf09d31d Mon Sep 17 00:00:00 2001 From: Goran Rojovic <100121253+goran-ethernal@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:13:47 +0200 Subject: [PATCH] Change child predicates deployment (#372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial fix * lint fix * fixes * comments fix * Remove unused parameters * Make IncrementBy method of Address. Reorganize functions to be grouped by structs * Introduce slice of internal bridge contract addresses * Adjust comments * Minor simplifications (return callContract) * Fixes in iterating through bridge config map, renames * Add comments * Use the proper field to set the internal rpc url * Rename * Changes in return value in deployContracts * Fix internal tx relayer initialization * Promote getProxyNameForImpl to method * Minor simplifications * Remove unused param * Lint fix * comments fix --------- Co-authored-by: Stefan Negovanović --- chain/params.go | 47 ++ command/bridge/deploy/deploy.go | 593 ++++-------------- command/bridge/deploy/deploy_test.go | 16 +- command/bridge/deploy/external_contracts.go | 332 ++++++++++ command/bridge/deploy/internal_contracts.go | 365 +++++++++++ command/bridge/deploy/params.go | 7 +- command/bridge/deploy/result.go | 9 +- command/bridge/deploy/types.go | 115 ++++ .../withdraw/erc1155/withdraw_erc1155.go | 2 +- .../bridge/withdraw/erc20/withdraw_erc20.go | 2 +- .../bridge/withdraw/erc721/withdraw_erc721.go | 2 +- command/genesis/polybft_params.go | 44 -- consensus/polybft/bridge_batch_test.go | 4 - consensus/polybft/bridge_event_manager.go | 14 +- consensus/polybft/bridge_manager.go | 6 +- consensus/polybft/contracts_initializer.go | 308 +++++++-- consensus/polybft/contractsapi/helper.go | 10 + consensus/polybft/fsm.go | 2 +- consensus/polybft/fsm_test.go | 10 +- consensus/polybft/helpers_test.go | 18 +- consensus/polybft/polybft.go | 179 ++---- consensus/polybft/polybft_config.go | 105 ++-- consensus/polybft/polybft_config_test.go | 48 ++ consensus/polybft/sc_integration_test.go | 20 - .../state_store_bridge_message_test.go | 11 - .../polybft/state_store_governance_test.go | 26 +- consensus/polybft/state_sync_relayer.go | 12 +- .../polybft/validator/validator_metadata.go | 6 +- consensus/polybft/validator/validator_set.go | 4 +- .../polybft/validator/validator_set_test.go | 2 +- contracts/system_addresses.go | 105 ++-- e2e-polybft/e2e/bridge_test.go | 86 +-- e2e-polybft/e2e/helpers_test.go | 17 - e2e-polybft/framework/test-bridge.go | 4 +- types/types.go | 103 +-- types/types_test.go | 110 ++++ 36 files changed, 1766 insertions(+), 978 deletions(-) create mode 100644 command/bridge/deploy/external_contracts.go create mode 100644 command/bridge/deploy/internal_contracts.go create mode 100644 command/bridge/deploy/types.go create mode 100644 consensus/polybft/polybft_config_test.go diff --git a/chain/params.go b/chain/params.go index 63fc19a45f..93f5d2b1d6 100644 --- a/chain/params.go +++ b/chain/params.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" + "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/forkmanager" "github.com/0xPolygon/polygon-edge/types" ) @@ -81,6 +82,52 @@ func (p *Params) GetEngine() string { return "" } +// GetBridgeAllowListAdmin returns admin account for the bridge allow list (first of them in the list) +func (p *Params) GetBridgeAllowListAdmin() types.Address { + if p.BridgeAllowList == nil || len(p.BridgeAllowList.AdminAddresses) == 0 { + return types.ZeroAddress + } + + return p.BridgeAllowList.AdminAddresses[0] +} + +// GetBridgeBlockListAdmin returns admin account for the bridge block list (first of them in the list) +func (p *Params) GetBridgeBlockListAdmin() types.Address { + if p.BridgeBlockList == nil || len(p.BridgeBlockList.AdminAddresses) == 0 { + return types.ZeroAddress + } + + return p.BridgeBlockList.AdminAddresses[0] +} + +// GetBridgeOwner returns owner account for bridge. +// +// It is resolved by the given priorities: +// 1. in case bridge allow list admin is configured, return it as an owner +// 2. in case bridge block list admin is configured, return it as an owner +// 3. otherwise return predefined SystemCaller address +func (p *Params) GetBridgeOwner() types.Address { + if owner := p.GetBridgeAllowListAdmin(); owner != types.ZeroAddress { + return owner + } + + if owner := p.GetBridgeBlockListAdmin(); owner != types.ZeroAddress { + return owner + } + + return contracts.SystemCaller +} + +// IsBridgeAllowListEnabled returns true in case bridge allow list is configured, otherwise false. +func (p *Params) IsBridgeAllowListEnabled() bool { + return p.GetBridgeAllowListAdmin() != types.ZeroAddress +} + +// IsBridgeBlockListEnabled returns true in case bridge block list is configured, otherwise false. +func (p *Params) IsBridgeBlockListEnabled() bool { + return p.GetBridgeBlockListAdmin() != types.ZeroAddress +} + // predefined forks const ( Homestead = "homestead" diff --git a/command/bridge/deploy/deploy.go b/command/bridge/deploy/deploy.go index 513a1c7e45..1928dab343 100644 --- a/command/bridge/deploy/deploy.go +++ b/command/bridge/deploy/deploy.go @@ -18,241 +18,21 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" ) -const ( - contractsDeploymentTitle = "[BRIDGE - CONTRACTS DEPLOYMENT]" - ProxySufix = "Proxy" - - gatewayName = "Gateway" - blsName = "BLS" - bn256G2Name = "BN256G2" - rootERC20PredicateName = "RootERC20Predicate" - childERC20MintablePredicateName = "ChildERC20MintablePredicate" - rootERC20Name = "RootERC20" - erc20TemplateName = "ERC20Template" - rootERC721PredicateName = "RootERC721Predicate" - childERC721MintablePredicateName = "ChildERC721MintablePredicate" - erc721TemplateName = "ERC721Template" - rootERC1155PredicateName = "RootERC1155Predicate" - childERC1155MintablePredicateName = "ChildERC1155MintablePredicate" - erc1155TemplateName = "ERC1155Template" - bladeManagerName = "BladeManager" -) - var ( // params are the parameters of CLI command params deployParams // consensusCfg contains consensus protocol configuration parameters consensusCfg polybft.PolyBFTConfig - - // metadataPopulatorMap maps rootchain contract names to callback - // which populates appropriate field in the RootchainMetadata - metadataPopulatorMap = map[string]func(*polybft.RootchainConfig, types.Address){ - getProxyNameForImpl(bladeManagerName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.BladeManagerAddress = addr - }, - getProxyNameForImpl(blsName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.BLSAddress = addr - }, - getProxyNameForImpl(bn256G2Name): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.BN256G2Address = addr - }, - getProxyNameForImpl(gatewayName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.Gateway = addr - }, - getProxyNameForImpl(rootERC20PredicateName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootERC20PredicateAddress = addr - }, - getProxyNameForImpl(childERC20MintablePredicateName): func( - rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC20PredicateAddress = addr - }, - rootERC20Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootNativeERC20Address = addr - }, - erc20TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC20Address = addr - }, - getProxyNameForImpl(rootERC721PredicateName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootERC721PredicateAddress = addr - }, - getProxyNameForImpl(childERC721MintablePredicateName): func( - rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC721PredicateAddress = addr - }, - erc721TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC721Address = addr - }, - getProxyNameForImpl(rootERC1155PredicateName): func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootERC1155PredicateAddress = addr - }, - getProxyNameForImpl(childERC1155MintablePredicateName): func( - rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC1155PredicateAddress = addr - }, - erc1155TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ChildERC1155Address = addr - }, - } - - // initializersMap maps rootchain contract names to initializer function callbacks - initializersMap = map[string]func(command.OutputFormatter, txrelayer.TxRelayer, - []*validator.GenesisValidator, - *polybft.RootchainConfig, crypto.Key, int64) error{ - getProxyNameForImpl(rootERC20PredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - inputParams := &contractsapi.InitializeRootERC20PredicateFn{ - NewGateway: config.Gateway, - NewChildERC20Predicate: contracts.ChildERC20PredicateContract, - NewDestinationTokenTemplate: contracts.ChildERC20Contract, - // root native token address should be non-zero only if native token is non-mintable on a childchain - NewNativeTokenRoot: config.RootNativeERC20Address, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, inputParams, - config.RootERC20PredicateAddress, rootERC20PredicateName, key) - }, - getProxyNameForImpl(childERC20MintablePredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - initParams := &contractsapi.InitializeChildERC20PredicateFn{ - NewGateway: config.Gateway, - NewRootERC20Predicate: contracts.RootERC20PredicateContract, - NewDestinationTokenTemplate: config.ChildERC20Address, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, initParams, - config.ChildERC20PredicateAddress, childERC20MintablePredicateName, key) - }, - getProxyNameForImpl(rootERC721PredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - initParams := &contractsapi.InitializeRootERC721PredicateFn{ - NewGateway: config.Gateway, - NewChildERC721Predicate: contracts.ChildERC721PredicateContract, - NewDestinationTokenTemplate: contracts.ChildERC721Contract, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, initParams, - config.RootERC721PredicateAddress, rootERC721PredicateName, key) - }, - getProxyNameForImpl(childERC721MintablePredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - initParams := &contractsapi.InitializeChildERC721PredicateFn{ - NewGateway: config.Gateway, - NewRootERC721Predicate: contracts.RootERC721PredicateContract, - NewDestinationTokenTemplate: config.ChildERC721Address, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, initParams, - config.ChildERC721PredicateAddress, childERC721MintablePredicateName, key) - }, - getProxyNameForImpl(rootERC1155PredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - initParams := &contractsapi.InitializeRootERC1155PredicateFn{ - NewGateway: config.Gateway, - NewChildERC1155Predicate: contracts.ChildERC1155PredicateContract, - NewDestinationTokenTemplate: contracts.ChildERC1155Contract, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, initParams, - config.RootERC1155PredicateAddress, rootERC1155PredicateName, key) - }, - getProxyNameForImpl(childERC1155MintablePredicateName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - initParams := &contractsapi.InitializeChildERC1155PredicateFn{ - NewGateway: config.Gateway, - NewRootERC1155Predicate: contracts.RootERC1155PredicateContract, - NewDestinationTokenTemplate: config.ChildERC1155Address, - NewDestinationChainID: big.NewInt(chainID), - } - - return initContract(fmt, relayer, initParams, - config.ChildERC1155PredicateAddress, childERC1155MintablePredicateName, key) - }, - getProxyNameForImpl(bladeManagerName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - gvs := make([]*contractsapi.GenesisAccount, len(genesisValidators)) - for i := 0; i < len(genesisValidators); i++ { - gvs[i] = &contractsapi.GenesisAccount{ - Addr: genesisValidators[i].Address, - IsValidator: true, - // this is set on purpose to 0, each account must premine enough tokens to itself if token is non-mintable - StakedTokens: big.NewInt(0), - PreminedTokens: big.NewInt(0), - } - } - - initParams := &contractsapi.InitializeBladeManagerFn{ - NewRootERC20Predicate: config.RootERC20PredicateAddress, - GenesisAccounts: gvs, - } - - return initContract(fmt, relayer, initParams, - config.BladeManagerAddress, bladeManagerName, key) - }, - getProxyNameForImpl(gatewayName): func(fmt command.OutputFormatter, - relayer txrelayer.TxRelayer, - genesisValidators []*validator.GenesisValidator, - config *polybft.RootchainConfig, - key crypto.Key, - chainID int64) error { - validatorSet, err := getValidatorSet(fmt, genesisValidators) - if err != nil { - return err - } - - inputParams := &contractsapi.InitializeGatewayFn{ - NewBls: config.BLSAddress, - NewBn256G2: config.BN256G2Address, - Validators: validatorSet, - } - - return initContract(fmt, relayer, inputParams, config.Gateway, - gatewayName, key) - }, - } ) type deploymentResultInfo struct { - RootchainCfg *polybft.RootchainConfig + BridgeCfg *polybft.BridgeConfig CommandResults []command.CommandResult } @@ -260,7 +40,7 @@ type deploymentResultInfo struct { func GetCommand() *cobra.Command { cmd := &cobra.Command{ Use: "deploy", - Short: "Deploys and initializes required smart contracts on the rootchain", + Short: "Deploys and initializes set of bridge smart contracts", PreRunE: preRunCommand, Run: runCommand, } @@ -276,28 +56,35 @@ func GetCommand() *cobra.Command { ¶ms.deployerKey, deployerKeyFlag, "", - "hex-encoded private key of the account which deploys rootchain contracts", + "hex-encoded private key of the account which deploys bridge contracts", ) cmd.Flags().StringVar( - ¶ms.jsonRPCAddress, - jsonRPCFlag, + ¶ms.externalRPCAddress, + externalRPCFlag, txrelayer.DefaultRPCAddress, - "the JSON RPC rootchain IP address", + "the JSON RPC external chain IP address", + ) + + cmd.Flags().StringVar( + ¶ms.internalRPCAddress, + internalRPCFlag, + txrelayer.DefaultRPCAddress, + "the JSON RPC blade chain IP address", ) cmd.Flags().StringVar( ¶ms.rootERC20TokenAddr, erc20AddrFlag, "", - "existing root native erc20 token address, that originates from a rootchain", + "existing erc20 token address, that originates from a rootchain and that gets mapped to the Blade native one", ) cmd.Flags().BoolVar( ¶ms.isTestMode, helper.TestModeFlag, false, - "test indicates whether rootchain contracts deployer is hardcoded test account"+ + "test indicates whether bridge contracts deployer is hardcoded test account"+ " (otherwise provided secrets are used to resolve deployer account)", ) @@ -315,6 +102,15 @@ func GetCommand() *cobra.Command { cmdHelper.TxTimeoutDesc, ) + cmd.Flags().BoolVar( + ¶ms.isBootstrap, + isBootstrapFlag, + true, + "indicates if bridge deploy command is run during bootstraping of the Blade chain. "+ + "If it is run on a live Blade chain, the command will deploy and initialize internal predicates, "+ + "otherwise it will pre-allocate the internal predicates addresses in the genesis configuration.", + ) + cmd.MarkFlagsMutuallyExclusive(helper.TestModeFlag, deployerKeyFlag) return cmd @@ -329,7 +125,8 @@ func runCommand(cmd *cobra.Command, _ []string) { defer outputter.WriteOutput() outputter.WriteCommandResult(&helper.MessageResult{ - Message: fmt.Sprintf("%s started... Rootchain JSON RPC address %s.", contractsDeploymentTitle, params.jsonRPCAddress), + Message: fmt.Sprintf("%s started... External chain JSON RPC address %s.", + contractsDeploymentTitle, params.externalRPCAddress), }) chainConfig, err := chain.ImportFromFile(params.genesisPath) @@ -339,23 +136,27 @@ func runCommand(cmd *cobra.Command, _ []string) { return } - client, err := jsonrpc.NewEthClient(params.jsonRPCAddress) + externalChainClient, err := jsonrpc.NewEthClient(params.externalRPCAddress) if err != nil { outputter.SetError(fmt.Errorf("failed to initialize JSON RPC client for provided IP address: %s: %w", - params.jsonRPCAddress, err)) + params.externalRPCAddress, err)) return } - chainID, err := client.ChainID() + externalChainIDBig, err := externalChainClient.ChainID() if err != nil { - outputter.SetError(fmt.Errorf("failed to get chainID for provided IP address: %s: %w", params.jsonRPCAddress, err)) + outputter.SetError(fmt.Errorf("failed to get chainID for provided IP address: %s: %w", + params.externalRPCAddress, err)) } - if consensusCfg.Bridge[chainID.Uint64()] != nil { - code, err := client.GetCode(consensusCfg.Bridge[chainID.Uint64()].GatewayAddr, jsonrpc.LatestBlockNumberOrHash) + externalChainID := externalChainIDBig.Uint64() + bridgeCfg := consensusCfg.Bridge[externalChainID] + + if bridgeCfg != nil { + code, err := externalChainClient.GetCode(bridgeCfg.ExternalGatewayAddr, jsonrpc.LatestBlockNumberOrHash) if err != nil { - outputter.SetError(fmt.Errorf("failed to check if rootchain contracts are deployed: %w", err)) + outputter.SetError(fmt.Errorf("failed to check if external chain bridge contracts are deployed: %w", err)) return } else if code != "0x" { @@ -367,30 +168,29 @@ func runCommand(cmd *cobra.Command, _ []string) { } } - // set event tracker start blocks for rootchain contract(s) of interest - // the block number should be queried before deploying contracts so that no events during deployment - // and initialization are missed - blockNum, err := client.BlockNumber() + deploymentResultInfo, err := deployContracts(outputter, externalChainClient, externalChainIDBig, + chainConfig, consensusCfg.InitialValidatorSet, cmd.Context()) if err != nil { - outputter.SetError(fmt.Errorf("failed to query rootchain latest block number: %w", err)) + outputter.SetError(fmt.Errorf("failed to deploy bridge contracts: %w", err)) + outputter.SetCommandResult(command.Results(deploymentResultInfo.CommandResults)) return } - deploymentResultInfo, err := deployContracts(outputter, client, - chainConfig.Params.ChainID, consensusCfg.InitialValidatorSet, cmd.Context()) + // set event tracker start blocks for external chain contract(s) of interest + // the block number should be queried before deploying contracts so that no events during deployment + // and initialization are missed + latestBlockNum, err := externalChainClient.BlockNumber() if err != nil { - outputter.SetError(fmt.Errorf("failed to deploy rootchain contracts: %w", err)) - outputter.SetCommandResult(command.Results(deploymentResultInfo.CommandResults)) + outputter.SetError(fmt.Errorf("failed to query the external chain's latest block number: %w", err)) return } // populate bridge configuration - consensusCfg.Bridge[chainID.Uint64()] = deploymentResultInfo.RootchainCfg.ToBridgeConfig() - - consensusCfg.Bridge[chainID.Uint64()].EventTrackerStartBlocks = map[types.Address]uint64{ - deploymentResultInfo.RootchainCfg.Gateway: blockNum, + consensusCfg.Bridge[externalChainID] = deploymentResultInfo.BridgeCfg + consensusCfg.Bridge[externalChainID].EventTrackerStartBlocks = map[types.Address]uint64{ + deploymentResultInfo.BridgeCfg.ExternalGatewayAddr: latestBlockNum, } // write updated consensus configuration @@ -409,187 +209,72 @@ func runCommand(cmd *cobra.Command, _ []string) { outputter.SetCommandResult(command.Results(deploymentResultInfo.CommandResults)) } -// deployContracts deploys and initializes rootchain smart contracts -func deployContracts(outputter command.OutputFormatter, client *jsonrpc.EthClient, chainID int64, - initialValidators []*validator.GenesisValidator, cmdCtx context.Context) (deploymentResultInfo, error) { - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(client), txrelayer.WithWriter(outputter), +// deployContracts deploys and initializes bridge smart contracts +func deployContracts( + outputter command.OutputFormatter, + externalChainClient *jsonrpc.EthClient, + externalChainID *big.Int, + chainCfg *chain.Chain, + initialValidators []*validator.GenesisValidator, + cmdCtx context.Context) (*deploymentResultInfo, error) { + externalTxRelayer, err := txrelayer.NewTxRelayer( + txrelayer.WithClient(externalChainClient), + txrelayer.WithWriter(outputter), txrelayer.WithReceiptsTimeout(params.txTimeout)) - if err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, - fmt.Errorf("failed to initialize tx relayer: %w", err) + return nil, fmt.Errorf("failed to initialize tx relayer for external chain: %w", err) } deployerKey, err := helper.DecodePrivateKey(params.deployerKey) if err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, - fmt.Errorf("failed to initialize deployer key: %w", err) + return nil, fmt.Errorf("failed to initialize deployer key: %w", err) } if params.isTestMode { deployerAddr := deployerKey.Address() txn := helper.CreateTransaction(types.ZeroAddress, &deployerAddr, nil, ethgo.Ether(1), true) - if _, err = txRelayer.SendTransactionLocal(txn); err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, err + if _, err = externalTxRelayer.SendTransactionLocal(txn); err != nil { + return nil, err } } - type contractInfo struct { - name string - artifact *contracts.Artifact - hasProxy bool - byteCodeBuilder func() ([]byte, error) - } - - rootchainConfig := &polybft.RootchainConfig{JSONRPCAddr: params.jsonRPCAddress} - - tokenContracts := []*contractInfo{} + var ( + internalChainID = chainCfg.Params.ChainID + bridgeConfig = &polybft.BridgeConfig{JSONRPCEndpoint: params.externalRPCAddress} + externalContracts []*contract + internalContracts []*contract + ) - // deploy root ERC20 token only if non-mintable native token flavor is used on a child chain - if !consensusCfg.NativeTokenConfig.IsMintable { - if params.rootERC20TokenAddr != "" { - // use existing root chain ERC20 token - if err := populateExistingTokenAddr(client, - params.rootERC20TokenAddr, rootERC20Name, rootchainConfig); err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, err - } - } else { - // deploy MockERC20 as a root chain root native token - tokenContracts = append(tokenContracts, - &contractInfo{name: rootERC20Name, artifact: contractsapi.RootERC20}) - } + // setup external contracts + if externalContracts, err = initExternalContracts(bridgeConfig, externalChainClient, externalChainID); err != nil { + return nil, err } - allContracts := []*contractInfo{ - { - name: gatewayName, - artifact: contractsapi.Gateway, - hasProxy: true, - }, - { - name: blsName, - artifact: contractsapi.BLS, - hasProxy: true, - }, - { - name: bn256G2Name, - artifact: contractsapi.BLS256, - hasProxy: true, - }, - { - name: rootERC20PredicateName, - artifact: contractsapi.RootERC20Predicate, - hasProxy: true, - }, - { - name: childERC20MintablePredicateName, - artifact: contractsapi.ChildERC20Predicate, - hasProxy: true, - }, - { - name: erc20TemplateName, - artifact: contractsapi.ChildERC20, - }, - { - name: rootERC721PredicateName, - artifact: contractsapi.RootERC721Predicate, - hasProxy: true, - }, - { - name: childERC721MintablePredicateName, - artifact: contractsapi.ChildERC721Predicate, - hasProxy: true, - }, - { - name: erc721TemplateName, - artifact: contractsapi.ChildERC721, - }, - { - name: rootERC1155PredicateName, - artifact: contractsapi.RootERC1155Predicate, - hasProxy: true, - }, - { - name: childERC1155MintablePredicateName, - artifact: contractsapi.ChildERC1155Predicate, - hasProxy: true, - }, - { - name: erc1155TemplateName, - artifact: contractsapi.ChildERC1155, - }, - } + // setup internal contracts + internalContracts = initInternalContracts(chainCfg) - if !consensusCfg.NativeTokenConfig.IsMintable { - // if token is non-mintable we will deploy BladeManager - // if not, we don't need it - allContracts = append(allContracts, &contractInfo{ - name: bladeManagerName, - artifact: contractsapi.BladeManager, - hasProxy: true, - }) + // pre-allocate internal predicates addresses in genesis if blade is bootstrapping + if params.isBootstrap { + if err := preAllocateInternalPredicates(outputter, internalContracts, chainCfg, bridgeConfig); err != nil { + return nil, err + } } - allContracts = append(tokenContracts, allContracts...) - g, ctx := errgroup.WithContext(cmdCtx) - results := make(map[string]*deployContractResult, len(allContracts)) + results := make(map[string]*deployContractResult) resultsLock := sync.Mutex{} proxyAdmin := types.StringToAddress(params.proxyContractsAdmin) - for _, contract := range allContracts { - contract := contract - + deployContractFn := func(contract *contract, txr txrelayer.TxRelayer) { g.Go(func() error { select { case <-ctx.Done(): return ctx.Err() default: - bytecode := contract.artifact.Bytecode - if contract.byteCodeBuilder != nil { - bytecode, err = contract.byteCodeBuilder() - if err != nil { - return err - } - } - - txn := helper.CreateTransaction(types.ZeroAddress, nil, bytecode, nil, true) - - receipt, err := txRelayer.SendTransaction(txn, deployerKey) + deployResults, err := contract.deploy(bridgeConfig, txr, deployerKey, proxyAdmin) if err != nil { - return fmt.Errorf("failed sending %s contract deploy transaction: %w", contract.name, err) - } - - if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { - return fmt.Errorf("deployment of %s contract failed", contract.name) - } - - deployResults := make([]*deployContractResult, 0, 2) - implementationAddress := types.Address(receipt.ContractAddress) - - deployResults = append(deployResults, newDeployContractsResult(contract.name, - implementationAddress, - receipt.TransactionHash, - receipt.GasUsed)) - - if contract.hasProxy { - proxyContractName := getProxyNameForImpl(contract.name) - - receipt, err := helper.DeployProxyContract( - txRelayer, deployerKey, proxyContractName, proxyAdmin, implementationAddress) - if err != nil { - return err - } - - if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { - return fmt.Errorf("deployment of %s contract failed", proxyContractName) - } - - deployResults = append(deployResults, newDeployContractsResult(proxyContractName, - types.Address(receipt.ContractAddress), - receipt.TransactionHash, - receipt.GasUsed)) + return err } resultsLock.Lock() @@ -604,73 +289,74 @@ func deployContracts(outputter command.OutputFormatter, client *jsonrpc.EthClien }) } - if err := g.Wait(); err != nil { - return collectResultsOnError(results), err - } - - commandResults := make([]command.CommandResult, 0, len(results)) - - for _, result := range results { - commandResults = append(commandResults, result) - - populatorFn, exists := metadataPopulatorMap[result.Name] - if !exists { - continue - } - - populatorFn(rootchainConfig, result.Address) - } - - g, ctx = errgroup.WithContext(cmdCtx) - - for contractName := range results { - contractName := contractName - - initializer, exists := initializersMap[contractName] - if !exists { - continue + initializeContractFn := func(contract *contract, txr txrelayer.TxRelayer, chainID int64) { + if contract.initializeFn == nil { + // some contracts do not have initialize function + return } g.Go(func() error { select { - case <-cmdCtx.Done(): - return cmdCtx.Err() + case <-ctx.Done(): + return ctx.Err() default: - return initializer(outputter, txRelayer, initialValidators, rootchainConfig, deployerKey, chainID) + return contract.initializeFn(outputter, txr, + initialValidators, bridgeConfig, deployerKey, chainID) + } }) } + // deploy external contracts + for _, contract := range externalContracts { + deployContractFn(contract, externalTxRelayer) + } + + var internalTxRelayer txrelayer.TxRelayer + // deploy internal contracts if blade is already running + if !params.isBootstrap { + internalTxRelayer, err = txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.internalRPCAddress), + txrelayer.WithWriter(outputter), txrelayer.WithReceiptsTimeout(params.txTimeout)) + if err != nil { + return nil, fmt.Errorf("failed to initialize tx relayer for internal chain: %w", err) + } + + for _, contract := range internalContracts { + deployContractFn(contract, internalTxRelayer) + } + } + + // wait for all contracts to be deployed if err := g.Wait(); err != nil { - return deploymentResultInfo{RootchainCfg: nil, CommandResults: nil}, err + return collectResultsOnError(results), err } - return deploymentResultInfo{ - RootchainCfg: rootchainConfig, - CommandResults: commandResults}, nil -} + // initialize contracts only after all of them are deployed + g, ctx = errgroup.WithContext(cmdCtx) -// populateExistingTokenAddr checks whether given token is deployed on the provided address. -// If it is, then its address is set to the rootchain config, otherwise an error is returned -func populateExistingTokenAddr(eth *jsonrpc.EthClient, tokenAddr, tokenName string, - rootchainCfg *polybft.RootchainConfig) error { - addr := types.StringToAddress(tokenAddr) + // initialize external contracts + for _, contract := range externalContracts { + initializeContractFn(contract, externalTxRelayer, internalChainID) + } - code, err := eth.GetCode(addr, jsonrpc.LatestBlockNumberOrHash) - if err != nil { - return fmt.Errorf("failed to check is %s token deployed: %w", tokenName, err) - } else if code == "0x" { - return fmt.Errorf("%s token is not deployed on provided address %s", tokenName, tokenAddr) + // initialize internal contracts if blade is live + if !params.isBootstrap { + for _, contract := range internalContracts { + initializeContractFn(contract, internalTxRelayer, externalChainID.Int64()) + } } - populatorFn, ok := metadataPopulatorMap[tokenName] - if !ok { - return fmt.Errorf("root chain metadata populator not registered for contract '%s'", tokenName) + // wait for all contracts to be initialized + if err := g.Wait(); err != nil { + return nil, err } - populatorFn(rootchainCfg, addr) + commandResults := make([]command.CommandResult, 0, len(results)) + for _, result := range results { + commandResults = append(commandResults, result) + } - return nil + return &deploymentResultInfo{BridgeCfg: bridgeConfig, CommandResults: commandResults}, nil } // initContract initializes arbitrary contract with given parameters deployed on a given address @@ -696,7 +382,7 @@ func initContract(cmdOutput command.OutputFormatter, txRelayer txrelayer.TxRelay return nil } -func collectResultsOnError(results map[string]*deployContractResult) deploymentResultInfo { +func collectResultsOnError(results map[string]*deployContractResult) *deploymentResultInfo { commandResults := make([]command.CommandResult, 0, len(results)+1) messageResult := helper.MessageResult{Message: "[BRIDGE - DEPLOY] Successfully deployed the following contracts\n"} @@ -710,14 +396,7 @@ func collectResultsOnError(results map[string]*deployContractResult) deploymentR commandResults = append([]command.CommandResult{messageResult}, commandResults...) - return deploymentResultInfo{ - RootchainCfg: nil, - - CommandResults: commandResults} -} - -func getProxyNameForImpl(input string) string { - return input + ProxySufix + return &deploymentResultInfo{BridgeCfg: nil, CommandResults: commandResults} } // getValidatorSet converts given validators to generic map @@ -757,5 +436,5 @@ func getValidatorSet(o command.OutputFormatter, return nil, err } - return accSet.ToAPIBinding(), nil + return accSet.ToABIBinding(), nil } diff --git a/command/bridge/deploy/deploy_test.go b/command/bridge/deploy/deploy_test.go index eeca033071..9bb06b5dc7 100644 --- a/command/bridge/deploy/deploy_test.go +++ b/command/bridge/deploy/deploy_test.go @@ -2,6 +2,7 @@ package deploy import ( "context" + "math/big" "os" "testing" @@ -10,6 +11,7 @@ import ( "github.com/Ethernal-Tech/ethgo/testutil" "github.com/stretchr/testify/require" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/bridge/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" @@ -48,8 +50,20 @@ func TestDeployContracts_NoPanics(t *testing.T) { }, } + chainCfg := &chain.Chain{ + Params: &chain.Params{ + ChainID: 1, + Engine: map[string]interface{}{ + "polybft": consensusCfg, + }, + }, + Genesis: &chain.Genesis{ + Alloc: make(map[types.Address]*chain.GenesisAccount), + }, + } + require.NotPanics(t, func() { - _, err = deployContracts(outputter, client, 1, []*validator.GenesisValidator{}, context.Background()) + _, err = deployContracts(outputter, client, big.NewInt(2), chainCfg, []*validator.GenesisValidator{}, context.Background()) }) require.NoError(t, err) } diff --git a/command/bridge/deploy/external_contracts.go b/command/bridge/deploy/external_contracts.go new file mode 100644 index 0000000000..30268e60ad --- /dev/null +++ b/command/bridge/deploy/external_contracts.go @@ -0,0 +1,332 @@ +package deploy + +import ( + "fmt" + "math/big" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/jsonrpc" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +// initExternalContracts initializes the external contracts +func initExternalContracts(bridgeCfg *polybft.BridgeConfig, + externalChainClient *jsonrpc.EthClient, externalChainID *big.Int) ([]*contract, error) { + externalContracts := make([]*contract, 0) + + // deploy root ERC20 token only if non-mintable native token flavor is used on a child chain + // and this external chain is the native token origin + if !consensusCfg.NativeTokenConfig.IsMintable && consensusCfg.NativeTokenConfig.ChainID == externalChainID.Uint64() { + if params.rootERC20TokenAddr != "" { + // use existing root chain ERC20 token + if err := populateExistingNativeTokenAddr(externalChainClient, + params.rootERC20TokenAddr, erc20Name, bridgeCfg); err != nil { + return nil, err + } + } else { + // deploy MockERC20 as a root chain root native token + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc20Name), + hasProxy: false, + artifact: contractsapi.RootERC20, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalNativeERC20Addr = dcr[0].Address + }, + }) + } + } + + // BLS contract + externalContracts = append(externalContracts, &contract{ + name: blsName, + hasProxy: true, + artifact: contractsapi.BLS, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.BLSAddress = dcr[1].Address + }, + }) + + // BN256G2 contract + externalContracts = append(externalContracts, &contract{ + name: bn256G2Name, + hasProxy: true, + artifact: contractsapi.BLS256, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.BN256G2Address = dcr[1].Address + }, + }) + + // Gateway contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, gatewayName), + hasProxy: true, + artifact: contractsapi.Gateway, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalGatewayAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + validatorSet, err := getValidatorSet(fmt, genesisValidators) + if err != nil { + return err + } + + inputParams := &contractsapi.InitializeGatewayFn{ + NewBls: config.BLSAddress, + NewBn256G2: config.BN256G2Address, + Validators: validatorSet, + } + + return initContract(fmt, relayer, inputParams, config.ExternalGatewayAddr, + gatewayName, key) + }, + }) + + // External ERC20Predicate contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc20PredicateName), + hasProxy: true, + artifact: contractsapi.RootERC20Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC20PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeRootERC20PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewChildERC20Predicate: config.InternalERC20PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC20Contract, + // root native token address should be non-zero only if native token is non-mintable on a childchain + NewNativeTokenRoot: config.ExternalNativeERC20Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalERC20PredicateAddr, + getContractName(false, erc20PredicateName), key) + }, + }) + + // External ERC20Mintable contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc20MintablePredicateName), + hasProxy: true, + artifact: contractsapi.ChildERC20Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalMintableERC20PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeChildERC20PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewRootERC20Predicate: config.InternalMintableERC20PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC20Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalMintableERC20PredicateAddr, + getContractName(false, erc20MintablePredicateName), key) + }, + }) + + // External ERC20Template contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc20TemplateName), + hasProxy: false, + artifact: contractsapi.ChildERC20, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC20Addr = dcr[0].Address + }, + }) + + // External ERC721Predicate contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc721PredicateName), + hasProxy: true, + artifact: contractsapi.RootERC721Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC721PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeRootERC721PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewChildERC721Predicate: config.InternalERC721PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC721Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalERC721PredicateAddr, + getContractName(false, erc721PredicateName), key) + }, + }) + + // External ERC721MintablePredicate contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc721MintablePredicateName), + hasProxy: true, + artifact: contractsapi.ChildERC721Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalMintableERC721PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeChildERC721PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewRootERC721Predicate: config.InternalMintableERC721PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC721Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalMintableERC721PredicateAddr, + getContractName(false, erc721MintablePredicateName), key) + }, + }) + + // External ERC721Template contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc721TemplateName), + hasProxy: false, + artifact: contractsapi.ChildERC721, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC721Addr = dcr[0].Address + }, + }) + + // External ERC1155Predicate contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc1155PredicateName), + hasProxy: true, + artifact: contractsapi.RootERC1155Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC1155PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeRootERC1155PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewChildERC1155Predicate: config.InternalERC1155PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC1155Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalERC1155PredicateAddr, + getContractName(false, erc1155PredicateName), key) + }, + }) + + // External ERC1155MintablePredicate contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc1155MintablePredicateName), + hasProxy: true, + artifact: contractsapi.ChildERC1155Predicate, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalMintableERC1155PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + input := &contractsapi.InitializeChildERC1155PredicateFn{ + NewGateway: config.ExternalGatewayAddr, + NewRootERC1155Predicate: config.InternalMintableERC1155PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC1155Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + + return initContract(fmt, relayer, input, config.ExternalMintableERC1155PredicateAddr, + getContractName(false, erc1155MintablePredicateName), key) + }, + }) + + // External ERC1155Template contract + externalContracts = append(externalContracts, &contract{ + name: getContractName(false, erc1155TemplateName), + hasProxy: false, + artifact: contractsapi.ChildERC1155, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.ExternalERC1155Addr = dcr[0].Address + }, + }) + + if !consensusCfg.NativeTokenConfig.IsMintable { + // if token is non-mintable we will deploy BladeManager + // if not, we don't need it + externalContracts = append(externalContracts, &contract{ + name: bladeManagerName, + artifact: contractsapi.BladeManager, + hasProxy: true, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.BladeManagerAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + gvs := make([]*contractsapi.GenesisAccount, len(genesisValidators)) + for i := 0; i < len(genesisValidators); i++ { + gvs[i] = &contractsapi.GenesisAccount{ + Addr: genesisValidators[i].Address, + IsValidator: true, + // this is set on purpose to 0, each account must premine enough tokens to itself if token is non-mintable + StakedTokens: big.NewInt(0), + PreminedTokens: big.NewInt(0), + } + } + + initParams := &contractsapi.InitializeBladeManagerFn{ + NewRootERC20Predicate: config.ExternalERC20PredicateAddr, + GenesisAccounts: gvs, + } + + return initContract(fmt, relayer, initParams, + config.BladeManagerAddr, bladeManagerName, key) + }, + }) + } + + return externalContracts, nil +} + +// populateExistingNativeTokenAddr checks whether given token is deployed on the provided address. +// If it is, then its address is set to the rootchain config, otherwise an error is returned +func populateExistingNativeTokenAddr(eth *jsonrpc.EthClient, tokenAddr, tokenName string, + bridgeCfg *polybft.BridgeConfig) error { + addr := types.StringToAddress(tokenAddr) + + code, err := eth.GetCode(addr, jsonrpc.LatestBlockNumberOrHash) + if err != nil { + return fmt.Errorf("failed to check is %s token deployed: %w", tokenName, err) + } else if code == "0x" { + return fmt.Errorf("%s token is not deployed on provided address %s", tokenName, tokenAddr) + } + + bridgeCfg.ExternalNativeERC20Addr = addr + + return nil +} diff --git a/command/bridge/deploy/internal_contracts.go b/command/bridge/deploy/internal_contracts.go new file mode 100644 index 0000000000..84d5126bca --- /dev/null +++ b/command/bridge/deploy/internal_contracts.go @@ -0,0 +1,365 @@ +//nolint:dupl +package deploy + +import ( + "math/big" + + "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/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/Ethernal-Tech/ethgo" +) + +var bigZero = big.NewInt(0) + +// initInternalContracts initializes the internal contracts +func initInternalContracts(chainCfg *chain.Chain) []*contract { + useBridgeAllowList := chainCfg.Params.IsBridgeAllowListEnabled() + useBridgeBlockList := chainCfg.Params.IsBridgeBlockListEnabled() + + internalContracts := make([]*contract, 0, 7) + + // Gateway contract + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, gatewayName), + hasProxy: true, + artifact: contractsapi.Gateway, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalGatewayAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + _ int64) error { + validatorSet, err := getValidatorSet(fmt, genesisValidators) + if err != nil { + return err + } + + inputParams := &contractsapi.InitializeGatewayFn{ + NewBls: contracts.BLSContract, + NewBn256G2: contracts.BLS256Contract, + Validators: validatorSet, + } + + return initContract(fmt, relayer, inputParams, config.ExternalGatewayAddr, + gatewayName, key) + }, + }) + + // InternalERC20Predicate contract + contractArtifact := contractsapi.ChildERC20Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.ChildERC20PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc20PredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalERC20PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeChildERC20PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC20Predicate: config.ExternalERC20PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC20Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + NewNativeTokenRootAddress: config.ExternalNativeERC20Addr, + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeChildERC20PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC20Predicate: config.ExternalERC20PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC20Contract, + NewNativeTokenRootAddress: config.ExternalNativeERC20Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalERC20PredicateAddr, + getContractName(true, erc20PredicateName), key) + }, + }) + + // InternalERC721Predicate contract + contractArtifact = contractsapi.ChildERC721Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.ChildERC721PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc721PredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalERC721PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeChildERC721PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC721Predicate: config.ExternalERC721PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC721Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeChildERC721PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC721Predicate: config.ExternalERC721PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC721Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalERC721PredicateAddr, + getContractName(true, erc721PredicateName), key) + }, + }) + + // InternalERC1155Predicate contract + contractArtifact = contractsapi.ChildERC1155Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.ChildERC1155PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc1155PredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalERC1155PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeChildERC1155PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC1155Predicate: config.ExternalERC1155PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC1155Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeChildERC1155PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewRootERC1155Predicate: config.ExternalERC1155PredicateAddr, + NewDestinationTokenTemplate: contracts.ChildERC1155Contract, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalERC1155PredicateAddr, + getContractName(true, erc1155PredicateName), key) + }, + }) + + // InternalMintableERC20Predicate contract + contractArtifact = contractsapi.RootERC20Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.RootMintableERC20PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc20MintablePredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalMintableERC20PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeRootMintableERC20PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC20Predicate: config.ExternalMintableERC20PredicateAddr, + NewTokenTemplate: config.ExternalERC20Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeRootERC20PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC20Predicate: config.ExternalMintableERC20PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC20Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalMintableERC20PredicateAddr, + getContractName(true, erc20MintablePredicateName), key) + }, + }) + + // InternalMintableERC721Predicate contract + contractArtifact = contractsapi.RootERC721Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.RootMintableERC721PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc721MintablePredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalMintableERC721PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeRootMintableERC721PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC721Predicate: config.ExternalMintableERC721PredicateAddr, + NewTokenTemplate: config.ExternalERC721Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeRootERC721PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC721Predicate: config.ExternalMintableERC721PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC721Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalMintableERC721PredicateAddr, + getContractName(true, erc721MintablePredicateName), key) + }, + }) + + // InternalMintableERC1155Predicate contract + contractArtifact = contractsapi.RootERC1155Predicate + if useBridgeAllowList || useBridgeBlockList { + contractArtifact = contractsapi.RootMintableERC1155PredicateACL + } + + internalContracts = append(internalContracts, &contract{ + name: getContractName(true, erc1155MintablePredicateName), + hasProxy: true, + artifact: contractArtifact, + addressPopulatorFn: func(bc *polybft.BridgeConfig, dcr []*deployContractResult) { + bc.InternalMintableERC1155PredicateAddr = dcr[1].Address + }, + initializeFn: func(fmt command.OutputFormatter, relayer txrelayer.TxRelayer, + genesisValidators []*validator.GenesisValidator, + config *polybft.BridgeConfig, + key crypto.Key, + destinationChainID int64) error { + var input contractsapi.FunctionAbi + if useBridgeAllowList || useBridgeBlockList { + input = &contractsapi.InitializeRootMintableERC1155PredicateACLFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC1155Predicate: config.ExternalMintableERC1155PredicateAddr, + NewTokenTemplate: config.ExternalERC1155Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + NewUseAllowList: useBridgeAllowList, + NewUseBlockList: useBridgeBlockList, + NewOwner: chainCfg.Params.GetBridgeOwner(), + } + } else { + input = &contractsapi.InitializeRootERC1155PredicateFn{ + NewGateway: config.InternalGatewayAddr, + NewChildERC1155Predicate: config.ExternalMintableERC1155PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC1155Addr, + NewDestinationChainID: big.NewInt(destinationChainID), + } + } + + return initContract(fmt, relayer, input, config.InternalMintableERC1155PredicateAddr, + getContractName(true, erc1155MintablePredicateName), key) + }, + }) + + return internalContracts +} + +// preAllocateInternalPredicates pre-allocates internal predicates in genesis +// if the command is run in bootstrap mode +func preAllocateInternalPredicates(o command.OutputFormatter, internalContracts []*contract, + chainCfg *chain.Chain, bridgeCfg *polybft.BridgeConfig) error { + predicateBaseProxyAddress := contracts.ChildBridgeContractsBaseAddress + + if consensusCfg.Bridge != nil { + for _, bridgeCfg := range consensusCfg.Bridge { + highestAddr := bridgeCfg.GetHighestInternalAddress() + if highestAddr.Compare(predicateBaseProxyAddress) > 0 { + predicateBaseProxyAddress = highestAddr + } + } + } + + lastAddress := predicateBaseProxyAddress + for _, contract := range internalContracts { + proxyAddress, implAddress := generateInternalContractAndProxyAddress(lastAddress) + + contract.addressPopulatorFn(bridgeCfg, []*deployContractResult{ + newDeployContractsResult(contract.name, false, implAddress, ethgo.ZeroHash, 0), + newDeployContractsResult(contract.constructProxyName(), true, proxyAddress, ethgo.ZeroHash, 0), + }) + + chainCfg.Genesis.Alloc[implAddress] = &chain.GenesisAccount{ + Balance: bigZero, + Code: contract.artifact.DeployedBytecode, + } + + lastAddress = proxyAddress + } + + if _, err := o.Write([]byte("[BRIDGE - DEPLOY] Internal predicates pre-allocated in bootstrap mode\n")); err != nil { + return err + } + + return nil +} + +// generateInternalContractAndProxyAddress generates the internal contract and proxy addresses +func generateInternalContractAndProxyAddress(lastAddress types.Address) (types.Address, types.Address) { + proxyAddress := lastAddress.IncrementBy(10) + implAddress := lastAddress.IncrementBy(1) + + return proxyAddress, implAddress +} diff --git a/command/bridge/deploy/params.go b/command/bridge/deploy/params.go index 2adc7400c9..9e3e85a8b6 100644 --- a/command/bridge/deploy/params.go +++ b/command/bridge/deploy/params.go @@ -14,16 +14,21 @@ const ( deployerKeyFlag = "deployer-key" jsonRPCFlag = "json-rpc" erc20AddrFlag = "erc20-token" + isBootstrapFlag = "bootstrap" + externalRPCFlag = "external-json-rpc" + internalRPCFlag = "internal-json-rpc" ) type deployParams struct { genesisPath string deployerKey string - jsonRPCAddress string + externalRPCAddress string + internalRPCAddress string rootERC20TokenAddr string proxyContractsAdmin string txTimeout time.Duration isTestMode bool + isBootstrap bool } func (ip *deployParams) validateFlags() error { diff --git a/command/bridge/deploy/result.go b/command/bridge/deploy/result.go index 12bb60fa50..11291187eb 100644 --- a/command/bridge/deploy/result.go +++ b/command/bridge/deploy/result.go @@ -14,16 +14,21 @@ type deployContractResult struct { Address types.Address `json:"address"` Hash types.Hash `json:"hash"` GasUsed uint64 `json:"gasUsed"` + isProxy bool `json:"-"` } -func newDeployContractsResult(name string, +func newDeployContractsResult( + name string, + isProxy bool, address types.Address, - hash ethgo.Hash, gasUsed uint64) *deployContractResult { + hash ethgo.Hash, + gasUsed uint64) *deployContractResult { return &deployContractResult{ Name: name, Address: address, Hash: types.BytesToHash(hash.Bytes()), GasUsed: gasUsed, + isProxy: isProxy, } } diff --git a/command/bridge/deploy/types.go b/command/bridge/deploy/types.go new file mode 100644 index 0000000000..87bdc86287 --- /dev/null +++ b/command/bridge/deploy/types.go @@ -0,0 +1,115 @@ +package deploy + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +const ( + contractsDeploymentTitle = "[BRIDGE - CONTRACTS DEPLOYMENT]" + + proxySuffix = "Proxy" + externalPrefix = "External" + internalPrefix = "Internal" + + gatewayName = "Gateway" + bladeManagerName = "BladeManager" + blsName = "BLS" + bn256G2Name = "BN256G2" + erc20PredicateName = "ERC20Predicate" + erc20MintablePredicateName = "ERC20MintablePredicate" + erc20Name = "ERC20" + erc20TemplateName = "ERC20Template" + erc721PredicateName = "ERC721Predicate" + erc721MintablePredicateName = "ERC721MintablePredicate" + erc721TemplateName = "ERC721Template" + erc1155PredicateName = "ERC1155Predicate" + erc1155MintablePredicateName = "ERC1155MintablePredicate" + erc1155TemplateName = "ERC1155Template" +) + +type addressPopulator func(*polybft.BridgeConfig, []*deployContractResult) +type initializer func(command.OutputFormatter, txrelayer.TxRelayer, + []*validator.GenesisValidator, + *polybft.BridgeConfig, crypto.Key, int64) error + +// contract represents a contract to be deployed +type contract struct { + name string + hasProxy bool + artifact *contracts.Artifact + addressPopulatorFn addressPopulator + initializeFn initializer +} + +// deploy deploys the contract and its proxy if it has one, and returns the deployment results +func (c *contract) deploy( + bridgeCfg *polybft.BridgeConfig, + txRelayer txrelayer.TxRelayer, deployerKey crypto.Key, + proxyAdmin types.Address) ([]*deployContractResult, error) { + txn := helper.CreateTransaction(types.ZeroAddress, nil, c.artifact.Bytecode, nil, true) + + receipt, err := txRelayer.SendTransaction(txn, deployerKey) + if err != nil { + return nil, fmt.Errorf("failed sending %s contract deploy transaction: %w", c.name, err) + } + + if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { + return nil, fmt.Errorf("deployment of %s contract failed", c.name) + } + + deployResults := make([]*deployContractResult, 0, 2) + implementationAddress := types.Address(receipt.ContractAddress) + + deployResults = append(deployResults, + newDeployContractsResult(c.name, false, + implementationAddress, + receipt.TransactionHash, + receipt.GasUsed)) + + if c.hasProxy { + proxyContractName := c.constructProxyName() + + receipt, err := helper.DeployProxyContract( + txRelayer, deployerKey, proxyContractName, proxyAdmin, implementationAddress) + if err != nil { + return nil, err + } + + if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { + return nil, fmt.Errorf("deployment of %s contract failed", proxyContractName) + } + + deployResults = append(deployResults, + newDeployContractsResult(proxyContractName, true, + types.Address(receipt.ContractAddress), + receipt.TransactionHash, + receipt.GasUsed)) + } + + c.addressPopulatorFn(bridgeCfg, deployResults) + + return deployResults, nil +} + +// constructProxyName builds a proxy contract name, by adding a predefined proxy suffix on the contract name. +func (c *contract) constructProxyName() string { + return fmt.Sprintf("%s%s", c.name, proxySuffix) +} + +func getContractName(isInternal bool, input string) string { + prefix := externalPrefix + if isInternal { + prefix = internalPrefix + } + + return fmt.Sprintf("%s%s%s", prefix, input, proxySuffix) +} diff --git a/command/bridge/withdraw/erc1155/withdraw_erc1155.go b/command/bridge/withdraw/erc1155/withdraw_erc1155.go index f7e9018bdd..1140787d28 100644 --- a/command/bridge/withdraw/erc1155/withdraw_erc1155.go +++ b/command/bridge/withdraw/erc1155/withdraw_erc1155.go @@ -51,7 +51,7 @@ func GetCommand() *cobra.Command { withdrawCmd.Flags().StringVar( &wp.PredicateAddr, common.ChildPredicateFlag, - contracts.ChildERC1155PredicateContract.String(), + "", "ERC 1155 child chain predicate address", ) diff --git a/command/bridge/withdraw/erc20/withdraw_erc20.go b/command/bridge/withdraw/erc20/withdraw_erc20.go index 3fcdfaa5d7..349f4c01cd 100644 --- a/command/bridge/withdraw/erc20/withdraw_erc20.go +++ b/command/bridge/withdraw/erc20/withdraw_erc20.go @@ -43,7 +43,7 @@ func GetCommand() *cobra.Command { withdrawCmd.Flags().StringVar( &wp.PredicateAddr, common.ChildPredicateFlag, - contracts.ChildERC20PredicateContract.String(), + "", "child ERC 20 predicate address", ) diff --git a/command/bridge/withdraw/erc721/withdraw_erc721.go b/command/bridge/withdraw/erc721/withdraw_erc721.go index 6685c0e7ba..bec6d6086d 100644 --- a/command/bridge/withdraw/erc721/withdraw_erc721.go +++ b/command/bridge/withdraw/erc721/withdraw_erc721.go @@ -42,7 +42,7 @@ func GetCommand() *cobra.Command { withdrawCmd.Flags().StringVar( &wp.PredicateAddr, common.ChildPredicateFlag, - contracts.ChildERC721PredicateContract.String(), + "", "ERC 721 child chain predicate address", ) diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 8dae65f5f3..40df7efb52 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -374,10 +374,6 @@ func (p *genesisParams) deployContracts(rewardTokenByteCode []byte, } genesisContracts := []*contractInfo{ - { - artifact: contractsapi.Gateway, - address: contracts.GatewayContractV1, - }, { artifact: contractsapi.BridgeStorage, address: contracts.BridgeStorageContractV1, @@ -459,46 +455,6 @@ func (p *genesisParams) deployContracts(rewardTokenByteCode []byte, }) } - if len(params.bridgeAllowListAdmin) != 0 || len(params.bridgeBlockListAdmin) != 0 { - // rootchain originated tokens predicates (with access lists) - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC20PredicateACL, - address: contracts.ChildERC20PredicateContractV1, - }) - - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC721PredicateACL, - address: contracts.ChildERC721PredicateContractV1, - }) - - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC1155PredicateACL, - address: contracts.ChildERC1155PredicateContractV1, - }) - } else { - // rootchain originated tokens predicates - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC20Predicate, - address: contracts.ChildERC20PredicateContractV1, - }) - - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC721Predicate, - address: contracts.ChildERC721PredicateContractV1, - }) - - genesisContracts = append(genesisContracts, - &contractInfo{ - artifact: contractsapi.ChildERC1155Predicate, - address: contracts.ChildERC1155PredicateContractV1, - }) - } - allocations := make(map[types.Address]*chain.GenesisAccount, len(genesisContracts)+1) if rewardTokenByteCode != nil { diff --git a/consensus/polybft/bridge_batch_test.go b/consensus/polybft/bridge_batch_test.go index 44e95f1ba1..d8a96c33f5 100644 --- a/consensus/polybft/bridge_batch_test.go +++ b/consensus/polybft/bridge_batch_test.go @@ -12,10 +12,6 @@ import ( func TestBridgeBatchSigned_Hash(t *testing.T) { t.Parallel() - const ( - eventsCount = 10 - ) - bridgeBatchSigned1 := newTestBridgeBatchSigned(t, 1, 0) bridgeBatchSigned2 := newTestBridgeBatchSigned(t, 1, 0) bridgeBatchSigned3 := newTestBridgeBatchSigned(t, 2, 0) diff --git a/consensus/polybft/bridge_event_manager.go b/consensus/polybft/bridge_event_manager.go index 56165e5bfd..e33959557b 100644 --- a/consensus/polybft/bridge_event_manager.go +++ b/consensus/polybft/bridge_event_manager.go @@ -21,7 +21,6 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/types" ) @@ -65,6 +64,7 @@ func (d *dummyBridgeEventManager) ProcessLog(header *types.Header, // bridgeEventManagerConfig holds the configuration data of bridge event manager type bridgeEventManagerConfig struct { + bridgeCfg *BridgeConfig topic topic key *wallet.Key maxNumberOfEvents uint64 @@ -322,10 +322,11 @@ func (b *bridgeEventManager) getAggSignatureForBridgeBatchMessage(blockNumber ui return Signature{}, err } - signatures := make(bls.Signatures, 0, len(votes)) - publicKeys := make([][]byte, 0, len(votes)) - bmap := bitmap.Bitmap{} - signers := make(map[types.Address]struct{}, 0) + var ( + signatures = make(bls.Signatures, 0, len(votes)) + bmap = bitmap.Bitmap{} + signers = make(map[types.Address]struct{}, 0) + ) for _, vote := range votes { index, exists := validatorAddrToIndex[vote.From] @@ -341,7 +342,6 @@ func (b *bridgeEventManager) getAggSignatureForBridgeBatchMessage(blockNumber ui bmap.Set(uint64(index)) //nolint:gosec signatures = append(signatures, signature) - publicKeys = append(publicKeys, validatorsMetadata[index].BlsKey.Marshal()) signers[types.StringToAddress(vote.From)] = struct{}{} } @@ -543,7 +543,7 @@ func (b *bridgeEventManager) GetLogFilters() map[types.Address][]types.Hash { var bridgeMessageResult contractsapi.BridgeMessageResultEvent return map[types.Address][]types.Hash{ - contracts.GatewayContract: {types.Hash(bridgeMessageResult.Sig())}, + b.config.bridgeCfg.ExternalGatewayAddr: {types.Hash(bridgeMessageResult.Sig())}, } } diff --git a/consensus/polybft/bridge_manager.go b/consensus/polybft/bridge_manager.go index c17750ff1c..11b5b372bf 100644 --- a/consensus/polybft/bridge_manager.go +++ b/consensus/polybft/bridge_manager.go @@ -9,7 +9,6 @@ import ( "github.com/0xPolygon/polygon-edge/consensus" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/types" "github.com/Ethernal-Tech/blockchain-event-tracker/store" "github.com/Ethernal-Tech/blockchain-event-tracker/tracker" @@ -197,7 +196,7 @@ func newBridgeManager( var err error - gatewayAddr := runtimeConfig.GenesisConfig.Bridge[chainID].GatewayAddr + gatewayAddr := runtimeConfig.GenesisConfig.Bridge[chainID].ExternalGatewayAddr bridgeManager := &bridgeManager{ chainID: chainID, logger: logger.Named("bridge-manager"), @@ -268,6 +267,7 @@ func (b *bridgeManager) initBridgeEventManager( logger.Named("state-sync-manager"), runtimeConfig.State, &bridgeEventManagerConfig{ + bridgeCfg: runtimeConfig.GenesisConfig.Bridge[b.chainID], key: runtimeConfig.Key, topic: runtimeConfig.bridgeTopic, maxNumberOfEvents: maxNumberOfEvents, @@ -302,7 +302,7 @@ func (b *bridgeManager) initStateSyncRelayer( maxBlocksToWaitForResend: defaultMaxBlocksToWaitForResend, maxAttemptsToSend: defaultMaxAttemptsToSend, maxEventsPerBatch: defaultMaxEventsPerBatch, - eventExecutionAddr: contracts.GatewayContract, + //eventExecutionAddr: contracts.GatewayContract, }, logger.Named("state_sync_relayer")) } else { diff --git a/consensus/polybft/contracts_initializer.go b/consensus/polybft/contracts_initializer.go index 917e692af7..129ef8fadb 100644 --- a/consensus/polybft/contracts_initializer.go +++ b/consensus/polybft/contracts_initializer.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/0xPolygon/polygon-edge/bls" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" @@ -93,22 +94,25 @@ func initEpochManager(polyBFTConfig PolyBFTConfig, transition *state.Transition) } // getInitERC20PredicateInput builds initialization input parameters for child chain ERC20Predicate SC -func getInitERC20PredicateInput(config *BridgeConfig, childChainMintable bool, chainID *big.Int) ([]byte, error) { +func getInitERC20PredicateInput( + config *BridgeConfig, + childChainMintable bool, + destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childChainMintable { params = &contractsapi.InitializeRootERC20PredicateFn{ - NewGateway: contracts.GatewayContract, - NewChildERC20Predicate: config.ChildERC20PredicateAddr, - NewDestinationTokenTemplate: config.ChildERC20Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC20Predicate: config.ExternalMintableERC20PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC20Addr, + NewDestinationChainID: destinationChainID, } } else { params = &contractsapi.InitializeChildERC20PredicateFn{ - NewGateway: contracts.GatewayContract, - NewRootERC20Predicate: config.RootERC20PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC20Predicate: config.ExternalERC20PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC20Contract, - NewNativeTokenRootAddress: config.RootNativeERC20Addr, - NewDestinationChainID: chainID, + NewNativeTokenRootAddress: config.ExternalNativeERC20Addr, + NewDestinationChainID: destinationChainID, } } @@ -117,25 +121,25 @@ func getInitERC20PredicateInput(config *BridgeConfig, childChainMintable bool, c // getInitERC20PredicateACLInput builds initialization input parameters for child chain ERC20PredicateAccessList SC func getInitERC20PredicateACLInput(config *BridgeConfig, owner types.Address, - useAllowList, useBlockList, childChainMintable bool, chainID *big.Int) ([]byte, error) { + useAllowList, useBlockList, childChainMintable bool, destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childChainMintable { params = &contractsapi.InitializeRootMintableERC20PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewChildERC20Predicate: config.ChildERC20PredicateAddr, - NewTokenTemplate: config.ChildERC20Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC20Predicate: config.ExternalMintableERC20PredicateAddr, + NewTokenTemplate: config.ExternalERC20Addr, + NewDestinationChainID: destinationChainID, NewUseAllowList: useAllowList, NewUseBlockList: useBlockList, NewOwner: owner, } } else { params = &contractsapi.InitializeChildERC20PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewRootERC20Predicate: config.RootERC20PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC20Predicate: config.ExternalERC20PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC20Contract, - NewDestinationChainID: chainID, - NewNativeTokenRootAddress: config.RootNativeERC20Addr, + NewDestinationChainID: destinationChainID, + NewNativeTokenRootAddress: config.ExternalNativeERC20Addr, NewUseAllowList: useAllowList, NewUseBlockList: useBlockList, NewOwner: owner, @@ -146,21 +150,24 @@ func getInitERC20PredicateACLInput(config *BridgeConfig, owner types.Address, } // getInitERC721PredicateInput builds initialization input parameters for child chain ERC721Predicate SC -func getInitERC721PredicateInput(config *BridgeConfig, childOriginatedTokens bool, chainID *big.Int) ([]byte, error) { +func getInitERC721PredicateInput( + config *BridgeConfig, + childOriginatedTokens bool, + destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childOriginatedTokens { params = &contractsapi.InitializeRootERC721PredicateFn{ - NewGateway: contracts.GatewayContract, - NewChildERC721Predicate: config.ChildERC721PredicateAddr, - NewDestinationTokenTemplate: config.ChildERC721Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC721Predicate: config.ExternalMintableERC721PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC721Addr, + NewDestinationChainID: destinationChainID, } } else { params = &contractsapi.InitializeChildERC721PredicateFn{ - NewGateway: contracts.GatewayContract, - NewRootERC721Predicate: config.RootERC721PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC721Predicate: config.ExternalERC721PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC721Contract, - NewDestinationChainID: chainID, + NewDestinationChainID: destinationChainID, } } @@ -170,24 +177,27 @@ func getInitERC721PredicateInput(config *BridgeConfig, childOriginatedTokens boo // getInitERC721PredicateACLInput builds initialization input parameters // for child chain ERC721PredicateAccessList SC func getInitERC721PredicateACLInput(config *BridgeConfig, owner types.Address, - useAllowList, useBlockList, childChainMintable bool, chainID *big.Int) ([]byte, error) { + useAllowList, useBlockList, childChainMintable bool, destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childChainMintable { params = &contractsapi.InitializeRootMintableERC721PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewChildERC721Predicate: config.ChildERC721PredicateAddr, - NewTokenTemplate: config.ChildERC721Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC721Predicate: config.ExternalMintableERC721PredicateAddr, + NewTokenTemplate: config.ExternalERC721Addr, + NewDestinationChainID: destinationChainID, NewUseAllowList: useAllowList, NewUseBlockList: useBlockList, NewOwner: owner, } } else { params = &contractsapi.InitializeChildERC721PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewRootERC721Predicate: config.RootERC721PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC721Predicate: config.ExternalERC721PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC721Contract, - NewDestinationChainID: chainID, + NewDestinationChainID: destinationChainID, + NewUseAllowList: useAllowList, + NewUseBlockList: useBlockList, + NewOwner: owner, } } @@ -195,21 +205,24 @@ func getInitERC721PredicateACLInput(config *BridgeConfig, owner types.Address, } // getInitERC1155PredicateInput builds initialization input parameters for child chain ERC1155Predicate SC -func getInitERC1155PredicateInput(config *BridgeConfig, childChainMintable bool, chainID *big.Int) ([]byte, error) { +func getInitERC1155PredicateInput( + config *BridgeConfig, + childChainMintable bool, + destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childChainMintable { params = &contractsapi.InitializeRootERC1155PredicateFn{ - NewGateway: contracts.GatewayContract, - NewChildERC1155Predicate: config.ChildERC1155PredicateAddr, - NewDestinationTokenTemplate: config.ChildERC1155Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC1155Predicate: config.ExternalMintableERC1155PredicateAddr, + NewDestinationTokenTemplate: config.ExternalERC1155Addr, + NewDestinationChainID: destinationChainID, } } else { params = &contractsapi.InitializeChildERC1155PredicateFn{ - NewGateway: contracts.GatewayContract, - NewRootERC1155Predicate: config.RootERC1155PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC1155Predicate: config.ExternalERC1155PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC1155Contract, - NewDestinationChainID: chainID, + NewDestinationChainID: destinationChainID, } } @@ -219,24 +232,27 @@ func getInitERC1155PredicateInput(config *BridgeConfig, childChainMintable bool, // getInitERC1155PredicateACLInput builds initialization input parameters // for child chain ERC1155PredicateAccessList SC func getInitERC1155PredicateACLInput(config *BridgeConfig, owner types.Address, - useAllowList, useBlockList, childChainMintable bool, chainID *big.Int) ([]byte, error) { + useAllowList, useBlockList, childChainMintable bool, destinationChainID *big.Int) ([]byte, error) { var params contractsapi.StateTransactionInput if childChainMintable { params = &contractsapi.InitializeRootMintableERC1155PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewChildERC1155Predicate: config.ChildERC1155PredicateAddr, - NewTokenTemplate: config.ChildERC1155Addr, - NewDestinationChainID: chainID, + NewGateway: config.InternalGatewayAddr, + NewChildERC1155Predicate: config.ExternalMintableERC1155PredicateAddr, + NewTokenTemplate: config.ExternalERC1155Addr, + NewDestinationChainID: destinationChainID, NewUseAllowList: useAllowList, NewUseBlockList: useBlockList, NewOwner: owner, } } else { params = &contractsapi.InitializeChildERC1155PredicateACLFn{ - NewGateway: contracts.GatewayContract, - NewRootERC1155Predicate: config.RootERC1155PredicateAddr, + NewGateway: config.InternalGatewayAddr, + NewRootERC1155Predicate: config.ExternalERC1155PredicateAddr, NewDestinationTokenTemplate: contracts.ChildERC1155Contract, - NewDestinationChainID: chainID, + NewDestinationChainID: destinationChainID, + NewUseAllowList: useAllowList, + NewUseBlockList: useBlockList, + NewOwner: owner, } } @@ -363,7 +379,15 @@ func initBridgeStorageContract(cfg PolyBFTConfig, transition *state.Transition) } // initGatewayContract initializes Gateway contract on blade chain -func initGatewayContract(cfg PolyBFTConfig, transition *state.Transition) error { +func initGatewayContract(cfg PolyBFTConfig, bridgeCfg *BridgeConfig, + transition *state.Transition, alloc map[types.Address]*chain.GenesisAccount) error { + implementationAddr := bridgeCfg.InternalGatewayAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize gateway contract for bridges that were added + // after the genesis block + return nil + } + validators, err := getValidatorStorageValidators(cfg.InitialValidatorSet) if err != nil { return fmt.Errorf("error while converting validators for gateway contract: %w", err) @@ -380,13 +404,187 @@ func initGatewayContract(cfg PolyBFTConfig, transition *state.Transition) error return fmt.Errorf("gateway.initialize params encoding failed: %w", err) } - return callContract(contracts.SystemCaller, contracts.GatewayContract, input, + return callContract(contracts.SystemCaller, bridgeCfg.InternalGatewayAddr, input, "Gateway.initialize", transition) } +// initERC20ACLPredicateContract initializes ChildERC20Predicate with access list contract on blade chain +func initERC20ACLPredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + owner types.Address, + useBridgeAllowList, useBridgeBlockList, childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC20PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC20PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC20PredicateACLInput(bcfg, owner, + useBridgeAllowList, useBridgeBlockList, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + +// initERC721ACLPredicateContract initializes ChildERC721Predicate with access list contract on blade chain +func initERC721ACLPredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + owner types.Address, + useBridgeAllowList, useBridgeBlockList, childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC721PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC721PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC721PredicateACLInput(bcfg, owner, + useBridgeAllowList, useBridgeBlockList, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + +// initERC1155ACLPredicateContract initializes ChildERC1155Predicate with access list contract on blade chain +func initERC1155ACLPredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + owner types.Address, + useBridgeAllowList, useBridgeBlockList, childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC1155PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC1155PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC1155PredicateACLInput(bcfg, owner, + useBridgeAllowList, useBridgeBlockList, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + +// initERC20PredicateContract initializes ChildERC20Predicate contract on blade chain +func initERC20PredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC20PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC20PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC20PredicateInput(bcfg, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + +// initERC721PredicateContract initializes ChildERC721Predicate contract on blade chain +func initERC721PredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC721PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC721PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC721PredicateInput(bcfg, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + +// initERC1155PredicateContract initializes ChildERC1155Predicate contract on blade chain +func initERC1155PredicateContract( + transition *state.Transition, + bcfg *BridgeConfig, + alloc map[types.Address]*chain.GenesisAccount, + childMintable bool, + destinationChainID *big.Int, + contractName string) error { + contractAddr := bcfg.InternalMintableERC1155PredicateAddr + if !childMintable { + contractAddr = bcfg.InternalERC1155PredicateAddr + } + + implementationAddr := contractAddr.IncrementBy(1) + if _, exists := alloc[implementationAddr]; !exists { + // we do not initialize child predicates for bridges that were added + // after the genesis block + return nil + } + + input, err := getInitERC1155PredicateInput(bcfg, childMintable, destinationChainID) + if err != nil { + return err + } + + return callContract(contracts.SystemCaller, contractAddr, input, contractName, transition) +} + // mintRewardTokensToWallet mints configured amount of reward tokens to reward wallet address func mintRewardTokensToWallet(polyBFTConfig PolyBFTConfig, transition *state.Transition) error { - if isNativeRewardToken(polyBFTConfig) { + if isNativeRewardToken(polyBFTConfig.RewardConfig.TokenAddress) { // if reward token is a native erc20 token, we don't need to mint an amount of tokens // for given wallet address to it since this is done in premine return nil @@ -492,8 +690,8 @@ func getValidatorStorageValidators(initialValidators []*validator.GenesisValidat } // isNativeRewardToken returns true in case a native token is used as a reward token as well -func isNativeRewardToken(cfg PolyBFTConfig) bool { - return cfg.RewardConfig.TokenAddress == contracts.NativeERC20TokenContract +func isNativeRewardToken(rewardTokenAddr types.Address) bool { + return rewardTokenAddr == contracts.NativeERC20TokenContract } // IsNativeStakeToken return true in case a native token is used for staking diff --git a/consensus/polybft/contractsapi/helper.go b/consensus/polybft/contractsapi/helper.go index a1cf51e5c5..ab08995924 100644 --- a/consensus/polybft/contractsapi/helper.go +++ b/consensus/polybft/contractsapi/helper.go @@ -23,6 +23,16 @@ type EventAbi interface { ParseLog(log *ethgo.Log) (bool, error) } +// FunctionAbi is an interface representing a function in contractsapi +type FunctionAbi interface { + // Sig returns the function ABI signature or ID (which is unique for all function types) + Sig() []byte + // DecodeAbi does abi decoding of given function + DecodeAbi(buf []byte) error + // EncodeAbi does abi encoding of given function + EncodeAbi() ([]byte, error) +} + var ( // stateSyncABIType is a specific case where we need to encode state sync event as a tuple of tuple stateSyncABIType = abi.MustNewType( diff --git a/consensus/polybft/fsm.go b/consensus/polybft/fsm.go index eafdc37f15..eef3666106 100644 --- a/consensus/polybft/fsm.go +++ b/consensus/polybft/fsm.go @@ -764,7 +764,7 @@ func createCommitValidatorSetInput( } return &contractsapi.CommitValidatorSetBridgeStorageFn{ - NewValidatorSet: validators.ToAPIBinding(), + NewValidatorSet: validators.ToABIBinding(), Signature: signatureBig, Bitmap: extra.Committed.Bitmap, }, nil diff --git a/consensus/polybft/fsm_test.go b/consensus/polybft/fsm_test.go index e4048a93f7..00c8e63878 100644 --- a/consensus/polybft/fsm_test.go +++ b/consensus/polybft/fsm_test.go @@ -661,7 +661,7 @@ func TestFSM_VerifyStateTransaction_BridgeBatches(t *testing.T) { require.NoError(t, err) if i == 0 { - tx := createStateTransactionWithData(contracts.GatewayContract, inputData) + tx := createStateTransactionWithData(types.StringToAddress("0x10101010101"), inputData) txns = append(txns, tx) } } @@ -794,13 +794,15 @@ func TestFSM_VerifyStateTransaction_BridgeBatches(t *testing.T) { inputData, err := bridgeBatchSigned.EncodeAbi() require.NoError(t, err) + gatewayContractAddr := types.StringToAddress("0x10101010101") + txns = append(txns, - createStateTransactionWithData(contracts.GatewayContract, inputData)) + createStateTransactionWithData(gatewayContractAddr, inputData)) inputData, err = bridgeBatchSigned.EncodeAbi() require.NoError(t, err) txns = append(txns, - createStateTransactionWithData(contracts.GatewayContract, inputData)) + createStateTransactionWithData(gatewayContractAddr, inputData)) err = f.VerifyStateTransactions(txns) require.ErrorContains(t, err, "only one bridge batch tx is allowed per block") }) @@ -1459,7 +1461,7 @@ func TestFSM_VerifyStateTransaction_InvalidTypeOfStateTransactions(t *testing.T) var txns []*types.Transaction txns = append(txns, - createStateTransactionWithData(contracts.GatewayContract, []byte{9, 3, 1, 1})) + createStateTransactionWithData(types.StringToAddress("0x1010101001"), []byte{9, 3, 1, 1})) require.ErrorContains(t, f.VerifyStateTransactions(txns), "unknown state transaction") } diff --git a/consensus/polybft/helpers_test.go b/consensus/polybft/helpers_test.go index e2cb30ba74..0b418d970a 100644 --- a/consensus/polybft/helpers_test.go +++ b/consensus/polybft/helpers_test.go @@ -183,14 +183,14 @@ func generateTestAccount(tb testing.TB) *wallet.Account { // createTestBridgeConfig creates test bridge configuration with hard-coded addresses func createTestBridgeConfig() *BridgeConfig { return &BridgeConfig{ - GatewayAddr: types.StringToAddress("1"), - RootERC20PredicateAddr: types.StringToAddress("2"), - ChildERC20PredicateAddr: types.StringToAddress("3"), - RootNativeERC20Addr: types.StringToAddress("4"), - RootERC721PredicateAddr: types.StringToAddress("5"), - ChildERC721PredicateAddr: types.StringToAddress("6"), - RootERC1155PredicateAddr: types.StringToAddress("7"), - ChildERC1155PredicateAddr: types.StringToAddress("8"), - JSONRPCEndpoint: "http://localhost:8545", + ExternalGatewayAddr: types.StringToAddress("1"), + ExternalERC20PredicateAddr: types.StringToAddress("2"), + ExternalMintableERC20PredicateAddr: types.StringToAddress("3"), + ExternalNativeERC20Addr: types.StringToAddress("4"), + ExternalERC721PredicateAddr: types.StringToAddress("5"), + ExternalMintableERC721PredicateAddr: types.StringToAddress("6"), + ExternalERC1155PredicateAddr: types.StringToAddress("7"), + ExternalMintableERC1155PredicateAddr: types.StringToAddress("8"), + JSONRPCEndpoint: "http://localhost:8545", } } diff --git a/consensus/polybft/polybft.go b/consensus/polybft/polybft.go index 30b92d0c83..5ae188f9ae 100644 --- a/consensus/polybft/polybft.go +++ b/consensus/polybft/polybft.go @@ -205,181 +205,115 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st return err } - bridgeCfg := polyBFTConfig.Bridge - if bridgeCfg != nil { + if polyBFTConfig.IsBridgeEnabled() { // initialize BridgeStorage SC if err = initBridgeStorageContract(polyBFTConfig, transition); err != nil { return err } - // initialize Gateway SC - if err = initGatewayContract(polyBFTConfig, transition); err != nil { - return err - } - - // check if there are Bridge Allow List Admins and Bridge Block List Admins - // and if there are, get the first address as the Admin - bridgeAllowListAdmin := types.ZeroAddress - if config.Params.BridgeAllowList != nil && len(config.Params.BridgeAllowList.AdminAddresses) > 0 { - bridgeAllowListAdmin = config.Params.BridgeAllowList.AdminAddresses[0] - } - - bridgeBlockListAdmin := types.ZeroAddress - if config.Params.BridgeBlockList != nil && len(config.Params.BridgeBlockList.AdminAddresses) > 0 { - bridgeBlockListAdmin = config.Params.BridgeBlockList.AdminAddresses[0] - } + bridgeCfgMap := polyBFTConfig.Bridge + isBridgeAllowListEnabled := config.Params.IsBridgeAllowListEnabled() + isBridgeBlockListEnabled := config.Params.IsBridgeBlockListEnabled() // initialize Predicate SCs - if bridgeAllowListAdmin != types.ZeroAddress || bridgeBlockListAdmin != types.ZeroAddress { + if isBridgeAllowListEnabled || isBridgeBlockListEnabled { // The owner of the contract will be the allow list admin or the block list admin, if any of them is set. - owner := contracts.SystemCaller - useBridgeAllowList := bridgeAllowListAdmin != types.ZeroAddress - useBridgeBlockList := bridgeBlockListAdmin != types.ZeroAddress - - if bridgeAllowListAdmin != types.ZeroAddress { - owner = bridgeAllowListAdmin - } else if bridgeBlockListAdmin != types.ZeroAddress { - owner = bridgeBlockListAdmin - } + owner := config.Params.GetBridgeOwner() + useBridgeAllowList := isBridgeAllowListEnabled + useBridgeBlockList := isBridgeBlockListEnabled - for chainID := range bridgeCfg { - // initialize ChildERC20PredicateAccessList SC - input, err := getInitERC20PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, false, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } + for chainID, chainBridgeCfg := range bridgeCfgMap { + chainIDBig := new(big.Int).SetUint64(chainID) - if err = callContract(contracts.SystemCaller, contracts.ChildERC20PredicateContract, input, - "ChildERC20PredicateAccessList", transition); err != nil { + // initialize Gateway SC + if err = initGatewayContract(polyBFTConfig, chainBridgeCfg, transition, config.Genesis.Alloc); err != nil { return err } - // initialize ChildERC721PredicateAccessList SC - input, err = getInitERC721PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, false, new(big.Int).SetUint64(chainID)) - if err != nil { + // initialize ChildERC20PredicateAccessList SC + if err = initERC20ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, false, chainIDBig, + "ChildERC20PredicateAccessList"); err != nil { return err } - if err = callContract(contracts.SystemCaller, contracts.ChildERC721PredicateContract, input, - "ChildERC721PredicateAccessList", transition); err != nil { + // initialize ChildERC721PredicateAccessList SC + if err = initERC721ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, false, chainIDBig, + "ChildERC721PredicateAccessList"); err != nil { return err } // initialize ChildERC1155PredicateAccessList SC - input, err = getInitERC1155PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, false, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.ChildERC1155PredicateContract, input, - "ChildERC1155PredicateAccessList", transition); err != nil { + if err = initERC1155ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, false, chainIDBig, + "ChildERC1155PredicateAccessList"); err != nil { return err } // initialize RootMintableERC20PredicateAccessList SC - input, err = getInitERC20PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC20PredicateContract, input, - "RootERC20PredicateAccessList", transition); err != nil { + if err = initERC20ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, true, chainIDBig, + "RootERC20PredicateAccessList"); err != nil { return err } // initialize RootMintableERC721PredicateAccessList SC - input, err = getInitERC721PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC721PredicateContract, input, - "RootERC721PredicateAccessList", transition); err != nil { + if err = initERC721ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, true, chainIDBig, + "RootERC721PredicateAccessList"); err != nil { return err } // initialize RootMintableERC1155PredicateAccessList SC - input, err = getInitERC1155PredicateACLInput(bridgeCfg[chainID], owner, - useBridgeAllowList, useBridgeBlockList, true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC1155PredicateContract, input, - "RootERC1155PredicateAccessList", transition); err != nil { + if err = initERC1155ACLPredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + owner, useBridgeAllowList, useBridgeBlockList, true, chainIDBig, + "RootERC1155PredicateAccessList"); err != nil { return err } } } else { - for chainID := range bridgeCfg { - // initialize ChildERC20Predicate SC - input, err := getInitERC20PredicateInput(bridgeCfg[chainID], false, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } + for destChainID, chainBridgeCfg := range bridgeCfgMap { + destChainIDBig := new(big.Int).SetUint64(destChainID) - if err = callContract(contracts.SystemCaller, contracts.ChildERC20PredicateContract, input, - "ChildERC20Predicate", transition); err != nil { + // initialize Gateway SC + if err = initGatewayContract(polyBFTConfig, chainBridgeCfg, transition, config.Genesis.Alloc); err != nil { return err } - // initialize ChildERC721Predicate SC - input, err = getInitERC721PredicateInput(bridgeCfg[chainID], false, new(big.Int).SetUint64(chainID)) - if err != nil { + // initialize ChildERC20Predicate SC + if err = initERC20PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + false, destChainIDBig, "ChildERC20Predicate"); err != nil { return err } - if err = callContract(contracts.SystemCaller, contracts.ChildERC721PredicateContract, input, - "ChildERC721Predicate", transition); err != nil { + // initialize ChildERC721Predicate SC + if err = initERC721PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + false, destChainIDBig, "ChildERC721Predicate"); err != nil { return err } // initialize ChildERC1155Predicate SC - input, err = getInitERC1155PredicateInput(bridgeCfg[chainID], false, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.ChildERC1155PredicateContract, input, - "ChildERC1155Predicate", transition); err != nil { + if err = initERC1155PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + false, destChainIDBig, "ChildERC1155Predicate"); err != nil { return err } // initialize RootMintableERC20Predicate SC - input, err = getInitERC20PredicateInput(bridgeCfg[chainID], true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC20PredicateContract, input, - "RootERC20Predicate", transition); err != nil { + if err = initERC20PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + true, destChainIDBig, "RootERC20Predicate"); err != nil { return err } // initialize RootMintableERC721Predicate SC - input, err = getInitERC721PredicateInput(bridgeCfg[chainID], true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC721PredicateContract, input, - "RootERC721Predicate", transition); err != nil { + if err = initERC721PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + true, destChainIDBig, "RootERC721Predicate"); err != nil { return err } // initialize RootMintableERC1155Predicate SC - input, err = getInitERC1155PredicateInput(bridgeCfg[chainID], true, new(big.Int).SetUint64(chainID)) - if err != nil { - return err - } - - if err = callContract(contracts.SystemCaller, contracts.RootERC1155PredicateContract, input, - "RootERC1155Predicate", transition); err != nil { + if err = initERC1155PredicateContract(transition, chainBridgeCfg, config.Genesis.Alloc, + true, destChainIDBig, "RootERC1155Predicate"); err != nil { return err } } @@ -387,9 +321,14 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st } if polyBFTConfig.NativeTokenConfig.IsMintable { + predicateAddress := types.ZeroAddress + if bridgeCfg, exists := polyBFTConfig.Bridge[polyBFTConfig.NativeTokenConfig.ChainID]; exists { + predicateAddress = bridgeCfg.InternalERC20PredicateAddr + } + // initialize NativeERC20Mintable SC params := &contractsapi.InitializeNativeERC20MintableFn{ - Predicate_: contracts.ChildERC20PredicateContract, + Predicate_: predicateAddress, Owner_: polyBFTConfig.BladeAdmin, RootToken_: types.ZeroAddress, // in case native mintable token is used, it is always root token Name_: polyBFTConfig.NativeTokenConfig.Name, @@ -413,8 +352,8 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st Name_: polyBFTConfig.NativeTokenConfig.Name, Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, - RootToken_: polyBFTConfig.Bridge[polyBFTConfig.NativeTokenConfig.ChainID].RootNativeERC20Addr, - Predicate_: contracts.ChildERC20PredicateContract, + RootToken_: polyBFTConfig.Bridge[polyBFTConfig.NativeTokenConfig.ChainID].ExternalNativeERC20Addr, + Predicate_: polyBFTConfig.Bridge[polyBFTConfig.NativeTokenConfig.ChainID].InternalERC20PredicateAddr, TokenSupply_: initialTotalSupply, } @@ -431,7 +370,7 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st // initialize EIP1559Burn SC if isBurnContractSet { burnParams := &contractsapi.InitializeEIP1559BurnFn{ - NewChildERC20Predicate: contracts.ChildERC20PredicateContract, + NewChildERC20Predicate: polyBFTConfig.Bridge[polyBFTConfig.NativeTokenConfig.ChainID].InternalERC20PredicateAddr, NewBurnDestination: config.Params.BurnContractDestinationAddress, } diff --git a/consensus/polybft/polybft_config.go b/consensus/polybft/polybft_config.go index 71868fc7e1..4400abf9c7 100644 --- a/consensus/polybft/polybft_config.go +++ b/consensus/polybft/polybft_config.go @@ -133,72 +133,73 @@ func GetPolyBFTConfig(chainParams *chain.Params) (PolyBFTConfig, error) { // BridgeConfig is the rootchain configuration, needed for bridging type BridgeConfig struct { - GatewayAddr types.Address `json:"gatewayAddress"` - RootERC20PredicateAddr types.Address `json:"erc20PredicateAddress"` - ChildERC20PredicateAddr types.Address `json:"erc20ChildPredicateAddress"` - RootNativeERC20Addr types.Address `json:"nativeERC20Address"` - RootERC721PredicateAddr types.Address `json:"erc721PredicateAddress"` - ChildERC721PredicateAddr types.Address `json:"erc721ChildMintablePredicateAddress"` - RootERC1155PredicateAddr types.Address `json:"erc1155PredicateAddress"` - ChildERC1155PredicateAddr types.Address `json:"erc1155ChildMintablePredicateAddress"` - ChildERC20Addr types.Address `json:"childERC20Address"` - ChildERC721Addr types.Address `json:"childERC721Address"` - ChildERC1155Addr types.Address `json:"childERC1155Address"` - BladeManagerAddr types.Address `json:"bladeManagerAddress"` + // External chain bridge contracts + ExternalGatewayAddr types.Address `json:"externalGatewayAddress"` + ExternalERC20PredicateAddr types.Address `json:"externalERC20PredicateAddress"` + ExternalMintableERC20PredicateAddr types.Address `json:"externalMintableERC20PredicateAddress"` + ExternalNativeERC20Addr types.Address `json:"nativeERC20Address"` + ExternalERC721PredicateAddr types.Address `json:"externalERC721PredicateAddress"` + ExternalMintableERC721PredicateAddr types.Address `json:"externalERC721MintablePredicateAddress"` + ExternalERC1155PredicateAddr types.Address `json:"externalERC1155PredicateAddress"` + ExternalMintableERC1155PredicateAddr types.Address `json:"externalERC1155MintablePredicateAddress"` + ExternalERC20Addr types.Address `json:"externalERC20Address"` + ExternalERC721Addr types.Address `json:"externalERC721Address"` + ExternalERC1155Addr types.Address `json:"externalERC1155Address"` + BladeManagerAddr types.Address `json:"bladeManagerAddress"` // only populated if stake-manager-deploy command is executed, and used for e2e tests BLSAddress types.Address `json:"blsAddr"` BN256G2Address types.Address `json:"bn256G2Addr"` + // Blade bridge contracts + InternalGatewayAddr types.Address `json:"internalGatewayAddress"` + InternalERC20PredicateAddr types.Address `json:"internalERC20PredicateAddress"` + InternalERC721PredicateAddr types.Address `json:"internalERC721PredicateAddress"` + InternalERC1155PredicateAddr types.Address `json:"internalERC1155PredicateAddress"` + InternalMintableERC20PredicateAddr types.Address `json:"internalMintableERC20PredicateAddress"` + InternalMintableERC721PredicateAddr types.Address `json:"internalMintableERC721PredicateAddress"` + InternalMintableERC1155PredicateAddr types.Address `json:"internalMintableERC1155PredicateAddress"` + + // Event tracker JSONRPCEndpoint string `json:"jsonRPCEndpoint"` EventTrackerStartBlocks map[types.Address]uint64 `json:"eventTrackerStartBlocks"` } -func (p *PolyBFTConfig) IsBridgeEnabled() bool { - return len(p.Bridge) > 0 -} +// GetHighestInternalAddress returns the highest address among all internal bridge contracts +func (b *BridgeConfig) GetHighestInternalAddress() types.Address { + internalAddrs := b.getInternalContractAddrs() + + if len(internalAddrs) == 0 { + return types.ZeroAddress + } + + highestAddr := internalAddrs[0] -// RootchainConfig contains rootchain metadata (such as JSON RPC endpoint and contract addresses) -type RootchainConfig struct { - JSONRPCAddr string - - Gateway types.Address - BLSAddress types.Address - BN256G2Address types.Address - RootERC20PredicateAddress types.Address - ChildERC20PredicateAddress types.Address - RootNativeERC20Address types.Address - ChildERC20Address types.Address - RootERC721PredicateAddress types.Address - ChildERC721PredicateAddress types.Address - ChildERC721Address types.Address - RootERC1155PredicateAddress types.Address - ChildERC1155PredicateAddress types.Address - ChildERC1155Address types.Address - BladeManagerAddress types.Address + for _, addr := range internalAddrs[1:] { + if addr.Compare(highestAddr) > 0 { + highestAddr = addr + } + } + + return highestAddr } -// ToBridgeConfig creates BridgeConfig instance -func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { - return &BridgeConfig{ - JSONRPCEndpoint: r.JSONRPCAddr, - - GatewayAddr: r.Gateway, - RootERC20PredicateAddr: r.RootERC20PredicateAddress, - ChildERC20PredicateAddr: r.ChildERC20PredicateAddress, - RootNativeERC20Addr: r.RootNativeERC20Address, - RootERC721PredicateAddr: r.RootERC721PredicateAddress, - ChildERC721PredicateAddr: r.ChildERC721PredicateAddress, - RootERC1155PredicateAddr: r.RootERC1155PredicateAddress, - ChildERC1155PredicateAddr: r.ChildERC1155PredicateAddress, - ChildERC20Addr: r.ChildERC20Address, - ChildERC721Addr: r.ChildERC721Address, - ChildERC1155Addr: r.ChildERC1155Address, - BLSAddress: r.BLSAddress, - BN256G2Address: r.BN256G2Address, - BladeManagerAddr: r.BladeManagerAddress, +// getInternalContractAddrs enumerates all the Internal bridge contract addresses +func (b *BridgeConfig) getInternalContractAddrs() []types.Address { + return []types.Address{ + b.InternalGatewayAddr, + b.InternalERC20PredicateAddr, + b.InternalERC721PredicateAddr, + b.InternalERC1155PredicateAddr, + b.InternalMintableERC20PredicateAddr, + b.InternalMintableERC721PredicateAddr, + b.InternalMintableERC1155PredicateAddr, } } +func (p *PolyBFTConfig) IsBridgeEnabled() bool { + return len(p.Bridge) > 0 +} + // TokenConfig is the configuration of native token used by edge network type TokenConfig struct { Name string `json:"name"` diff --git a/consensus/polybft/polybft_config_test.go b/consensus/polybft/polybft_config_test.go new file mode 100644 index 0000000000..415c8b5ffe --- /dev/null +++ b/consensus/polybft/polybft_config_test.go @@ -0,0 +1,48 @@ +package polybft + +import ( + "reflect" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/0xPolygon/polygon-edge/types" +) + +// TestBridgeConfig_getInternalContractAddrs ensures that all fields in BridgeConfig whose name starts with "Internal" are returned. +func TestBridgeConfig_getInternalContractAddrs(t *testing.T) { + // Mock addresses for testing + mockAddr := types.Address{0x1} + + // Initialize a BridgeConfig struct with all Internal fields set to mockAddr + config := &BridgeConfig{ + InternalGatewayAddr: mockAddr, + InternalERC20PredicateAddr: mockAddr, + InternalERC721PredicateAddr: mockAddr, + InternalERC1155PredicateAddr: mockAddr, + InternalMintableERC20PredicateAddr: mockAddr, + InternalMintableERC721PredicateAddr: mockAddr, + InternalMintableERC1155PredicateAddr: mockAddr, + } + + // Get internal contract addresses from the function + internalAddrs := config.getInternalContractAddrs() + + // Use reflection to find all fields that start with "Internal" and are of type `types.Address` + var ( + expectedAddrs []types.Address + val = reflect.ValueOf(config).Elem() + typ = reflect.TypeOf(*config) + ) + + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + if strings.HasPrefix(field.Name, "Internal") && field.Type == reflect.TypeOf(types.Address{}) { + expectedAddrs = append(expectedAddrs, val.Field(i).Interface().(types.Address)) + } + } + + // Ensure that the function output matches the expected addresses derived from reflection + assert.ElementsMatch(t, expectedAddrs, internalAddrs, "The internal contract addresses should match the expected internal addresses") +} diff --git a/consensus/polybft/sc_integration_test.go b/consensus/polybft/sc_integration_test.go index da1d14f856..eb074ca544 100644 --- a/consensus/polybft/sc_integration_test.go +++ b/consensus/polybft/sc_integration_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/0xPolygon/polygon-edge/chain" @@ -16,7 +15,6 @@ import ( "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/hex" - "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" ) @@ -150,21 +148,3 @@ func TestIntegration_CommitEpoch(t *testing.T) { t.Logf("Number of validators %d on commit epoch, Gas used %+v\n", accSet.Len(), result.GasUsed) } } - -func deployAndInitContract(t *testing.T, transition *state.Transition, bytecode []byte, sender types.Address, - initCallback func() ([]byte, error)) types.Address { - t.Helper() - - deployResult := transition.Create2(sender, bytecode, big.NewInt(0), 1e9) - assert.NoError(t, deployResult.Err) - - if initCallback != nil { - initInput, err := initCallback() - require.NoError(t, err) - - result := transition.Call2(sender, deployResult.Address, initInput, big.NewInt(0), 1e9) - require.NoError(t, result.Err) - } - - return deployResult.Address -} diff --git a/consensus/polybft/state_store_bridge_message_test.go b/consensus/polybft/state_store_bridge_message_test.go index ab3cd772eb..2958cc7629 100644 --- a/consensus/polybft/state_store_bridge_message_test.go +++ b/consensus/polybft/state_store_bridge_message_test.go @@ -284,17 +284,6 @@ func insertTestBridgeBatches(t *testing.T, state *State, numberOfBatches uint64) } } -func createTestBridgeMessageEvent(index int64) *contractsapi.BridgeMsgEvent { - return &contractsapi.BridgeMsgEvent{ - ID: big.NewInt(index), - Sender: types.ZeroAddress, - Receiver: types.ZeroAddress, - Data: []byte{0, 1}, - SourceChainID: big.NewInt(1), - DestinationChainID: bigZero, - } -} - func TestState_StateSync_StateSyncRelayerDataAndEvents(t *testing.T) { t.Parallel() diff --git a/consensus/polybft/state_store_governance_test.go b/consensus/polybft/state_store_governance_test.go index 3290c68e02..bd043bf0e0 100644 --- a/consensus/polybft/state_store_governance_test.go +++ b/consensus/polybft/state_store_governance_test.go @@ -154,19 +154,19 @@ func createTestPolybftConfig() *PolyBFTConfig { }, }, Bridge: map[uint64]*BridgeConfig{0: { - GatewayAddr: types.StringToAddress("0xGatewayAddr"), - RootERC20PredicateAddr: types.StringToAddress("0xRootERC20PredicateAddr"), - ChildERC20PredicateAddr: types.StringToAddress("0xChildMintableERC20PredicateAddr"), - RootERC721PredicateAddr: types.StringToAddress("0xRootERC721PredicateAddr"), - ChildERC721PredicateAddr: types.StringToAddress("0xChildMintableERC721PredicateAddr"), - RootERC1155PredicateAddr: types.StringToAddress("0xRootERC1155PredicateAddr"), - ChildERC1155PredicateAddr: types.StringToAddress("0xChildMintableERC1155PredicateAddr"), - ChildERC20Addr: types.StringToAddress("0xChildERC20Addr"), - ChildERC721Addr: types.StringToAddress("0xChildERC721Addr"), - ChildERC1155Addr: types.StringToAddress("0xChildERC1155Addr"), - BLSAddress: types.StringToAddress("0xBLSAddress"), - BN256G2Address: types.StringToAddress("0xBN256G2Address"), - JSONRPCEndpoint: "http://mumbai-rpc.com", + ExternalGatewayAddr: types.StringToAddress("0xGatewayAddr"), + ExternalERC20PredicateAddr: types.StringToAddress("0xRootERC20PredicateAddr"), + ExternalMintableERC20PredicateAddr: types.StringToAddress("0xChildMintableERC20PredicateAddr"), + ExternalERC721PredicateAddr: types.StringToAddress("0xRootERC721PredicateAddr"), + ExternalMintableERC721PredicateAddr: types.StringToAddress("0xChildMintableERC721PredicateAddr"), + ExternalERC1155PredicateAddr: types.StringToAddress("0xRootERC1155PredicateAddr"), + ExternalMintableERC1155PredicateAddr: types.StringToAddress("0xChildMintableERC1155PredicateAddr"), + ExternalERC20Addr: types.StringToAddress("0xChildERC20Addr"), + ExternalERC721Addr: types.StringToAddress("0xChildERC721Addr"), + ExternalERC1155Addr: types.StringToAddress("0xChildERC1155Addr"), + BLSAddress: types.StringToAddress("0xBLSAddress"), + BN256G2Address: types.StringToAddress("0xBN256G2Address"), + JSONRPCEndpoint: "http://mumbai-rpc.com", EventTrackerStartBlocks: map[types.Address]uint64{ types.StringToAddress("SomeRootAddress"): 365_000, }}, diff --git a/consensus/polybft/state_sync_relayer.go b/consensus/polybft/state_sync_relayer.go index d61f776fc6..3db3143be3 100644 --- a/consensus/polybft/state_sync_relayer.go +++ b/consensus/polybft/state_sync_relayer.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -144,11 +143,12 @@ func (ssr stateSyncRelayerImpl) sendTx(events []*RelayerEventMetaData) error { // and the value is a slice of signatures of events we want to get. // This function is the implementation of EventSubscriber interface func (ssr *stateSyncRelayerImpl) GetLogFilters() map[types.Address][]types.Hash { - return map[types.Address][]types.Hash{ - contracts.GatewayContract: { - types.Hash(new(contractsapi.BridgeMessageResultEvent).Sig()), - }, - } + // return map[types.Address][]types.Hash{ + // contracts.GatewayContract: { + // types.Hash(new(contractsapi.BridgeMessageResultEvent).Sig()), + // }, + // } + return nil } // ProcessLog is the implementation of EventSubscriber interface, diff --git a/consensus/polybft/validator/validator_metadata.go b/consensus/polybft/validator/validator_metadata.go index e086ea893d..51f4bab660 100644 --- a/consensus/polybft/validator/validator_metadata.go +++ b/consensus/polybft/validator/validator_metadata.go @@ -235,7 +235,7 @@ func (as AccountSet) Copy() AccountSet { // Hash returns hash value of the AccountSet func (as AccountSet) Hash() (types.Hash, error) { - abiEncoded, err := accountSetABIType.Encode([]interface{}{as.ToAPIBinding()}) + abiEncoded, err := accountSetABIType.Encode([]interface{}{as.ToABIBinding()}) if err != nil { return types.ZeroHash, err } @@ -243,8 +243,8 @@ func (as AccountSet) Hash() (types.Hash, error) { return types.BytesToHash(crypto.Keccak256(abiEncoded)), nil } -// ToAPIBinding converts AccountSet to slice of contract api stubs to be encoded -func (as AccountSet) ToAPIBinding() []*contractsapi.Validator { +// ToABIBinding converts AccountSet to slice of contract ABI stubs to be encoded +func (as AccountSet) ToABIBinding() []*contractsapi.Validator { apiBinding := make([]*contractsapi.Validator, len(as)) for i, v := range as { apiBinding[i] = &contractsapi.Validator{ diff --git a/consensus/polybft/validator/validator_set.go b/consensus/polybft/validator/validator_set.go index 7e935f8523..232b6a0029 100644 --- a/consensus/polybft/validator/validator_set.go +++ b/consensus/polybft/validator/validator_set.go @@ -67,7 +67,7 @@ func (vs validatorSet) HasQuorum(blockNumber uint64, signers map[types.Address]s } } - quorumSize := getQuorumSize(blockNumber, vs.totalVotingPower) + quorumSize := getQuorumSize(vs.totalVotingPower) hasQuorum := aggregateVotingPower.Cmp(quorumSize) >= 0 vs.logger.Debug("HasQuorum", @@ -105,7 +105,7 @@ func (vs validatorSet) TotalVotingPower() big.Int { } // getQuorumSize calculates quorum size as 2/3 super-majority of provided total voting power -func getQuorumSize(blockNumber uint64, totalVotingPower *big.Int) *big.Int { +func getQuorumSize(totalVotingPower *big.Int) *big.Int { quorum := new(big.Int) quorum.Mul(totalVotingPower, big.NewInt(2)) diff --git a/consensus/polybft/validator/validator_set_test.go b/consensus/polybft/validator/validator_set_test.go index 82d18bff82..4653f5c7e0 100644 --- a/consensus/polybft/validator/validator_set_test.go +++ b/consensus/polybft/validator/validator_set_test.go @@ -47,7 +47,7 @@ func TestValidatorSet_getQuorumSize(t *testing.T) { } for _, c := range cases { - quorumSize := getQuorumSize(1, big.NewInt(c.totalVotingPower)) + quorumSize := getQuorumSize(big.NewInt(c.totalVotingPower)) require.Equal(t, c.expectedQuorumSize, quorumSize.Int64()) } } diff --git a/contracts/system_addresses.go b/contracts/system_addresses.go index b927666513..513250a016 100644 --- a/contracts/system_addresses.go +++ b/contracts/system_addresses.go @@ -12,83 +12,57 @@ var ( // BLSContractV1 is an address of BLS contract on the child chain BLSContractV1 = types.StringToAddress("0x1021") // RewardTokenContract is an address of reward token proxy on child chain - RewardTokenContract = types.StringToAddress("0x104") + RewardTokenContract = types.StringToAddress("0x103") // RewardTokenContractV1 is an address of reward token on child chain - RewardTokenContractV1 = types.StringToAddress("0x1041") + RewardTokenContractV1 = types.StringToAddress("0x1031") // BLS256Contract is an address of BLS256 proxy contract on the child chain - BLS256Contract = types.StringToAddress("0x105") + BLS256Contract = types.StringToAddress("0x104") // BLS256ContractV1 is an address of BLS256 contract on the child chain - BLS256ContractV1 = types.StringToAddress("0x1051") + BLS256ContractV1 = types.StringToAddress("0x1041") // DefaultBurnContract is an address of eip1559 default proxy contract - DefaultBurnContract = types.StringToAddress("0x106") + DefaultBurnContract = types.StringToAddress("0x105") // NativeERC20TokenContract is an address of bridge proxy contract // (used for transferring ERC20 native tokens on child chain) - NativeERC20TokenContract = types.StringToAddress("0x1010") + NativeERC20TokenContract = types.StringToAddress("0x106") // NativeERC20TokenContractV1 is an address of bridge contract // (used for transferring ERC20 native tokens on child chain) - NativeERC20TokenContractV1 = types.StringToAddress("0x10101") + NativeERC20TokenContractV1 = types.StringToAddress("0x1061") // StakeManagerContract is an address of stake manager proxy contract on child chain - StakeManagerContract = types.StringToAddress("0x10022") + StakeManagerContract = types.StringToAddress("0x107") // StakeManagerContract is an address of stake manager contract on child chain - StakeManagerContractV1 = types.StringToAddress("0x100221") - // GatewayCotnract is an address of gateway proxy contract - GatewayContract = types.StringToAddress("0x10032") - // GatewayCotnractV1 is an address of gateway contract - GatewayContractV1 = types.StringToAddress("0x100321") + StakeManagerContractV1 = types.StringToAddress("0x1071") // BridgeStorageContract is an address of bridge storage proxy contract - BridgeStorageContract = types.StringToAddress("0x10033") + BridgeStorageContract = types.StringToAddress("0x108") // BridgeStorageContractV1 is an address of bridge storage contract on child chain - BridgeStorageContractV1 = types.StringToAddress("0x100331") + BridgeStorageContractV1 = types.StringToAddress("0x1081") - // ChildERC20Contract is an address of bridgable ERC20 token contract on the child chain + // ChildERC20Contract is an address of ERC20 token template ChildERC20Contract = types.StringToAddress("0x1003") - // ChildERC20PredicateContract is an address of child ERC20 proxy predicate contract on the child chain - ChildERC20PredicateContract = types.StringToAddress("0x1004") - // ChildERC20PredicateContractV1 is an address of child ERC20 predicate contract on the child chain - ChildERC20PredicateContractV1 = types.StringToAddress("0x10041") - // ChildERC721Contract is an address of bridgable ERC721 token contract on the child chain - ChildERC721Contract = types.StringToAddress("0x1005") - // ChildERC721PredicateContract is an address of child ERC721 proxy predicate contract on the child chain - ChildERC721PredicateContract = types.StringToAddress("0x1006") - // ChildERC721PredicateContractV1 is an address of child ERC721 predicate contract on the child chain - ChildERC721PredicateContractV1 = types.StringToAddress("0x10061") - // ChildERC1155Contract is an address of bridgable ERC1155 token contract on the child chain - ChildERC1155Contract = types.StringToAddress("0x1007") - // ChildERC1155PredicateContract is an address of child ERC1155 proxy predicate contract on the child chain - ChildERC1155PredicateContract = types.StringToAddress("0x1008") - // ChildERC1155PredicateContractV1 is an address of child ERC1155 predicate contract on the child chain - ChildERC1155PredicateContractV1 = types.StringToAddress("0x10081") - // RootMintableERC20PredicateContract is an address of mintable ERC20 proxy predicate on the child chain - RootERC20PredicateContract = types.StringToAddress("0x1009") - // RootMintableERC20PredicateContractV1 is an address of mintable ERC20 predicate on the child chain - RootERC20PredicateContractV1 = types.StringToAddress("0x10091") - // RootMintableERC721PredicateContract is an address of mintable ERC721 proxy predicate on the child chain - RootERC721PredicateContract = types.StringToAddress("0x100a") - // RootMintableERC721PredicateContractV1 is an address of mintable ERC721 predicate on the child chain - RootERC721PredicateContractV1 = types.StringToAddress("0x100a1") - // RootMintableERC1155PredicateContract is an address of mintable ERC1155 proxy predicate on the child chain - RootERC1155PredicateContract = types.StringToAddress("0x100b") - // RootMintableERC1155PredicateContractV1 is an address of mintable ERC1155 predicate on the child chain - RootERC1155PredicateContractV1 = types.StringToAddress("0x100b1") + // ChildERC721Contract is an address of ERC721 token template + ChildERC721Contract = types.StringToAddress("0x1004") + // ChildERC1155Contract is an address of ERC1155 token template + ChildERC1155Contract = types.StringToAddress("0x1005") + + ChildBridgeContractsBaseAddress = types.StringToAddress("0x5006") // Governance contracts =============================================================================== // ChildGovernorContract is the proxy address of main governance contract - ChildGovernorContract = types.StringToAddress("0x100c") + ChildGovernorContract = types.StringToAddress("0x10a") // ChildGovernorContract is an address of main governance contract - ChildGovernorContractV1 = types.StringToAddress("0x100c1") + ChildGovernorContractV1 = types.StringToAddress("0x10a1") // ChildTimelockContract is the proxy address of timelock contract used by the governor contract - ChildTimelockContract = types.StringToAddress("0x100d") + ChildTimelockContract = types.StringToAddress("0x10b") // ChildTimelockContract is an address of timelock contract used by the governor contract - ChildTimelockContractV1 = types.StringToAddress("0x100d1") + ChildTimelockContractV1 = types.StringToAddress("0x10b1") // NetworkParamsContract is the proxy address of NetworkParams contract which holds network config params - NetworkParamsContract = types.StringToAddress("0x100e") + NetworkParamsContract = types.StringToAddress("0x10c") // NetworkParamsContract is an address of NetworkParams contract which holds network config params - NetworkParamsContractV1 = types.StringToAddress("0x100e1") + NetworkParamsContractV1 = types.StringToAddress("0x10c1") // ForkParamsContract is an address of ForkParams contract which holds data of enabled forks - ForkParamsContract = types.StringToAddress("0x100f") + ForkParamsContract = types.StringToAddress("0x10d") // ForkParamsContract is the proxy address of ForkParams contract which holds data of enabled forks - ForkParamsContractV1 = types.StringToAddress("0x100f1") + ForkParamsContractV1 = types.StringToAddress("0x10d1") // SystemCaller is address of account, used for system calls to smart contracts SystemCaller = types.StringToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") @@ -114,21 +88,16 @@ var ( // GetProxyImplementationMapping retrieves the addresses of proxy contracts that should be deployed unconditionally func GetProxyImplementationMapping() map[types.Address]types.Address { return map[types.Address]types.Address{ - GatewayContract: GatewayContractV1, - BridgeStorageContract: BridgeStorageContractV1, - BLSContract: BLSContractV1, - EpochManagerContract: EpochManagerContractV1, - StakeManagerContract: StakeManagerContractV1, - NativeERC20TokenContract: NativeERC20TokenContractV1, - ChildERC20PredicateContract: ChildERC20PredicateContractV1, - ChildERC721PredicateContract: ChildERC721PredicateContractV1, - ChildERC1155PredicateContract: ChildERC1155PredicateContractV1, - NetworkParamsContract: NetworkParamsContractV1, - ForkParamsContract: ForkParamsContractV1, - ChildTimelockContract: ChildTimelockContractV1, - ChildGovernorContract: ChildGovernorContractV1, - GatewayContract: GatewayContractV1, - BridgeStorageContract: BridgeStorageContractV1, - BLS256Contract: BLS256ContractV1, + BridgeStorageContract: BridgeStorageContractV1, + BLSContract: BLSContractV1, + EpochManagerContract: EpochManagerContractV1, + StakeManagerContract: StakeManagerContractV1, + NativeERC20TokenContract: NativeERC20TokenContractV1, + NetworkParamsContract: NetworkParamsContractV1, + ForkParamsContract: ForkParamsContractV1, + ChildTimelockContract: ChildTimelockContractV1, + ChildGovernorContract: ChildGovernorContractV1, + BridgeStorageContract: BridgeStorageContractV1, + BLS256Contract: BLS256ContractV1, } } diff --git a/e2e-polybft/e2e/bridge_test.go b/e2e-polybft/e2e/bridge_test.go index 4007eda122..6da12888a6 100644 --- a/e2e-polybft/e2e/bridge_test.go +++ b/e2e-polybft/e2e/bridge_test.go @@ -99,6 +99,8 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { chainID, err := rootchainTxRelayer.Client().ChainID() require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(childEthEndpoint)) require.NoError(t, err) @@ -129,7 +131,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { cluster.Bridge.Deposit( common.ERC20, rootERC20Token, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), strings.Join(amounts[:], ","), @@ -153,7 +155,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { // get child token address childERC20Token := getChildToken(t, contractsapi.RootERC20Predicate.Abi, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, rootERC20Token, rootchainTxRelayer) + bridgeCfg.ExternalERC20PredicateAddr, rootERC20Token, rootchainTxRelayer) // check receivers balances got increased by deposited amount for _, receiver := range receivers { @@ -175,7 +177,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { amounts[i], "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, childERC20Token, false) require.NoError(t, err) @@ -219,7 +221,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { require.NoError(t, cluster.Bridge.Deposit( common.ERC20, rootERC20Token, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:depositsSubset], ","), strings.Join(amounts[:depositsSubset], ","), @@ -235,7 +237,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { // check that we submitted the minimal commitment to smart contract commitmentIDRaw, err = txRelayer.Call(types.ZeroAddress, - contracts.GatewayContract, lastCommittedIDInput) + bridgeCfg.InternalGatewayAddr, lastCommittedIDInput) require.NoError(t, err) lastCommittedID, err := helperCommon.ParseUint64orHex(&commitmentIDRaw) @@ -246,7 +248,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { require.NoError(t, cluster.Bridge.Deposit( common.ERC20, rootERC20Token, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[depositsSubset:], ","), strings.Join(amounts[depositsSubset:], ","), @@ -261,7 +263,7 @@ func TestE2E_Bridge_RootchainTokensTransfers(t *testing.T) { require.NoError(t, cluster.WaitForBlock(midBlockNumber+5*sprintSize, 3*time.Minute)) // check that we submitted the minimal commitment to smart contract - commitmentIDRaw, err = txRelayer.Call(types.ZeroAddress, contracts.GatewayContract, lastCommittedIDInput) + commitmentIDRaw, err = txRelayer.Call(types.ZeroAddress, bridgeCfg.InternalGatewayAddr, lastCommittedIDInput) require.NoError(t, err) // check that the second (larger commitment) was also submitted in epoch @@ -330,6 +332,8 @@ func TestE2E_Bridge_ERC721Transfer(t *testing.T) { chainID, err := rootchainTxRelayer.Client().ChainID() require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + rootchainDeployer, err := bridgeHelper.DecodePrivateKey("") require.NoError(t, err) @@ -353,7 +357,7 @@ func TestE2E_Bridge_ERC721Transfer(t *testing.T) { cluster.Bridge.Deposit( common.ERC721, rootERC721Addr, - polybftCfg.Bridge[chainID.Uint64()].RootERC721PredicateAddr, + bridgeCfg.ExternalERC721PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), "", @@ -392,9 +396,9 @@ func TestE2E_Bridge_ERC721Transfer(t *testing.T) { require.NoError(t, err) // retrieve child token address (from both chains, and assert they are the same) - l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC721Predicate.Abi, polybftCfg.Bridge[chainID.Uint64()].RootERC721PredicateAddr, + l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC721Predicate.Abi, bridgeCfg.ExternalERC721PredicateAddr, rootERC721Addr, rootchainTxRelayer) - l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC721Predicate.Abi, contracts.ChildERC721PredicateContract, + l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC721Predicate.Abi, bridgeCfg.InternalERC721PredicateAddr, rootERC721Addr, txRelayer) t.Log("L1 child token", l1ChildTokenAddr) @@ -418,7 +422,7 @@ func TestE2E_Bridge_ERC721Transfer(t *testing.T) { "", tokenIDs[i], validatorSrv.JSONRPCAddr(), - contracts.ChildERC721PredicateContract, + bridgeCfg.InternalERC721PredicateAddr, l2ChildTokenAddr, false) require.NoError(t, err) @@ -494,6 +498,8 @@ func TestE2E_Bridge_ERC1155Transfer(t *testing.T) { chainID, err := rootchainTxRelayer.Client().ChainID() require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + rootchainDeployer, err := bridgeHelper.DecodePrivateKey("") require.NoError(t, err) @@ -517,7 +523,7 @@ func TestE2E_Bridge_ERC1155Transfer(t *testing.T) { cluster.Bridge.Deposit( common.ERC1155, rootERC1155Addr, - polybftCfg.Bridge[chainID.Uint64()].RootERC1155PredicateAddr, + bridgeCfg.ExternalERC1155PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), strings.Join(amounts[:], ","), @@ -556,9 +562,9 @@ func TestE2E_Bridge_ERC1155Transfer(t *testing.T) { require.NoError(t, err) // retrieve child token address - l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC1155Predicate.Abi, polybftCfg.Bridge[chainID.Uint64()].RootERC1155PredicateAddr, + l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC1155Predicate.Abi, bridgeCfg.ExternalERC1155PredicateAddr, rootERC1155Addr, rootchainTxRelayer) - l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC1155Predicate.Abi, contracts.ChildERC1155PredicateContract, + l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC1155Predicate.Abi, bridgeCfg.InternalERC1155PredicateAddr, rootERC1155Addr, txRelayer) t.Log("L1 child token", l1ChildTokenAddr) @@ -600,7 +606,7 @@ func TestE2E_Bridge_ERC1155Transfer(t *testing.T) { amounts[i], tokenIDs[i], validatorSrv.JSONRPCAddr(), - contracts.ChildERC1155PredicateContract, + bridgeCfg.InternalERC1155PredicateAddr, l2ChildTokenAddr, false) require.NoError(t, err) @@ -688,6 +694,8 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { chainID, err := rootchainTxRelayer.Client().ChainID() require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + childchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(childEthEndpoint)) require.NoError(t, err) @@ -703,7 +711,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { err = cluster.Bridge.Deposit( common.ERC20, rootToken, - contracts.RootERC20PredicateContract, + bridgeCfg.InternalMintableERC20PredicateAddr, depositorKeys[0], depositors[0].String(), amounts[0], @@ -722,7 +730,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { err = cluster.Bridge.Deposit( common.ERC20, rootToken, - contracts.RootERC20PredicateContract, + bridgeCfg.InternalMintableERC20PredicateAddr, key, depositors[i].String(), amounts[i], @@ -734,9 +742,9 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { } // retrieve child mintable token address from both chains and make sure they are the same - l1ChildToken := getChildToken(t, contractsapi.ChildERC20Predicate.Abi, polybftCfg.Bridge[chainID.Uint64()].ChildERC20PredicateAddr, + l1ChildToken := getChildToken(t, contractsapi.ChildERC20Predicate.Abi, bridgeCfg.ExternalMintableERC20PredicateAddr, rootToken, rootchainTxRelayer) - l2ChildToken := getChildToken(t, contractsapi.RootERC20Predicate.Abi, contracts.RootERC20PredicateContract, + l2ChildToken := getChildToken(t, contractsapi.RootERC20Predicate.Abi, bridgeCfg.InternalMintableERC20PredicateAddr, rootToken, childchainTxRelayer) t.Log("L1 child token", l1ChildToken) @@ -764,7 +772,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { amounts[i], "", cluster.Bridge.JSONRPCAddr(), - polybftCfg.Bridge[chainID.Uint64()].ChildERC20PredicateAddr, + bridgeCfg.ExternalMintableERC20PredicateAddr, l1ChildToken, true) require.NoError(t, err) @@ -819,7 +827,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { err = cluster.Bridge.Deposit( common.ERC721, rootERC721Token, - contracts.RootERC721PredicateContract, + bridgeCfg.InternalMintableERC721PredicateAddr, depositorKeys[0], depositors[0].String(), "", @@ -837,7 +845,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { err = cluster.Bridge.Deposit( common.ERC721, types.Address(rootERC721Token), - contracts.RootERC721PredicateContract, + bridgeCfg.InternalMintableERC721PredicateAddr, depositorKey, depositors[i].String(), "", @@ -849,9 +857,9 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { } // retrieve child token addresses on both chains and make sure they are the same - l1ChildToken := getChildToken(t, contractsapi.ChildERC721Predicate.Abi, polybftCfg.Bridge[chainID.Uint64()].ChildERC721PredicateAddr, + l1ChildToken := getChildToken(t, contractsapi.ChildERC721Predicate.Abi, bridgeCfg.ExternalMintableERC721PredicateAddr, types.Address(rootERC721Token), rootchainTxRelayer) - l2ChildToken := getChildToken(t, contractsapi.RootERC721Predicate.Abi, contracts.RootERC721PredicateContract, + l2ChildToken := getChildToken(t, contractsapi.RootERC721Predicate.Abi, bridgeCfg.InternalMintableERC721PredicateAddr, types.Address(rootERC721Token), childchainTxRelayer) t.Log("L1 child token", l1ChildToken) @@ -874,7 +882,7 @@ func TestE2E_Bridge_ChildchainTokensTransfer(t *testing.T) { "", fmt.Sprintf("%d", i), cluster.Bridge.JSONRPCAddr(), - polybftCfg.Bridge[chainID.Uint64()].ChildERC721PredicateAddr, + polybftCfg.Bridge[chainID.Uint64()].ExternalMintableERC721PredicateAddr, l1ChildToken, true) require.NoError(t, err) @@ -970,6 +978,8 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { chainID, err := rootchainTxRelayer.Client().ChainID() require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + deployerKey, err := bridgeHelper.DecodePrivateKey("") require.NoError(t, err) @@ -993,7 +1003,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { cluster.Bridge.Deposit( common.ERC20, rootERC20Token, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join(receivers[:], ","), strings.Join(depositAmounts[:], ","), @@ -1019,7 +1029,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { // get child token address childERC20Token := getChildToken(t, contractsapi.RootERC20Predicate.Abi, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, rootERC20Token, rootchainTxRelayer) + bridgeCfg.ExternalERC20PredicateAddr, rootERC20Token, rootchainTxRelayer) for _, receiver := range receivers { balance := erc20BalanceOf(t, types.StringToAddress(receiver), childERC20Token, relayer) @@ -1041,7 +1051,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { strings.Join(withdrawAmounts[:], ","), "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, childERC20Token, false) require.Error(t, err) @@ -1057,7 +1067,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { strings.Join(withdrawAmounts[:], ","), "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, childERC20Token, false) require.NoError(t, err) @@ -1073,7 +1083,7 @@ func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { strings.Join(withdrawAmounts[:], ","), "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, contracts.NativeERC20TokenContract, false) require.ErrorContains(t, err, "failed to send withdraw transaction") @@ -1170,6 +1180,8 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) + bridgeCfg := polybftCfg.Bridge[chainID.Uint64()] + checkBalancesFn := func(address types.Address, rootExpected, childExpected *big.Int, isValidator bool) { offset := ethgo.Gwei(100) expectedValue := new(big.Int) @@ -1178,7 +1190,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { "Root expected", rootExpected, "Child Expected", childExpected) balance := erc20BalanceOf(t, address, - polybftCfg.Bridge[chainID.Uint64()].RootNativeERC20Addr, rootchainTxRelayer) + bridgeCfg.ExternalNativeERC20Addr, rootchainTxRelayer) t.Log("Balance of native ERC20 token on root", balance, "Address", address) require.Equal(t, rootExpected, balance) @@ -1231,7 +1243,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { tokensToTransfer.String(), "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, contracts.NativeERC20TokenContract, false) require.NoError(t, err) @@ -1250,7 +1262,7 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { tokensToTransfer.String(), "", validatorSrv.JSONRPCAddr(), - contracts.ChildERC20PredicateContract, + bridgeCfg.InternalERC20PredicateAddr, contracts.NativeERC20TokenContract, false) require.NoError(t, err) @@ -1282,8 +1294,8 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge[chainID.Uint64()].RootNativeERC20Addr, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalNativeERC20Addr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join([]string{validatorAcc.Address().String(), nonValidatorKey.Address().String()}, ","), strings.Join([]string{tokensToTransfer.String(), tokensToTransfer.String()}, ","), @@ -1329,8 +1341,8 @@ func TestE2E_Bridge_NonMintableERC20Token_WithPremine(t *testing.T) { require.NoError(t, cluster.Bridge.Deposit( common.ERC20, - polybftCfg.Bridge[chainID.Uint64()].RootNativeERC20Addr, - polybftCfg.Bridge[chainID.Uint64()].RootERC20PredicateAddr, + bridgeCfg.ExternalNativeERC20Addr, + bridgeCfg.ExternalERC20PredicateAddr, bridgeHelper.TestAccountPrivKey, strings.Join([]string{nonValidatorKey.Address().String()}, ","), strings.Join([]string{tenMilionTokens.String()}, ","), diff --git a/e2e-polybft/e2e/helpers_test.go b/e2e-polybft/e2e/helpers_test.go index 7faa5c7a13..3676f009e2 100644 --- a/e2e-polybft/e2e/helpers_test.go +++ b/e2e-polybft/e2e/helpers_test.go @@ -210,20 +210,3 @@ func getChildToken(t *testing.T, predicateABI *abi.ABI, predicateAddr types.Addr return types.StringToAddress(childTokenRaw) } - -func getLastBridgeMsgEventID(t *testing.T, relayer txrelayer.TxRelayer) uint64 { - t.Helper() - - bridgeMsgEventsCounterFn := contractsapi.Gateway.Abi.Methods["counter"] - - input, err := bridgeMsgEventsCounterFn.Encode([]interface{}{}) - require.NoError(t, err) - - bridgeMsgEventIDRaw, err := relayer.Call(types.ZeroAddress, contracts.GatewayContract, input) - require.NoError(t, err) - - exitEventID, err := common.ParseUint64orHex(&bridgeMsgEventIDRaw) - require.NoError(t, err) - - return exitEventID -} diff --git a/e2e-polybft/framework/test-bridge.go b/e2e-polybft/framework/test-bridge.go index af775c11d0..e120eb4974 100644 --- a/e2e-polybft/framework/test-bridge.go +++ b/e2e-polybft/framework/test-bridge.go @@ -411,7 +411,7 @@ func (t *TestBridge) mintNativeRootToken(validatorAddresses []types.Address, tok args := []string{ "mint-erc20", "--jsonrpc", t.JSONRPCAddr(), - "--erc20-token", polybftConfig.Bridge[tokenConfig.ChainID].RootNativeERC20Addr.String(), + "--erc20-token", polybftConfig.Bridge[tokenConfig.ChainID].ExternalNativeERC20Addr.String(), } // mint something for every validator @@ -464,7 +464,7 @@ func (t *TestBridge) premineNativeRootToken(genesisPath string, tokenConfig *pol "--jsonrpc", t.JSONRPCAddr(), "--premine-amount", premineAmount.String(), "--stake-amount", stakedAmount.String(), - "--erc20-token", bridgeConfig.RootNativeERC20Addr.String(), + "--erc20-token", bridgeConfig.ExternalNativeERC20Addr.String(), "--genesis", genesisPath, } diff --git a/types/types.go b/types/types.go index d6a04b9197..2560a25e3b 100644 --- a/types/types.go +++ b/types/types.go @@ -48,6 +48,25 @@ var ( type Hash [HashLength]byte +func (h Hash) Bytes() []byte { + return h[:] +} + +func (h Hash) String() string { + return hex.EncodeToHex(h[:]) +} + +// UnmarshalText parses a hash in hex syntax. +func (h *Hash) UnmarshalText(input []byte) error { + *h = BytesToHash(StringToBytes(string(input))) + + return nil +} + +func (h Hash) MarshalText() ([]byte, error) { + return []byte(h.String()), nil +} + type Address [AddressLength]byte func min(i, j int) int { @@ -69,14 +88,6 @@ func BytesToHash(b []byte) Hash { return h } -func (h Hash) Bytes() []byte { - return h[:] -} - -func (h Hash) String() string { - return hex.EncodeToHex(h[:]) -} - // checksumEncode returns the checksummed address with 0x prefix, as by EIP-55 // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md func (a Address) checksumEncode() string { @@ -114,6 +125,55 @@ func (a Address) Bytes() []byte { return a[:] } +// IncrementBy increments the provided address by the given number. +// +// It does not mutate the original address, but returns altered copy instead. +func (a *Address) IncrementBy(increment uint64) Address { + // Convert Address to big.Int (20 bytes address space) + addrBigInt := new(big.Int).SetBytes(a[:]) + + // Increment by the provided number + addrBigInt.Add(addrBigInt, new(big.Int).SetUint64(increment)) + + var ( + addrBytes = addrBigInt.Bytes() + newAddr Address + ) + + // Handle overflow by truncating to 20 bytes + if len(addrBytes) > AddressLength { + copy(newAddr[:], addrBytes[len(addrBytes)-AddressLength:]) + } else { + copy(newAddr[AddressLength-len(addrBytes):], addrBytes) + } + + return newAddr +} + +// Compare returns 1 if addr1 is higher, -1 if addr2 is higher, and 0 if they are equal. +func (a Address) Compare(to Address) int { + addr1BigInt := new(big.Int).SetBytes(a[:]) + addr2BigInt := new(big.Int).SetBytes(to[:]) + + return addr1BigInt.Cmp(addr2BigInt) +} + +// UnmarshalText parses an address in hex syntax. +func (a *Address) UnmarshalText(input []byte) error { + buf := StringToBytes(string(input)) + if len(buf) != AddressLength { + return fmt.Errorf("incorrect length") + } + + *a = BytesToAddress(buf) + + return nil +} + +func (a Address) MarshalText() ([]byte, error) { + return []byte(a.String()), nil +} + func StringToHash(str string) Hash { return BytesToHash(StringToBytes(str)) } @@ -192,33 +252,6 @@ func IsValidAddress(address string, zeroAddressAllowed bool) (Address, error) { return addr, nil } -// UnmarshalText parses a hash in hex syntax. -func (h *Hash) UnmarshalText(input []byte) error { - *h = BytesToHash(StringToBytes(string(input))) - - return nil -} - -// UnmarshalText parses an address in hex syntax. -func (a *Address) UnmarshalText(input []byte) error { - buf := StringToBytes(string(input)) - if len(buf) != AddressLength { - return fmt.Errorf("incorrect length") - } - - *a = BytesToAddress(buf) - - return nil -} - -func (h Hash) MarshalText() ([]byte, error) { - return []byte(h.String()), nil -} - -func (a Address) MarshalText() ([]byte, error) { - return []byte(a.String()), nil -} - type Proof struct { Data []Hash // the proof himself Metadata map[string]interface{} diff --git a/types/types_test.go b/types/types_test.go index a26081ec35..8cede879b2 100644 --- a/types/types_test.go +++ b/types/types_test.go @@ -137,3 +137,113 @@ func TestIsValidAddress(t *testing.T) { } } } + +func TestIncrementAddressBy(t *testing.T) { + t.Parallel() + + cases := []struct { + address string + increment uint64 + expected string + }{ + { + "0x0000000000000000000000000000000000000000", + 1, + "0x0000000000000000000000000000000000000001", + }, + { + "0x0000000000000000000000000000000000000001", + 1, + "0x0000000000000000000000000000000000000002", + }, + { + "0x0000000000000000000000000000000000000001", + 2, + "0x0000000000000000000000000000000000000003", + }, + { + "0x00000000000000000000000000000000000000ff", + 1, + "0x0000000000000000000000000000000000000100", + }, + { + "0x00000000000000000000000000000000ffffffff", + 1, + "0x0000000000000000000000000000000100000000", + }, + { + "0x0000000000000000000000000000000000001001", + 30, + "0x000000000000000000000000000000000000101f", + }, + { + "0xffffffffffffffffffffffffffffffffffffffff", + 1, + "0x0000000000000000000000000000000000000000", + }, + } + + for _, c := range cases { + c := c + + t.Run("", func(t *testing.T) { + t.Parallel() + + addr := StringToAddress(c.address) + expectedAddr := StringToAddress(c.expected) + incrementedAddr := addr.IncrementBy(c.increment) + + assert.Equal(t, expectedAddr, incrementedAddr, "expected address %s, got %s", expectedAddr.String(), incrementedAddr.String()) + }) + } +} + +func TestCompare(t *testing.T) { + t.Parallel() + + cases := []struct { + address1 string + address2 string + expected int + }{ + { + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + -1, + }, + { + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000001", + 1, + }, + { + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000001", + 0, + }, + { + "0xffffffffffffffffffffffffffffffffffffffff", + "0x0000000000000000000000000000000000000000", + 1, + }, + { + "0x0000000000000000000000000000000000000000", + "0xffffffffffffffffffffffffffffffffffffffff", + -1, + }, + } + + for _, c := range cases { + c := c + + t.Run("", func(t *testing.T) { + t.Parallel() + + addr1 := StringToAddress(c.address1) + addr2 := StringToAddress(c.address2) + result := addr1.Compare(addr2) + + assert.Equal(t, c.expected, result, "expected comparison result %d, got %d", c.expected, result) + }) + } +}