diff --git a/internal/cli/model/model.go b/internal/cli/model/model.go index de279353f8..b2fac204f8 100644 --- a/internal/cli/model/model.go +++ b/internal/cli/model/model.go @@ -450,6 +450,10 @@ type MinerSCNodes struct { Nodes []Node `json:"Nodes"` } +type AutorizerNodes struct { + Nodes []Node `json:"Nodes"` +} + type MinerSCDelegatePoolInfo struct { ID string `json:"id"` Balance int64 `json:"balance"` diff --git a/tests/cli_tests/config/zbox_config.yaml b/tests/cli_tests/config/zbox_config.yaml index bd2836e3b2..455a311873 100644 --- a/tests/cli_tests/config/zbox_config.yaml +++ b/tests/cli_tests/config/zbox_config.yaml @@ -1,4 +1,4 @@ -block_worker: https://dev.zus.network/dns +block_worker: https://dev-5.devnet-0chain.net/dns confirmation_chain_length: 3 ethereum_node_url: "https://rpc.tenderly.co/fork/5b7ffac9-50cc-4169-b0ca-6fd203d26ef6" min_confirmation: 50 diff --git a/tests/cli_tests/main_test.go b/tests/cli_tests/main_test.go index 742523e034..cfb3ef09ba 100644 --- a/tests/cli_tests/main_test.go +++ b/tests/cli_tests/main_test.go @@ -32,6 +32,7 @@ func setupDefaultConfig() { viper.SetDefault("nodes.miner03ID", "c6f4b8ce5da386b278ba8c4e6cf98b24b32d15bc675b4d12c95e082079c91937") viper.SetDefault("nodes.sharder01ID", "ea26431f8adb7061766f1d6bbcc3b292d70dd59960d857f04b8a75e6a5bbe04f") viper.SetDefault("nodes.sharder02ID", "30001a01a888584772b7fee13934021ab8557e0ed471c0a3a454e9164180aef1") + viper.SetDefault("nodes.authorizer01ID", "7b07c0489e2f35d7c13160f4da2866b4aa69aa4e8d2b2cd9c4fc002693dca5d7") } // SetupConfig setups the main configuration system. @@ -51,6 +52,7 @@ func setupConfig() { miner03ID = viper.GetString("nodes.miner03ID") sharder01ID = viper.GetString("nodes.sharder01ID") sharder02ID = viper.GetString("nodes.sharder02ID") + authorizer01ID = viper.GetString("nodes.authorizer01ID") parsedConfig := config.Parse(filepath.Join(".", path, "cli_tests_config.yaml")) defaultTestTimeout, err := time.ParseDuration(parsedConfig.DefaultTestCaseTimeout) @@ -88,17 +90,18 @@ const ( miner03NodeDelegateWalletName = "wallets/miner03_node_delegate" sharder01NodeDelegateWalletName = "wallets/sharder01_node_delegate" sharder02NodeDelegateWalletName = "wallets/sharder02_node_delegate" + authorizer01NodeDelegateWallet = "wallets/authorizer01_node_delegate" stakingWallet = "wallets/staking" zboxTeamWallet = "wallets/zbox_team" ) var ( - miner01ID string - miner02ID string - miner03ID string - sharder01ID string - sharder02ID string - + miner01ID string + miner02ID string + miner03ID string + sharder01ID string + sharder02ID string + authorizer01ID string ethereumNodeURL string tokenAddress string ethereumAddress string @@ -147,6 +150,7 @@ func TestMain(m *testing.M) { strings.HasSuffix(f, miner03NodeDelegateWalletName+"_wallet.json") || strings.HasSuffix(f, sharder01NodeDelegateWalletName+"_wallet.json") || strings.HasSuffix(f, sharder02NodeDelegateWalletName+"_wallet.json") || + strings.HasSuffix(f, authorizer01NodeDelegateWallet+"_wallet.json") || strings.HasSuffix(f, stakingWallet+"_wallet.json") || strings.HasSuffix(f, zboxTeamWallet+"_wallet.json") { continue diff --git a/tests/cli_tests/zwalletcli_authorizer_stake_test.go b/tests/cli_tests/zwalletcli_authorizer_stake_test.go new file mode 100644 index 0000000000..23f3a961bd --- /dev/null +++ b/tests/cli_tests/zwalletcli_authorizer_stake_test.go @@ -0,0 +1,195 @@ +package cli_tests + +import ( + // "encoding/json" + "fmt" + // "os" + "strings" + "testing" + "time" + + "github.com/0chain/system_test/internal/api/util/test" + + climodel "github.com/0chain/system_test/internal/cli/model" + cliutils "github.com/0chain/system_test/internal/cli/util" + "github.com/stretchr/testify/require" + "regexp" +) + +var authorizerLockOutputRegex = regexp.MustCompile("txn hash: [a-f0-9]{64}") + +func TestAuthorizerStake(testSetup *testing.T) { + t := test.NewSystemTest(testSetup) + t.SetSmokeTests("Staking tokens against valid authorizer with valid tokens should work") + + var authorizer climodel.Node + // var authorizers climodel.AutorizerNodes + t.TestSetup("Get authorizer details", func() { + + output, err := listAuthorizer(t, configPath, "--json") + t.Log("list of authorizer ", output) + require.NoError(t, err, "error listing authorizers") + + authorizer.ID = authorizer01ID + t.Log("authorizer", authorizer.ID) + }) + + t.Parallel() + + t.RunWithTimeout("Staking tokens against valid authorizer with valid tokens should work", 5*time.Minute, func(t *test.SystemTest) { // todo: slow + createWallet(t) + t.Log("Before authorizer") + t.Log("authorizerID", authorizer.ID) + // Lock should work + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + "tokens": 2.0, + }), true) + t.Log("output", output, "Error", err) + require.Nil(t, err, "error staking tokens against a node") + require.Len(t, output, 1) + require.Regexp(t, authorizerLockOutputRegex, output[0]) + + // Unlock should work + require.Nil(t, err, "Error unstaking tokens") + output, err = authorizerUnlock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + }), true) + require.Nil(t, err, "error unlocking tokens against a node") + require.Len(t, output, 1) + require.Equal(t, "tokens unlocked", output[0]) + + output, err = authorizerPoolInfo(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + "json": "", + }), true) + + require.NotNil(t, err, "expected error when requesting unlocked pool but got output", strings.Join(output, "\n")) + require.Len(t, output, 1) + require.Equal(t, `resource_not_found: can't find pool stats`, output[0]) + }) + t.Run("Staking tokens with insufficient balance should fail", func(t *test.SystemTest) { + _, err := executeFaucetWithTokens(t, configPath, 1.0) + require.Nil(t, err, "error executing faucet") + + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "miner_id": authorizer.ID, + "tokens": 10, + }), false) + require.NotNil(t, err, "expected error when staking tokens with insufficient balance but got output: ", strings.Join(output, "\n")) + require.Len(t, output, 1) + require.Equal(t, "stake_pool_lock_failed: stake pool digging error: lock amount is greater than balance", output[0]) + }) + + t.Run("Staking tokens against invalid node id should fail", func(t *test.SystemTest) { + createWallet(t) + + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": "abcdefgh", + "tokens": 1, + }), false) + require.NotNil(t, err, "expected error when staking tokens against invalid authorizer but got output", strings.Join(output, "\n")) + require.Len(t, output, 1) + require.Equal(t, "stake_pool_lock_failed: can't get stake pool: get_stake_pool: authorizer not found or genesis authorizer used", output[0]) + }) + + t.Run("Staking negative tokens against valid authorizer should fail", func(t *test.SystemTest) { + createWallet(t) + + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + "tokens": -1, + }), false) + require.NotNil(t, err, "expected error when staking negative tokens but got output: ", strings.Join(output, "\n")) + require.Len(t, output, 1) + require.Equal(t, `invalid token amount: negative`, output[0]) + }) + + t.Run("Staking 0 tokens against authorizer should fail", func(t *test.SystemTest) { + createWallet(t) + + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer01ID, + "tokens": 0, + }), false) + require.NotNil(t, err, "expected error when staking more tokens than max_stake but got output: ", strings.Join(output, "\n")) + require.Len(t, output, 1) + require.Equal(t, "stake_pool_lock_failed: no stake to lock: 0", output[0]) + }) + + t.Run("Locking unlocking tokens with invalid node id should fail", func(t *test.SystemTest) { + createWallet(t) + + output, err := authorizerLock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + "tokens": 2, + }), true) + require.Nil(t, err, "error staking tokens against a node") + require.Len(t, output, 1) + require.Regexp(t, authorizerLockOutputRegex, output[0]) + + output, err = authorizerUnlock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": "abcdefgh", + }), false) + require.NotNil(t, err, "expected error when using invalid node id") + require.Len(t, output, 1) + require.Equal(t, "stake_pool_unlock_failed: can't get related stake pool: get_stake_pool: miner not found or genesis miner used", output[0]) + + // teardown + _, err = authorizerUnlock(t, configPath, createParams(map[string]interface{}{ + "authorizer_id": authorizer.ID, + }), true) + if err != nil { + t.Log("error unlocking tokens after test: ", t.Name()) + } + }) +} + +func listAuthorizer(t *test.SystemTest, cliConfigFilename, params string) ([]string, error) { + cmd := fmt.Sprintf( + "./zwallet bridge-list-auth --silent "+ + "--configDir ./config --config %s", + configPath, + ) + return cliutils.RunCommand(t, cmd, 3, time.Second*2) +} + +func authorizerLock(t *test.SystemTest, cliConfigFilename, params string, retry bool) ([]string, error) { + return authorizerLockForWallet(t, cliConfigFilename, params, escapedTestName(t), retry) +} + +func authorizerLockForWallet(t *test.SystemTest, cliConfigFilename, params, wallet string, retry bool) ([]string, error) { + t.Log("locking tokens against authorizers...") + t.Log("params", params) + if retry { + return cliutils.RunCommand(t, fmt.Sprintf("./zbox sp-lock %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename), 3, time.Second) + } else { + return cliutils.RunCommandWithoutRetry(fmt.Sprintf("./zbox sp-lock %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename)) + } +} + +func authorizerUnlock(t *test.SystemTest, cliConfigFilename, params string, retry bool) ([]string, error) { + return authorizerUnlockForWallet(t, cliConfigFilename, params, escapedTestName(t), retry) +} + +func authorizerUnlockForWallet(t *test.SystemTest, cliConfigFilename, params, wallet string, retry bool) ([]string, error) { + t.Log("unlocking tokens from authorizer pool...") + if retry { + return cliutils.RunCommand(t, fmt.Sprintf("./zbox sp-unlock %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename), 3, time.Second*2) + } else { + return cliutils.RunCommandWithoutRetry(fmt.Sprintf("./zbox sp-unlock %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename)) + } +} + +func authorizerPoolInfo(t *test.SystemTest, cliConfigFilename, params string, retry bool) ([]string, error) { + return authorizerPoolInfoForWallet(t, cliConfigFilename, params, escapedTestName(t), retry) +} + +func authorizerPoolInfoForWallet(t *test.SystemTest, cliConfigFilename, params, wallet string, retry bool) ([]string, error) { + t.Log("fetching sp-info...") + if retry { + return cliutils.RunCommand(t, fmt.Sprintf("./zbox sp-info %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename), 3, time.Second) + } else { + return cliutils.RunCommandWithoutRetry(fmt.Sprintf("./zbox sp-info %s --silent --wallet %s_wallet.json --configDir ./config --config %s", params, wallet, cliConfigFilename)) + } +}