diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f0631d..220dfd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 with: - go-version: "1.25.9" + go-version: "1.25.11" - name: Verify go.mod is tidy run: | @@ -28,17 +28,17 @@ jobs: - name: Run staticcheck env: - GOTOOLCHAIN: go1.25.9 + GOTOOLCHAIN: go1.25.11 run: go run honnef.co/go/tools/cmd/staticcheck@v0.6.1 ./... - name: Run staticcheck (tagged e2e) env: - GOTOOLCHAIN: go1.25.9 + GOTOOLCHAIN: go1.25.11 run: go run honnef.co/go/tools/cmd/staticcheck@v0.6.1 -tags=clie2e,networke2e ./e2e/... - name: Run govulncheck env: - GOTOOLCHAIN: go1.25.9 + GOTOOLCHAIN: go1.25.11 run: go run golang.org/x/vuln/cmd/govulncheck@v1.2.0 ./... - name: Run tests diff --git a/cmd/helpers_test.go b/cmd/helpers_test.go index 8eebdde..cde33c9 100644 --- a/cmd/helpers_test.go +++ b/cmd/helpers_test.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "math" "reflect" + "strings" "testing" "time" @@ -120,6 +121,24 @@ func TestFeeToShares(t *testing.T) { } } +func TestFractionToShares(t *testing.T) { + got, err := fractionToShares("auto-compound", 0.3) + if err != nil { + t.Fatalf("fractionToShares() returned error: %v", err) + } + if got != 300_000 { + t.Fatalf("fractionToShares() = %d, want 300000", got) + } + + _, err = fractionToShares("auto-compound", 1.01) + if err == nil { + t.Fatal("fractionToShares() expected error for value above one") + } + if !strings.Contains(err.Error(), "auto-compound") { + t.Fatalf("fractionToShares() error = %v, want field name", err) + } +} + func TestGetTransferAmountNAVAX(t *testing.T) { origAmount := transferAmount origAmountNAVAX := transferAmountNAVAX @@ -202,6 +221,153 @@ func TestParseTimeRange(t *testing.T) { } } +func TestParseAutoRenewPeriod(t *testing.T) { + got, err := parseAutoRenewPeriod("336h") + if err != nil { + t.Fatalf("parseAutoRenewPeriod() returned error: %v", err) + } + if got != 14*24*time.Hour { + t.Fatalf("parseAutoRenewPeriod() = %s, want 336h", got) + } + + _, err = parseAutoRenewPeriod("0s") + if err == nil { + t.Fatal("parseAutoRenewPeriod() expected error for zero period") + } + + _, err = parseAutoRenewPeriod("1.5s") + if err == nil { + t.Fatal("parseAutoRenewPeriod() expected error for sub-second period") + } + + _, err = parseAutoRenewPeriod("bad-period") + if err == nil { + t.Fatal("parseAutoRenewPeriod() expected error for invalid period") + } +} + +func TestParseAutoRenewConfigPeriod(t *testing.T) { + tests := []struct { + name string + input string + want time.Duration + wantErr bool + }{ + { + name: "zero duration", + input: "0", + want: 0, + }, + { + name: "zero seconds", + input: "0s", + want: 0, + }, + { + name: "non-zero duration", + input: "336h", + want: 14 * 24 * time.Hour, + }, + { + name: "negative duration", + input: "-1s", + wantErr: true, + }, + { + name: "sub-second duration", + input: "1.5s", + wantErr: true, + }, + { + name: "invalid duration", + input: "bad-period", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseAutoRenewConfigPeriod(tt.input) + if tt.wantErr { + if err == nil { + t.Fatalf("parseAutoRenewConfigPeriod(%q) expected error", tt.input) + } + return + } + if err != nil { + t.Fatalf("parseAutoRenewConfigPeriod(%q) returned error: %v", tt.input, err) + } + if got != tt.want { + t.Fatalf("parseAutoRenewConfigPeriod(%q) = %s, want %s", tt.input, got, tt.want) + } + }) + } +} + +func TestParseRewardAutoTimestamp(t *testing.T) { + tests := []struct { + name string + input string + wantUnix uint64 + wantRFC string + wantError bool + }{ + { + name: "RFC3339", + input: "2026-06-04T12:30:00Z", + wantUnix: 1780576200, + wantRFC: "2026-06-04T12:30:00Z", + }, + { + name: "Unix seconds", + input: "1780576200", + wantUnix: 1780576200, + wantRFC: "2026-06-04T12:30:00Z", + }, + { + name: "empty", + input: "", + wantError: true, + }, + { + name: "zero", + input: "0", + wantError: true, + }, + { + name: "too large", + input: "9223372036854775808", + wantError: true, + }, + { + name: "invalid", + input: "bad-timestamp", + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotUnix, gotTime, err := parseRewardAutoTimestamp(tt.input) + if tt.wantError { + if err == nil { + t.Fatalf("parseRewardAutoTimestamp(%q) expected error", tt.input) + } + return + } + if err != nil { + t.Fatalf("parseRewardAutoTimestamp(%q) returned error: %v", tt.input, err) + } + if gotUnix != tt.wantUnix { + t.Fatalf("parseRewardAutoTimestamp(%q) unix = %d, want %d", tt.input, gotUnix, tt.wantUnix) + } + if gotTime.Format(time.RFC3339) != tt.wantRFC { + t.Fatalf("parseRewardAutoTimestamp(%q) time = %s, want %s", tt.input, gotTime.Format(time.RFC3339), tt.wantRFC) + } + }) + } +} + func TestParseValidatorAddrs(t *testing.T) { got := parseValidatorAddrs(" 127.0.0.1 , node.example.com:9650 ,,https://node.example.com ") want := []string{"127.0.0.1", "node.example.com:9650", "https://node.example.com"} diff --git a/cmd/root.go b/cmd/root.go index 5e903d4..2d94f72 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -95,13 +95,17 @@ func avaxToNAVAX(avax float64) (uint64, error) { return uint64(math.Round(avax * 1e9)), nil } +func fractionToShares(name string, value float64) (uint32, error) { + if value < 0 || value > 1 { + return 0, fmt.Errorf("%s must be between 0 and 1 (got %.4f)", name, value) + } + return uint32(math.Round(value * 1_000_000)), nil +} + // feeToShares converts a decimal fee (0.02 = 2%) to shares (20,000 out of 1,000,000). // Uses rounding to avoid float precision issues. func feeToShares(fee float64) (uint32, error) { - if fee < 0 || fee > 1 { - return 0, fmt.Errorf("delegation fee must be between 0 and 1 (got %.4f)", fee) - } - return uint32(math.Round(fee * 1_000_000)), nil + return fractionToShares("delegation fee", fee) } // getOperationContext returns a context with timeout and signal handling. diff --git a/cmd/validator.go b/cmd/validator.go index 9e39406..25dfc1e 100644 --- a/cmd/validator.go +++ b/cmd/validator.go @@ -4,6 +4,7 @@ import ( "context" "encoding/hex" "fmt" + "strconv" "strings" "time" @@ -17,15 +18,23 @@ import ( ) var ( - valNodeID string - valStakeAmount float64 - valStartTime string - valDuration string - valDelegationFee float64 - valRewardAddr string - valNodeEndpoint string - valBLSPublicKey string - valBLSPoP string + valNodeID string + valStakeAmount float64 + valStartTime string + valDuration string + valDelegationFee float64 + valRewardAddr string + valNodeEndpoint string + valBLSPublicKey string + valBLSPoP string + valAutoPeriod string + valAutoCompound float64 + valOwnerAddr string + valSetAutoTxID string + valSetAutoPeriod string + valSetAutoCompound float64 + valRewardAutoTxID string + valRewardAutoTime string ) var validatorCmd = &cobra.Command{ @@ -203,6 +212,234 @@ var validatorDelegateCmd = &cobra.Command{ }, } +var validatorAddAutoRenewedCmd = &cobra.Command{ + Use: "add-auto-renewed", + Short: "Add an auto-renewed primary network validator", + Long: `Add an auto-renewed validator to the Avalanche primary network.`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx, cancel := getOperationContext() + defer cancel() + + if valStakeAmount <= 0 { + return fmt.Errorf("--stake is required and must be positive") + } + if valNodeID == "" { + return fmt.Errorf("--node-id is required") + } + nodeID, err := ids.NodeIDFromString(valNodeID) + if err != nil { + return fmt.Errorf("invalid node ID: %w", err) + } + + period, err := parseAutoRenewPeriod(valAutoPeriod) + if err != nil { + return err + } + + netConfig, err := getNetworkConfig(ctx) + if err != nil { + return fmt.Errorf("failed to get network config: %w", err) + } + if period < netConfig.MinStakeDuration { + return fmt.Errorf("period too short for %s: minimum is %s", netConfig.Name, netConfig.MinStakeDuration) + } + + nodePoP, nodeURI, err := getValidatorPoP(ctx, nodeID) + if err != nil { + return err + } + + w, cleanup, err := loadPChainWallet(ctx, netConfig) + if err != nil { + return fmt.Errorf("failed to create wallet: %w", err) + } + defer cleanup() + + rewardAddr := w.PChainAddress() + if valRewardAddr != "" { + rewardAddr, err = ids.ShortFromString(valRewardAddr) + if err != nil { + return fmt.Errorf("invalid reward address: %w", err) + } + } + + authorityAddr := w.PChainAddress() + if valOwnerAddr != "" { + authorityAddr, err = ids.ShortFromString(valOwnerAddr) + if err != nil { + return fmt.Errorf("invalid owner address: %w", err) + } + } + + stakeNAVAX, err := avaxToNAVAX(valStakeAmount) + if err != nil { + return fmt.Errorf("invalid stake amount: %w", err) + } + if stakeNAVAX < netConfig.MinValidatorStake { + return fmt.Errorf("stake too low for %s: minimum is %.9f AVAX", netConfig.Name, float64(netConfig.MinValidatorStake)/1e9) + } + + delegationFeeShares, err := feeToShares(valDelegationFee) + if err != nil { + return fmt.Errorf("invalid delegation fee: %w", err) + } + autoCompoundShares, err := fractionToShares("auto-compound", valAutoCompound) + if err != nil { + return fmt.Errorf("invalid auto-compound: %w", err) + } + + fmt.Printf("Adding auto-renewed validator %s with %.9f AVAX stake...\n", nodeID, valStakeAmount) + fmt.Printf(" Period: %s\n", period) + fmt.Printf(" Delegation Fee: %.2f%%\n", valDelegationFee*100) + fmt.Printf(" Auto-Compound Rewards: %.2f%%\n", valAutoCompound*100) + fmt.Printf(" Validator Authority: %s\n", authorityAddr) + if nodeURI != "" { + fmt.Printf(" Node Endpoint: %s\n", nodeURI) + } else { + fmt.Println(" BLS PoP Source: --bls-public-key/--bls-pop flags") + } + fmt.Println("Submitting transaction...") + + txID, err := pchain.AddAutoRenewedValidator(ctx, w, pchain.AddAutoRenewedValidatorConfig{ + NodeID: nodeID, + StakeAmt: stakeNAVAX, + RewardAddr: rewardAddr, + ValidatorAuthorityAddr: authorityAddr, + DelegationFee: delegationFeeShares, + AutoCompoundRewardShares: autoCompoundShares, + Period: period, + BLSSigner: nodePoP, + }) + if err != nil { + return err + } + + fmt.Printf("TX ID: %s\n", txID) + return nil + }, +} + +var validatorSetAutoConfigCmd = &cobra.Command{ + Use: "set-auto-config", + Short: "Set auto-renewed validator config", + Long: `Set the next-cycle configuration for an auto-renewed validator.`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx, cancel := getOperationContext() + defer cancel() + + if valSetAutoTxID == "" { + return fmt.Errorf("--tx-id is required") + } + autoRenewedTxID, err := ids.FromString(valSetAutoTxID) + if err != nil { + return fmt.Errorf("invalid tx ID: %w", err) + } + + if !cmd.Flags().Changed("period") { + return fmt.Errorf("--period is required") + } + period, err := parseAutoRenewConfigPeriod(valSetAutoPeriod) + if err != nil { + return err + } + + if !cmd.Flags().Changed("auto-compound") { + return fmt.Errorf("--auto-compound is required") + } + autoCompoundShares, err := fractionToShares("auto-compound", valSetAutoCompound) + if err != nil { + return fmt.Errorf("invalid auto-compound: %w", err) + } + + netConfig, err := getNetworkConfig(ctx) + if err != nil { + return fmt.Errorf("failed to get network config: %w", err) + } + if period > 0 && period < netConfig.MinStakeDuration { + return fmt.Errorf("period too short for %s: minimum is %s", netConfig.Name, netConfig.MinStakeDuration) + } + + w, cleanup, err := loadPChainWallet(ctx, netConfig) + if err != nil { + return fmt.Errorf("failed to create wallet: %w", err) + } + defer cleanup() + + fmt.Printf("Setting auto-renewed validator config for %s...\n", autoRenewedTxID) + if period == 0 { + fmt.Println(" Period: 0s (exit after current cycle)") + } else { + fmt.Printf(" Period: %s\n", period) + } + fmt.Printf(" Auto-Compound Rewards: %.2f%%\n", valSetAutoCompound*100) + fmt.Println("Submitting transaction...") + + txID, err := pchain.SetAutoRenewedValidatorConfig(ctx, w, pchain.SetAutoRenewedValidatorConfigTxConfig{ + TxID: autoRenewedTxID, + AutoCompoundRewardShares: autoCompoundShares, + Period: period, + }) + if err != nil { + return err + } + + fmt.Printf("TX ID: %s\n", txID) + return nil + }, +} + +var validatorRewardAutoCmd = &cobra.Command{ + Use: "reward-auto", + Short: "Reward an auto-renewed validator cycle", + Long: `Reward or exit an auto-renewed validator at the end of a validation cycle.`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx, cancel := getOperationContext() + defer cancel() + + if valRewardAutoTxID == "" { + return fmt.Errorf("--tx-id is required") + } + autoRenewedTxID, err := ids.FromString(valRewardAutoTxID) + if err != nil { + return fmt.Errorf("invalid tx ID: %w", err) + } + + if valRewardAutoTime == "" { + return fmt.Errorf("--timestamp is required") + } + timestamp, timestampTime, err := parseRewardAutoTimestamp(valRewardAutoTime) + if err != nil { + return err + } + + netConfig, err := getNetworkConfig(ctx) + if err != nil { + return fmt.Errorf("failed to get network config: %w", err) + } + + w, cleanup, err := loadPChainWallet(ctx, netConfig) + if err != nil { + return fmt.Errorf("failed to create wallet: %w", err) + } + defer cleanup() + + fmt.Printf("Rewarding auto-renewed validator cycle for %s...\n", autoRenewedTxID) + fmt.Printf(" Timestamp: %s (%d)\n", timestampTime.UTC().Format(time.RFC3339), timestamp) + fmt.Println("Submitting transaction...") + + txID, err := pchain.RewardAutoRenewedValidator(ctx, w, pchain.RewardAutoRenewedValidatorConfig{ + TxID: autoRenewedTxID, + Timestamp: timestamp, + }) + if err != nil { + return err + } + + fmt.Printf("TX ID: %s\n", txID) + return nil + }, +} + func parseTimeRange(startStr, durationStr string) (time.Time, time.Time, error) { var start time.Time var err error @@ -229,6 +466,63 @@ func parseTimeRange(startStr, durationStr string) (time.Time, time.Time, error) return start, end, nil } +func parseAutoRenewPeriod(periodStr string) (time.Duration, error) { + period, err := time.ParseDuration(periodStr) + if err != nil { + return 0, fmt.Errorf("invalid period: %w", err) + } + if period <= 0 { + return 0, fmt.Errorf("period must be positive") + } + if period%time.Second != 0 { + return 0, fmt.Errorf("period must be a whole number of seconds") + } + return period, nil +} + +func parseAutoRenewConfigPeriod(periodStr string) (time.Duration, error) { + if strings.TrimSpace(periodStr) == "0" { + return 0, nil + } + period, err := time.ParseDuration(periodStr) + if err != nil { + return 0, fmt.Errorf("invalid period: %w", err) + } + if period < 0 { + return 0, fmt.Errorf("period cannot be negative") + } + if period%time.Second != 0 { + return 0, fmt.Errorf("period must be a whole number of seconds") + } + return period, nil +} + +func parseRewardAutoTimestamp(timestampStr string) (uint64, time.Time, error) { + timestampStr = strings.TrimSpace(timestampStr) + if timestampStr == "" { + return 0, time.Time{}, fmt.Errorf("timestamp is required") + } + + if timestamp, err := strconv.ParseUint(timestampStr, 10, 64); err == nil { + if timestamp == 0 { + return 0, time.Time{}, fmt.Errorf("timestamp must be positive") + } + if timestamp > uint64(1<<63-1) { + return 0, time.Time{}, fmt.Errorf("timestamp is too large") + } + return timestamp, time.Unix(int64(timestamp), 0).UTC(), nil + } + + timestampTime, err := time.Parse(time.RFC3339, timestampStr) + if err != nil { + return 0, time.Time{}, fmt.Errorf("invalid timestamp (use RFC3339 or Unix seconds): %w", err) + } + if timestampTime.Unix() <= 0 { + return 0, time.Time{}, fmt.Errorf("timestamp must be positive") + } + return uint64(timestampTime.Unix()), timestampTime.UTC(), nil +} + // getValidatorPoP returns a BLS proof of possession for validator registration. // Manual mode (default): use --bls-public-key and --bls-pop. // Fallback mode: fetch from --node-endpoint. @@ -301,6 +595,9 @@ func normalizeValidatorNodeURI(addr string) (string, error) { func init() { rootCmd.AddCommand(validatorCmd) validatorCmd.AddCommand(validatorAddCmd) + validatorCmd.AddCommand(validatorAddAutoRenewedCmd) + validatorCmd.AddCommand(validatorSetAutoConfigCmd) + validatorCmd.AddCommand(validatorRewardAutoCmd) validatorCmd.AddCommand(validatorDelegateCmd) // Add validator flags @@ -314,6 +611,27 @@ func init() { validatorAddCmd.Flags().Float64Var(&valDelegationFee, "delegation-fee", 0.02, "Delegation fee (0.02 = 2%)") validatorAddCmd.Flags().StringVar(&valRewardAddr, "reward-address", "", "Reward address (default: own address)") + // Add auto-renewed validator flags + validatorAddAutoRenewedCmd.Flags().StringVar(&valNodeID, "node-id", "", "Node ID to validate (required)") + validatorAddAutoRenewedCmd.Flags().StringVar(&valNodeEndpoint, "node-endpoint", "", "Validator node endpoint (fallback mode) to fetch BLS proof of possession") + validatorAddAutoRenewedCmd.Flags().StringVar(&valBLSPublicKey, "bls-public-key", "", "Validator BLS public key (hex, recommended/manual mode)") + validatorAddAutoRenewedCmd.Flags().StringVar(&valBLSPoP, "bls-pop", "", "Validator BLS proof of possession signature (hex, recommended/manual mode)") + validatorAddAutoRenewedCmd.Flags().Float64Var(&valStakeAmount, "stake", 0, "Stake amount in AVAX (min 2000)") + validatorAddAutoRenewedCmd.Flags().StringVar(&valAutoPeriod, "period", "336h", "Auto-renewal cycle duration (for example, 336h for 14 days)") + validatorAddAutoRenewedCmd.Flags().Float64Var(&valDelegationFee, "delegation-fee", 0.02, "Delegation fee (0.02 = 2%)") + validatorAddAutoRenewedCmd.Flags().Float64Var(&valAutoCompound, "auto-compound", 1, "Fraction of rewards to auto-compound (0.3 = 30%, 1 = 100%)") + validatorAddAutoRenewedCmd.Flags().StringVar(&valRewardAddr, "reward-address", "", "Reward address (default: own address)") + validatorAddAutoRenewedCmd.Flags().StringVar(&valOwnerAddr, "owner-address", "", "Address authorized to update auto-renew config (default: own address)") + + // Set auto-renewed validator config flags + validatorSetAutoConfigCmd.Flags().StringVar(&valSetAutoTxID, "tx-id", "", "Original AddAutoRenewedValidatorTx ID (required)") + validatorSetAutoConfigCmd.Flags().StringVar(&valSetAutoPeriod, "period", "", "Next auto-renewal cycle duration, or 0 to exit after the current cycle (required)") + validatorSetAutoConfigCmd.Flags().Float64Var(&valSetAutoCompound, "auto-compound", 0, "Fraction of rewards to auto-compound (0.3 = 30%, 1 = 100%) (required)") + + // Reward auto-renewed validator flags + validatorRewardAutoCmd.Flags().StringVar(&valRewardAutoTxID, "tx-id", "", "Original AddAutoRenewedValidatorTx ID (required)") + validatorRewardAutoCmd.Flags().StringVar(&valRewardAutoTime, "timestamp", "", "Cycle end timestamp as RFC3339 or Unix seconds (required)") + // Delegate flags validatorDelegateCmd.Flags().StringVar(&valNodeID, "node-id", "", "Node ID to delegate to") validatorDelegateCmd.Flags().Float64Var(&valStakeAmount, "stake", 0, "Stake amount in AVAX (min 25)") diff --git a/go.mod b/go.mod index cd125df..fb5e9f6 100644 --- a/go.mod +++ b/go.mod @@ -1,30 +1,30 @@ module github.com/ava-labs/platform-cli -go 1.25.9 +go 1.25.11 require ( - github.com/ava-labs/avalanchego v1.14.1 + github.com/ava-labs/avalanchego v1.14.3-0.20260602193739-919446e8501f github.com/ava-labs/ledger-avalanche-go v1.1.0 - github.com/ava-labs/libevm v1.13.15-0.20251210210615-b8e76562a300 + github.com/ava-labs/libevm v1.13.15-0.20260602011657-ad0081e3b988 github.com/spf13/cobra v1.9.1 - golang.org/x/crypto v0.45.0 - golang.org/x/term v0.37.0 + golang.org/x/crypto v0.50.0 + golang.org/x/term v0.42.0 ) require ( connectrpc.com/connect v1.18.1 // indirect connectrpc.com/grpcreflect v1.3.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/StephenButtolph/canoto v0.17.3 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/StephenButtolph/canoto v0.18.0 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect - github.com/ava-labs/avalanchego/graft/coreth v0.0.0-20251203215505-70148edc6eca // indirect + github.com/ava-labs/avalanchego/graft/coreth v1.14.3-0.20260602193739-919446e8501f // indirect + github.com/ava-labs/avalanchego/graft/evm v1.14.3-0.20260602193739-919446e8501f // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -49,11 +49,11 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect - github.com/gofrs/flock v0.8.1 // indirect + github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/renameio/v2 v2.0.0 // indirect @@ -61,7 +61,7 @@ require ( github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.4 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -72,8 +72,8 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/moby/spdystream v0.2.0 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/moby/spdystream v0.5.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect @@ -87,7 +87,7 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.7.0 // indirect github.com/sagikazarmark/locafero v0.9.0 // indirect @@ -95,7 +95,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.14.0 // indirect github.com/spf13/cast v1.9.2 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.20.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.14 // indirect @@ -107,31 +107,29 @@ require ( github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/otel v1.40.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect - go.opentelemetry.io/proto/otlp v1.7.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/oauth2 v0.35.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.38.0 // indirect - gonum.org/v1/gonum v0.16.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/grpc v1.75.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect + gonum.org/v1/gonum v0.17.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 3c9e24a..4885c40 100644 --- a/go.sum +++ b/go.sum @@ -12,11 +12,11 @@ github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMd github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/StephenButtolph/canoto v0.17.3 h1:lvsnYD4b96vD1knnmp1xCmZqfYpY/jSeRozGdOfdvGI= -github.com/StephenButtolph/canoto v0.17.3/go.mod h1:IcnAHC6nJUfQFVR9y60ko2ecUqqHHSB6UwI9NnBFZnE= +github.com/StephenButtolph/canoto v0.18.0 h1:czLis9aEly5R/ExPwB5X0PJLhXi7Sv4PpffaAJV3KnE= +github.com/StephenButtolph/canoto v0.18.0/go.mod h1:01RsiQp1gnV1eJ6LwygP6buPCLUoAz7jKadQSB0FI0o= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -26,16 +26,18 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/ava-labs/avalanchego v1.14.1 h1:955YG175dhyFibiPr1LA1rDw9x8Vt1UcLuNwRLOk1kM= -github.com/ava-labs/avalanchego v1.14.1/go.mod h1:TWuYmX/Wmfdd+9KvFZJHGldQ6SXq0jZ334T0kUOaJsM= -github.com/ava-labs/avalanchego/graft/coreth v0.0.0-20251203215505-70148edc6eca h1:zZIQZhOqKe82SUvEx7IeRVoahjyKI0gfouHPQkvEHeI= -github.com/ava-labs/avalanchego/graft/coreth v0.0.0-20251203215505-70148edc6eca/go.mod h1:y+/5DAxCTLAXdWRxAYN1V8DV0DIF7uHhOOeNa9oASuU= -github.com/ava-labs/firewood-go-ethhash/ffi v0.0.18 h1:Lk4yxNL3iZMRxKZlTKVCHp0Rg7i5QclRei0ZKCgtPac= -github.com/ava-labs/firewood-go-ethhash/ffi v0.0.18/go.mod h1:hR/JSGXxST9B9olwu/NpLXHAykfAyNGfyKnYQqiiOeE= +github.com/ava-labs/avalanchego v1.14.3-0.20260602193739-919446e8501f h1:2cqY/0D0y9Sa2Baztu9Fg3QGjuglxihEdXNdDOa878o= +github.com/ava-labs/avalanchego v1.14.3-0.20260602193739-919446e8501f/go.mod h1:jIUfPDCGYX+oDyM0Ch+EC1hv0uki94xyjNnu1tf1fOQ= +github.com/ava-labs/avalanchego/graft/coreth v1.14.3-0.20260602193739-919446e8501f h1:BJ96PwQIvi+ZVpgLAbSsCyGvtDMBvDhDNrinEUPbS4o= +github.com/ava-labs/avalanchego/graft/coreth v1.14.3-0.20260602193739-919446e8501f/go.mod h1:26DyfT1dixgAro93kATSn0IwMsClMLhdhyfG/wn1ggg= +github.com/ava-labs/avalanchego/graft/evm v1.14.3-0.20260602193739-919446e8501f h1:1X6Vx7YtLBc2y5HqG3u5cXF7w8HNHwtW6jGUCXCHYOg= +github.com/ava-labs/avalanchego/graft/evm v1.14.3-0.20260602193739-919446e8501f/go.mod h1:26znzSsbvyDdC8gt8pzQNdANjD5xaEXYkJsaUQl28O4= +github.com/ava-labs/firewood-go-ethhash/ffi v0.5.0 h1:LXdgVYLV01sn2g4hqZUU8kP3/v3Uf4/1/069rFcc1u8= +github.com/ava-labs/firewood-go-ethhash/ffi v0.5.0/go.mod h1:MoUHYlFrwaflfLpHt8nmQUHoLy2CCHaFNH/n7vazUuI= github.com/ava-labs/ledger-avalanche-go v1.1.0 h1:OkscKtb/gX20HBt8RyAtwXLrQnCEls5SzWGieE7NoNM= github.com/ava-labs/ledger-avalanche-go v1.1.0/go.mod h1:mAlG9ptnPjvNoLGLHXnM3slGY8ewvBJtJNVTEjG8KvI= -github.com/ava-labs/libevm v1.13.15-0.20251210210615-b8e76562a300 h1:9VRvqASGSAnQ9tKVRKGH8Q0Yq8efCwYTBWp0p2creho= -github.com/ava-labs/libevm v1.13.15-0.20251210210615-b8e76562a300/go.mod h1:DqSotSn4Dx/UJV+d3svfW8raR+cH7+Ohl9BpsQ5HlGU= +github.com/ava-labs/libevm v1.13.15-0.20260602011657-ad0081e3b988 h1:h18i7JfNG4qiUlpE1ZZINRa1BZaPVdbNXQxO/2ol4tE= +github.com/ava-labs/libevm v1.13.15-0.20260602011657-ad0081e3b988/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -66,10 +68,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= -github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -178,14 +178,15 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -213,8 +214,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -244,11 +245,10 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -326,18 +326,18 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= @@ -347,8 +347,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y= +github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -383,16 +383,16 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= -github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= @@ -416,8 +416,9 @@ github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2 github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -454,8 +455,9 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= @@ -525,24 +527,24 @@ github.com/zondax/ledger-go v1.0.1 h1:Ks/2tz/dOF+dbRynfZ0dEhcdL1lqw43Sa0zMXHpQ3a github.com/zondax/ledger-go v1.0.1/go.mod h1:j7IgMY39f30apthJYMd1YsHZRqdyu4KbVmUp0nU78X0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= -go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= -go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= @@ -560,11 +562,11 @@ golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= -golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -573,8 +575,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -598,11 +600,11 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -610,8 +612,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -647,20 +649,20 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= @@ -678,15 +680,15 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -694,18 +696,18 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -717,8 +719,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/pchain/pchain.go b/pkg/pchain/pchain.go index 9e333a3..d07fc4d 100644 --- a/pkg/pchain/pchain.go +++ b/pkg/pchain/pchain.go @@ -9,9 +9,11 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + avmtypes "github.com/ava-labs/avalanchego/vms/types" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" "github.com/ava-labs/platform-cli/pkg/wallet" ) @@ -209,6 +211,213 @@ func issueAddPermissionlessValidatorTx( return tx.ID(), nil } +// AddAutoRenewedValidatorConfig holds configuration for adding an auto-renewed +// primary network validator. +type AddAutoRenewedValidatorConfig struct { + NodeID ids.NodeID + StakeAmt uint64 // in nAVAX + RewardAddr ids.ShortID + ValidatorAuthorityAddr ids.ShortID + DelegationFee uint32 // in parts per million (1_000_000 = 100%) + AutoCompoundRewardShares uint32 // in parts per million (1_000_000 = 100%) + Period time.Duration // auto-renewal cycle duration + BLSSigner *signer.ProofOfPossession // BLS proof of possession for the validator +} + +// AddAutoRenewedValidator adds an auto-renewed validator to the primary network. +func AddAutoRenewedValidator(ctx context.Context, w *wallet.Wallet, cfg AddAutoRenewedValidatorConfig) (ids.ID, error) { + avaxAssetID := w.PWallet().Builder().Context().AVAXAssetID + return issueAddAutoRenewedValidatorTx( + w.PWallet().Builder().NewAddPermissionlessValidatorTx, + w.PWallet().IssueUnsignedTx, + avaxAssetID, + cfg, + common.WithContext(ctx), + ) +} + +func issueAddAutoRenewedValidatorTx( + buildStakeTxFn func( + vdr *txs.SubnetValidator, + signer signer.Signer, + assetID ids.ID, + validationRewardsOwner *secp256k1fx.OutputOwners, + delegationRewardsOwner *secp256k1fx.OutputOwners, + shares uint32, + options ...common.Option, + ) (*txs.AddPermissionlessValidatorTx, error), + issueUnsignedTxFn func( + utx txs.UnsignedTx, + options ...common.Option, + ) (*txs.Tx, error), + avaxAssetID ids.ID, + cfg AddAutoRenewedValidatorConfig, + options ...common.Option, +) (ids.ID, error) { + rewardsOwner := &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{cfg.RewardAddr}, + } + validatorAuthority := &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{cfg.ValidatorAuthorityAddr}, + } + + stakeTx, err := buildStakeTxFn( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: cfg.NodeID, + Wght: cfg.StakeAmt, + }, + Subnet: ids.Empty, + }, + cfg.BLSSigner, + avaxAssetID, + rewardsOwner, + rewardsOwner, + cfg.DelegationFee, + options..., + ) + if err != nil { + return ids.Empty, fmt.Errorf("failed to build AddAutoRenewedValidatorTx: %w", err) + } + + tx, err := issueUnsignedTxFn( + &txs.AddAutoRenewedValidatorTx{ + BaseTx: stakeTx.BaseTx, + ValidatorNodeID: avmtypes.JSONByteSlice(cfg.NodeID.Bytes()), + Signer: cfg.BLSSigner, + StakeOuts: stakeTx.StakeOuts, + ValidatorRewardsOwner: rewardsOwner, + DelegatorRewardsOwner: rewardsOwner, + ValidatorAuthority: validatorAuthority, + DelegationShares: cfg.DelegationFee, + AutoCompoundRewardShares: cfg.AutoCompoundRewardShares, + Period: uint64(cfg.Period / time.Second), + }, + options..., + ) + if err != nil { + return ids.Empty, fmt.Errorf("failed to issue AddAutoRenewedValidatorTx: %w", err) + } + return tx.ID(), nil +} + +// SetAutoRenewedValidatorConfigTxConfig holds configuration for updating an +// auto-renewed validator's next-cycle configuration. +type SetAutoRenewedValidatorConfigTxConfig struct { + TxID ids.ID + AutoCompoundRewardShares uint32 // in parts per million (1_000_000 = 100%) + Period time.Duration // 0 means exit after the current cycle +} + +// SetAutoRenewedValidatorConfig updates an auto-renewed validator's next-cycle +// configuration. +func SetAutoRenewedValidatorConfig(ctx context.Context, w *wallet.Wallet, cfg SetAutoRenewedValidatorConfigTxConfig) (ids.ID, error) { + return issueSetAutoRenewedValidatorConfigTx( + w.PWallet().Builder().NewDisableL1ValidatorTx, + w.PWallet().IssueUnsignedTx, + cfg, + common.WithContext(ctx), + ) +} + +func issueSetAutoRenewedValidatorConfigTx( + buildAuthTxFn func( + validationID ids.ID, + options ...common.Option, + ) (*txs.DisableL1ValidatorTx, error), + issueUnsignedTxFn func( + utx txs.UnsignedTx, + options ...common.Option, + ) (*txs.Tx, error), + cfg SetAutoRenewedValidatorConfigTxConfig, + options ...common.Option, +) (ids.ID, error) { + authTx, err := buildAuthTxFn( + cfg.TxID, + options..., + ) + if err != nil { + return ids.Empty, fmt.Errorf("failed to build SetAutoRenewedValidatorConfigTx: %w", err) + } + + tx, err := issueUnsignedTxFn( + &txs.SetAutoRenewedValidatorConfigTx{ + BaseTx: authTx.BaseTx, + TxID: cfg.TxID, + Auth: authTx.DisableAuth, + AutoCompoundRewardShares: cfg.AutoCompoundRewardShares, + Period: uint64(cfg.Period / time.Second), + }, + options..., + ) + if err != nil { + return ids.Empty, fmt.Errorf("failed to issue SetAutoRenewedValidatorConfigTx: %w", err) + } + return tx.ID(), nil +} + +// RewardAutoRenewedValidatorConfig holds configuration for rewarding or exiting +// an auto-renewed validator at the end of a validation cycle. +type RewardAutoRenewedValidatorConfig struct { + TxID ids.ID + Timestamp uint64 // cycle end timestamp in Unix seconds +} + +// RewardAutoRenewedValidator rewards or exits an auto-renewed validator at the +// end of a validation cycle. +func RewardAutoRenewedValidator(ctx context.Context, w *wallet.Wallet, cfg RewardAutoRenewedValidatorConfig) (ids.ID, error) { + client := platformvm.NewClient(w.Config().RPCURL) + return issueRewardAutoRenewedValidatorTx( + func(ctx context.Context, txBytes []byte) (ids.ID, error) { + return client.IssueTx(ctx, txBytes) + }, + func(ctx context.Context, txID ids.ID, freq time.Duration) error { + return client.AwaitTxAccepted(ctx, txID, freq) + }, + cfg, + common.WithContext(ctx), + ) +} + +func issueRewardAutoRenewedValidatorTx( + issueTxFn func( + ctx context.Context, + txBytes []byte, + ) (ids.ID, error), + awaitTxAcceptedFn func( + ctx context.Context, + txID ids.ID, + freq time.Duration, + ) error, + cfg RewardAutoRenewedValidatorConfig, + options ...common.Option, +) (ids.ID, error) { + ops := common.NewOptions(options) + ctx := ops.Context() + + tx := &txs.Tx{Unsigned: &txs.RewardAutoRenewedValidatorTx{ + TxID: cfg.TxID, + Timestamp: cfg.Timestamp, + }} + if err := tx.Initialize(txs.Codec); err != nil { + return ids.Empty, fmt.Errorf("failed to initialize RewardAutoRenewedValidatorTx: %w", err) + } + + txID, err := issueTxFn(ctx, tx.Bytes()) + if err != nil { + return ids.Empty, fmt.Errorf("failed to issue RewardAutoRenewedValidatorTx: %w", err) + } + if ops.AssumeDecided() { + return txID, nil + } + if err := awaitTxAcceptedFn(ctx, txID, ops.PollFrequency()); err != nil { + return ids.Empty, fmt.Errorf("failed waiting for RewardAutoRenewedValidatorTx acceptance: %w", err) + } + return txID, nil +} + // AddDelegatorConfig holds configuration for adding a delegator. type AddDelegatorConfig struct { NodeID ids.NodeID diff --git a/pkg/pchain/pchain_test.go b/pkg/pchain/pchain_test.go index a09a09f..f017e04 100644 --- a/pkg/pchain/pchain_test.go +++ b/pkg/pchain/pchain_test.go @@ -1,6 +1,7 @@ package pchain import ( + "bytes" "context" "errors" "strings" @@ -264,6 +265,277 @@ func TestIssueAddPermissionlessValidatorTx(t *testing.T) { } } +func TestIssueAddAutoRenewedValidatorTx(t *testing.T) { + nodeID := ids.GenerateTestNodeID() + rewardAddr := ids.GenerateTestShortID() + authorityAddr := ids.GenerateTestShortID() + assetID := ids.GenerateTestID() + pop := &signer.ProofOfPossession{} + cfg := AddAutoRenewedValidatorConfig{ + NodeID: nodeID, + StakeAmt: 123, + RewardAddr: rewardAddr, + ValidatorAuthorityAddr: authorityAddr, + DelegationFee: 20_000, + AutoCompoundRewardShares: 500_000, + Period: 14 * 24 * time.Hour, + BLSSigner: pop, + } + txID := ids.GenerateTestID() + stakeOuts := []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: cfg.StakeAmt, + }, + }} + + var gotVdr *txs.SubnetValidator + var gotSigner signer.Signer + var gotAssetID ids.ID + var gotValidationRewardsOwner *secp256k1fx.OutputOwners + var gotDelegationRewardsOwner *secp256k1fx.OutputOwners + var gotDelegationShares uint32 + var gotUnsignedTx txs.UnsignedTx + gotTxID, err := issueAddAutoRenewedValidatorTx( + func( + vdr *txs.SubnetValidator, + signer signer.Signer, + assetID ids.ID, + validationRewardsOwner *secp256k1fx.OutputOwners, + delegationRewardsOwner *secp256k1fx.OutputOwners, + shares uint32, + _ ...common.Option, + ) (*txs.AddPermissionlessValidatorTx, error) { + gotVdr = vdr + gotSigner = signer + gotAssetID = assetID + gotValidationRewardsOwner = validationRewardsOwner + gotDelegationRewardsOwner = delegationRewardsOwner + gotDelegationShares = shares + return &txs.AddPermissionlessValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: 1, + }}, + StakeOuts: stakeOuts, + }, nil + }, + func(utx txs.UnsignedTx, _ ...common.Option) (*txs.Tx, error) { + gotUnsignedTx = utx + return &txs.Tx{TxID: txID}, nil + }, + assetID, + cfg, + ) + if err != nil { + t.Fatalf("issueAddAutoRenewedValidatorTx() returned error: %v", err) + } + if gotTxID != txID { + t.Fatalf("issueAddAutoRenewedValidatorTx() txID = %s, want %s", gotTxID, txID) + } + if gotVdr == nil { + t.Fatal("issueAddAutoRenewedValidatorTx() builder validator is nil") + } + if gotVdr.Validator.NodeID != cfg.NodeID { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder nodeID = %s, want %s", gotVdr.Validator.NodeID, cfg.NodeID) + } + if gotVdr.Validator.Wght != cfg.StakeAmt { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder weight = %d, want %d", gotVdr.Validator.Wght, cfg.StakeAmt) + } + if gotVdr.Subnet != ids.Empty { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder subnet = %s, want Primary Network (ids.Empty)", gotVdr.Subnet) + } + gotPop, ok := gotSigner.(*signer.ProofOfPossession) + if !ok { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder signer type = %T, want *signer.ProofOfPossession", gotSigner) + } + if gotPop != pop { + t.Fatal("issueAddAutoRenewedValidatorTx() builder signer pointer mismatch") + } + if gotAssetID != assetID { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder assetID = %s, want %s", gotAssetID, assetID) + } + if gotValidationRewardsOwner == nil || len(gotValidationRewardsOwner.Addrs) != 1 || gotValidationRewardsOwner.Addrs[0] != rewardAddr { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder validation owner addrs = %#v, want [%s]", gotValidationRewardsOwner, rewardAddr) + } + if gotDelegationRewardsOwner == nil || len(gotDelegationRewardsOwner.Addrs) != 1 || gotDelegationRewardsOwner.Addrs[0] != rewardAddr { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder delegation owner addrs = %#v, want [%s]", gotDelegationRewardsOwner, rewardAddr) + } + if gotDelegationShares != cfg.DelegationFee { + t.Fatalf("issueAddAutoRenewedValidatorTx() builder delegation shares = %d, want %d", gotDelegationShares, cfg.DelegationFee) + } + + autoTx, ok := gotUnsignedTx.(*txs.AddAutoRenewedValidatorTx) + if !ok { + t.Fatalf("issueAddAutoRenewedValidatorTx() unsigned type = %T, want *txs.AddAutoRenewedValidatorTx", gotUnsignedTx) + } + if !bytes.Equal(autoTx.ValidatorNodeID, cfg.NodeID.Bytes()) { + t.Fatalf("issueAddAutoRenewedValidatorTx() nodeID bytes = %x, want %x", []byte(autoTx.ValidatorNodeID), cfg.NodeID.Bytes()) + } + if autoTx.Signer != pop { + t.Fatal("issueAddAutoRenewedValidatorTx() auto-renew signer pointer mismatch") + } + if len(autoTx.StakeOuts) != 1 || autoTx.StakeOuts[0] != stakeOuts[0] { + t.Fatalf("issueAddAutoRenewedValidatorTx() stake outs = %#v, want builder stake outs", autoTx.StakeOuts) + } + if autoTx.ValidatorRewardsOwner != gotValidationRewardsOwner { + t.Fatal("issueAddAutoRenewedValidatorTx() validation rewards owner was not reused") + } + if autoTx.DelegatorRewardsOwner != gotDelegationRewardsOwner { + t.Fatal("issueAddAutoRenewedValidatorTx() delegation rewards owner was not reused") + } + validatorAuthority, ok := autoTx.ValidatorAuthority.(*secp256k1fx.OutputOwners) + if !ok { + t.Fatalf("issueAddAutoRenewedValidatorTx() authority type = %T, want *secp256k1fx.OutputOwners", autoTx.ValidatorAuthority) + } + if len(validatorAuthority.Addrs) != 1 || validatorAuthority.Addrs[0] != authorityAddr { + t.Fatalf("issueAddAutoRenewedValidatorTx() authority addrs = %#v, want [%s]", validatorAuthority.Addrs, authorityAddr) + } + if autoTx.DelegationShares != cfg.DelegationFee { + t.Fatalf("issueAddAutoRenewedValidatorTx() delegation shares = %d, want %d", autoTx.DelegationShares, cfg.DelegationFee) + } + if autoTx.AutoCompoundRewardShares != cfg.AutoCompoundRewardShares { + t.Fatalf("issueAddAutoRenewedValidatorTx() auto-compound shares = %d, want %d", autoTx.AutoCompoundRewardShares, cfg.AutoCompoundRewardShares) + } + if autoTx.Period != uint64(cfg.Period/time.Second) { + t.Fatalf("issueAddAutoRenewedValidatorTx() period seconds = %d, want %d", autoTx.Period, uint64(cfg.Period/time.Second)) + } +} + +func TestIssueSetAutoRenewedValidatorConfigTx(t *testing.T) { + validatorTxID := ids.GenerateTestID() + issuedTxID := ids.GenerateTestID() + auth := &secp256k1fx.Input{SigIndices: []uint32{0}} + cfg := SetAutoRenewedValidatorConfigTxConfig{ + TxID: validatorTxID, + AutoCompoundRewardShares: 250_000, + Period: 7 * 24 * time.Hour, + } + + var gotAuthTxID ids.ID + var gotUnsignedTx txs.UnsignedTx + gotTxID, err := issueSetAutoRenewedValidatorConfigTx( + func(validationID ids.ID, _ ...common.Option) (*txs.DisableL1ValidatorTx, error) { + gotAuthTxID = validationID + return &txs.DisableL1ValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: 1, + }}, + ValidationID: validationID, + DisableAuth: auth, + }, nil + }, + func(utx txs.UnsignedTx, _ ...common.Option) (*txs.Tx, error) { + gotUnsignedTx = utx + return &txs.Tx{TxID: issuedTxID}, nil + }, + cfg, + ) + if err != nil { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() returned error: %v", err) + } + if gotTxID != issuedTxID { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() txID = %s, want %s", gotTxID, issuedTxID) + } + if gotAuthTxID != validatorTxID { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() auth txID = %s, want %s", gotAuthTxID, validatorTxID) + } + setTx, ok := gotUnsignedTx.(*txs.SetAutoRenewedValidatorConfigTx) + if !ok { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() unsigned type = %T, want *txs.SetAutoRenewedValidatorConfigTx", gotUnsignedTx) + } + if setTx.TxID != validatorTxID { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() validator txID = %s, want %s", setTx.TxID, validatorTxID) + } + if setTx.Auth != auth { + t.Fatal("issueSetAutoRenewedValidatorConfigTx() auth pointer mismatch") + } + if setTx.AutoCompoundRewardShares != cfg.AutoCompoundRewardShares { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() auto-compound shares = %d, want %d", setTx.AutoCompoundRewardShares, cfg.AutoCompoundRewardShares) + } + if setTx.Period != uint64(cfg.Period/time.Second) { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() period seconds = %d, want %d", setTx.Period, uint64(cfg.Period/time.Second)) + } +} + +func TestIssueSetAutoRenewedValidatorConfigTxAllowsZeroPeriod(t *testing.T) { + cfg := SetAutoRenewedValidatorConfigTxConfig{ + TxID: ids.GenerateTestID(), + AutoCompoundRewardShares: 0, + Period: 0, + } + + var gotPeriodSeconds uint64 + _, err := issueSetAutoRenewedValidatorConfigTx( + func(validationID ids.ID, _ ...common.Option) (*txs.DisableL1ValidatorTx, error) { + return &txs.DisableL1ValidatorTx{ + ValidationID: validationID, + DisableAuth: &secp256k1fx.Input{}, + }, nil + }, + func(utx txs.UnsignedTx, _ ...common.Option) (*txs.Tx, error) { + setTx, ok := utx.(*txs.SetAutoRenewedValidatorConfigTx) + if !ok { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() unsigned type = %T, want *txs.SetAutoRenewedValidatorConfigTx", utx) + } + gotPeriodSeconds = setTx.Period + return &txs.Tx{TxID: ids.GenerateTestID()}, nil + }, + cfg, + ) + if err != nil { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() returned error: %v", err) + } + if gotPeriodSeconds != 0 { + t.Fatalf("issueSetAutoRenewedValidatorConfigTx() period seconds = %d, want 0", gotPeriodSeconds) + } +} + +func TestIssueRewardAutoRenewedValidatorTx(t *testing.T) { + validatorTxID := ids.GenerateTestID() + issuedTxID := ids.GenerateTestID() + cfg := RewardAutoRenewedValidatorConfig{ + TxID: validatorTxID, + Timestamp: 1780576200, + } + + var gotTxBytes []byte + var gotAwaitTxID ids.ID + gotTxID, err := issueRewardAutoRenewedValidatorTx( + func(_ context.Context, txBytes []byte) (ids.ID, error) { + gotTxBytes = txBytes + return issuedTxID, nil + }, + func(_ context.Context, txID ids.ID, _ time.Duration) error { + gotAwaitTxID = txID + return nil + }, + cfg, + ) + if err != nil { + t.Fatalf("issueRewardAutoRenewedValidatorTx() returned error: %v", err) + } + if gotTxID != issuedTxID { + t.Fatalf("issueRewardAutoRenewedValidatorTx() txID = %s, want %s", gotTxID, issuedTxID) + } + if gotAwaitTxID != issuedTxID { + t.Fatalf("issueRewardAutoRenewedValidatorTx() awaited txID = %s, want %s", gotAwaitTxID, issuedTxID) + } + parsedTx, err := txs.Parse(txs.Codec, gotTxBytes) + if err != nil { + t.Fatalf("issueRewardAutoRenewedValidatorTx() failed to parse issued bytes: %v", err) + } + rewardTx, ok := parsedTx.Unsigned.(*txs.RewardAutoRenewedValidatorTx) + if !ok { + t.Fatalf("issueRewardAutoRenewedValidatorTx() unsigned type = %T, want *txs.RewardAutoRenewedValidatorTx", parsedTx.Unsigned) + } + if rewardTx.TxID != validatorTxID { + t.Fatalf("issueRewardAutoRenewedValidatorTx() validator txID = %s, want %s", rewardTx.TxID, validatorTxID) + } + if rewardTx.Timestamp != cfg.Timestamp { + t.Fatalf("issueRewardAutoRenewedValidatorTx() timestamp = %d, want %d", rewardTx.Timestamp, cfg.Timestamp) + } +} + func TestIssueAddPermissionlessDelegatorTx(t *testing.T) { nodeID := ids.GenerateTestNodeID() rewardAddr := ids.GenerateTestShortID()