From 4fbe4ba649c3ec7b9440107b318d4b536261bc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= <93934272+Stefan-Ethernal@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:01:15 +0200 Subject: [PATCH] Make stake token address as mandatory in certain use cases (#1914) * Stake token address is mandatory if not run in test mode * Mandatory stake token in rootchain fund command (in case those are minted) * Add unit tests --- command/rootchain/fund/params.go | 12 ++ command/rootchain/fund/params_test.go | 105 ++++++++++++++++++ command/rootchain/helper/utils.go | 7 +- .../rootchain/supernet/stakemanager/params.go | 19 +++- .../supernet/stakemanager/params_test.go | 48 ++++++++ .../stakemanager/stake_manager_deploy.go | 4 +- types/types.go | 2 +- 7 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 command/rootchain/fund/params_test.go create mode 100644 command/rootchain/supernet/stakemanager/params_test.go diff --git a/command/rootchain/fund/params.go b/command/rootchain/fund/params.go index 4dd10f2edd..8493b059e6 100644 --- a/command/rootchain/fund/params.go +++ b/command/rootchain/fund/params.go @@ -2,9 +2,11 @@ package fund import ( "errors" + "fmt" "math/big" cmdhelper "github.com/0xPolygon/polygon-edge/command/helper" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/types" ) @@ -56,5 +58,15 @@ func (fp *fundParams) validateFlags() error { fp.amountValues[i] = amountValue } + if fp.mintStakeToken { + if fp.stakeTokenAddr == "" { + return rootHelper.ErrMandatoryStakeToken + } + + if err := types.IsValidAddress(fp.stakeTokenAddr); err != nil { + return fmt.Errorf("invalid stake token address is provided: %w", err) + } + } + return nil } diff --git a/command/rootchain/fund/params_test.go b/command/rootchain/fund/params_test.go new file mode 100644 index 0000000000..4a1500ac80 --- /dev/null +++ b/command/rootchain/fund/params_test.go @@ -0,0 +1,105 @@ +package fund + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/types" +) + +func Test_validateFlags(t *testing.T) { + t.Parallel() + + cases := []struct { + buildParamsFn func() *fundParams + err string + }{ + { + // no addresses provided + buildParamsFn: func() *fundParams { + return &fundParams{} + }, + err: errNoAddressesProvided.Error(), + }, + { + // inconsistent length (addresses vs amounts) + buildParamsFn: func() *fundParams { + return &fundParams{ + addresses: []string{"0x1", "0x2"}, + amounts: []string{"10"}, + } + }, + err: errInconsistentLength.Error(), + }, + { + // address contains invalid characters + buildParamsFn: func() *fundParams { + return &fundParams{ + addresses: []string{"0x10", "0x20"}, + amounts: []string{"10", "20"}, + } + }, + err: "address \x10 has invalid length", + }, + { + // stake token address omitted + buildParamsFn: func() *fundParams { + return &fundParams{ + mintStakeToken: true, + addresses: []string{ + types.StringToAddress("0x10").String(), + types.StringToAddress("0x20").String()}, + amounts: []string{"10", "20"}, + } + }, + err: rootHelper.ErrMandatoryStakeToken.Error(), + }, + { + // stake token address omitted + buildParamsFn: func() *fundParams { + return &fundParams{ + mintStakeToken: true, + stakeTokenAddr: "0xA", + addresses: []string{ + types.StringToAddress("0x10").String(), + types.StringToAddress("0x20").String()}, + amounts: []string{"10", "20"}, + } + }, + err: "invalid stake token address is provided", + }, + { + // valid scenario + buildParamsFn: func() *fundParams { + return &fundParams{ + addresses: []string{ + types.StringToAddress("0x10").String(), + types.StringToAddress("0x20").String()}, + amounts: []string{"10", "20"}, + } + }, + err: "", + }, + } + + for i, c := range cases { + c := c + i := i + + t.Run(fmt.Sprintf("case#%d", i+1), func(t *testing.T) { + t.Parallel() + + fp := c.buildParamsFn() + + err := fp.validateFlags() + if c.err != "" { + require.ErrorContains(t, err, c.err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/command/rootchain/helper/utils.go b/command/rootchain/helper/utils.go index 24e50dcd41..d0525c955c 100644 --- a/command/rootchain/helper/utils.go +++ b/command/rootchain/helper/utils.go @@ -40,9 +40,10 @@ const ( ) var ( - ErrRootchainNotFound = errors.New("rootchain not found") - ErrRootchainPortBind = errors.New("port 8545 is not bind with localhost") - errTestModeSecrets = errors.New("rootchain test mode does not imply specifying secrets parameters") + ErrRootchainNotFound = errors.New("rootchain not found") + ErrRootchainPortBind = errors.New("port 8545 is not bind with localhost") + ErrMandatoryStakeToken = errors.New("stake token address is mandatory") + errTestModeSecrets = errors.New("rootchain test mode does not imply specifying secrets parameters") rootchainAccountKey *wallet.Key ) diff --git a/command/rootchain/supernet/stakemanager/params.go b/command/rootchain/supernet/stakemanager/params.go index c62aa0d9c0..ad3478653e 100644 --- a/command/rootchain/supernet/stakemanager/params.go +++ b/command/rootchain/supernet/stakemanager/params.go @@ -5,7 +5,9 @@ import ( "os" "github.com/0xPolygon/polygon-edge/command/helper" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" + "github.com/0xPolygon/polygon-edge/types" ) type stakeManagerDeployParams struct { @@ -19,10 +21,23 @@ type stakeManagerDeployParams struct { } func (s *stakeManagerDeployParams) validateFlags() error { - if !s.isTestMode && s.privateKey == "" { - return sidechainHelper.ValidateSecretFlags(s.accountDir, s.accountConfig) + if !s.isTestMode { + // private key is mandatory + if s.privateKey == "" { + return sidechainHelper.ValidateSecretFlags(s.accountDir, s.accountConfig) + } + + // stake token address is mandatory + if s.stakeTokenAddress == "" { + return rootHelper.ErrMandatoryStakeToken + } + + if err := types.IsValidAddress(s.stakeTokenAddress); err != nil { + return fmt.Errorf("invalid stake token address is provided: %w", err) + } } + // check if provided genesis path is valid if _, err := os.Stat(s.genesisPath); err != nil { return fmt.Errorf("provided genesis path '%s' is invalid. Error: %w ", s.genesisPath, err) } diff --git a/command/rootchain/supernet/stakemanager/params_test.go b/command/rootchain/supernet/stakemanager/params_test.go new file mode 100644 index 0000000000..bbcb03d0c0 --- /dev/null +++ b/command/rootchain/supernet/stakemanager/params_test.go @@ -0,0 +1,48 @@ +package stakemanager + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" +) + +func TestValidateFlags(t *testing.T) { + t.Parallel() + + testCases := []struct { + params *stakeManagerDeployParams + errMsg string + }{ + { + params: &stakeManagerDeployParams{ + isTestMode: false, + privateKey: rootHelper.TestAccountPrivKey, + stakeTokenAddress: "", + }, + errMsg: rootHelper.ErrMandatoryStakeToken.Error(), + }, + { + params: &stakeManagerDeployParams{ + isTestMode: false, + privateKey: rootHelper.TestAccountPrivKey, + stakeTokenAddress: "0x1B", + }, + errMsg: "invalid stake token address is provided", + }, + } + + for i, tc := range testCases { + i := i + tc := tc + + t.Run(fmt.Sprintf("case#%d", i+1), func(t *testing.T) { + t.Parallel() + + err := tc.params.validateFlags() + require.ErrorContains(t, err, tc.errMsg) + }) + } +} diff --git a/command/rootchain/supernet/stakemanager/stake_manager_deploy.go b/command/rootchain/supernet/stakemanager/stake_manager_deploy.go index a60fd0f35f..7c14bcbc01 100644 --- a/command/rootchain/supernet/stakemanager/stake_manager_deploy.go +++ b/command/rootchain/supernet/stakemanager/stake_manager_deploy.go @@ -24,7 +24,7 @@ func GetCommand() *cobra.Command { stakeMgrDeployCmd := &cobra.Command{ Use: "stake-manager-deploy", Short: "Command for deploying stake manager contract on rootchain", - PreRunE: runPreRun, + PreRunE: preRunCommand, RunE: runCommand, } @@ -33,7 +33,7 @@ func GetCommand() *cobra.Command { return stakeMgrDeployCmd } -func runPreRun(cmd *cobra.Command, _ []string) error { +func preRunCommand(cmd *cobra.Command, _ []string) error { params.jsonRPC = helper.GetJSONRPCAddress(cmd) return params.validateFlags() diff --git a/types/types.go b/types/types.go index 8db99b7d7d..3ca3cc35b5 100644 --- a/types/types.go +++ b/types/types.go @@ -159,7 +159,7 @@ func IsValidAddress(address string) error { // check if the address has the correct length if len(decodedAddress) != AddressLength { - return fmt.Errorf("address %s has invalid length", address) + return fmt.Errorf("address %s has invalid length", string(decodedAddress)) } return nil