diff --git a/.changeset/whole-symbols-vanish.md b/.changeset/whole-symbols-vanish.md new file mode 100644 index 00000000..ab912d24 --- /dev/null +++ b/.changeset/whole-symbols-vanish.md @@ -0,0 +1,5 @@ +--- +"chainlink-deployments-framework": minor +--- + +add error decode command diff --git a/chain/evm/provider/rpcclient/multiclient.go b/chain/evm/provider/rpcclient/multiclient.go index 1d1a1988..e24d127b 100644 --- a/chain/evm/provider/rpcclient/multiclient.go +++ b/chain/evm/provider/rpcclient/multiclient.go @@ -401,7 +401,10 @@ func (mc *MultiClient) retryWithBackups(ctx context.Context, opName string, op f err = op(timeoutCtx, client) if err != nil { - mc.lggr.Warnf("traceID %q: chain %q: op: %q: client index %d: failed execution - retryable error '%s'", traceID.String(), mc.chainName, opName, rpcIndex, maybeDataErr(err)) + detailedErr := maybeDataErr(err) + mc.lggr.Warnf("traceID %q: chain %q: op: %q: client index %d: failed execution - retryable error '%s'", traceID.String(), mc.chainName, opName, rpcIndex, detailedErr) + err = errors.Join(err, detailedErr) + return err } diff --git a/engine/cld/legacy/cli/mcmsv2/err_decode_helpers.go b/engine/cld/legacy/cli/mcmsv2/err_decode_helpers.go index 62f95d2e..aedeb013 100644 --- a/engine/cld/legacy/cli/mcmsv2/err_decode_helpers.go +++ b/engine/cld/legacy/cli/mcmsv2/err_decode_helpers.go @@ -30,6 +30,10 @@ import ( const noRevertData = "(no revert data)" +type errorSelector [4]byte + +var emptySelector = errorSelector{} + type traceConfig struct { DisableStorage bool `json:"disableStorage,omitempty"` DisableMemory bool `json:"disableMemory,omitempty"` @@ -57,25 +61,25 @@ type ErrSig struct { TypeVer string Name string Inputs abi.Arguments - id [4]byte + id errorSelector } // ErrDecoder indexes custom-error selectors across many ABIs. type ErrDecoder struct { - bySelector map[[4]byte][]ErrSig + bySelector map[errorSelector][]ErrSig registry analyzer.EVMABIRegistry } // NewErrDecoder builds an index from EVM ABI registry. func NewErrDecoder(registry analyzer.EVMABIRegistry) (*ErrDecoder, error) { - idx := make(map[[4]byte][]ErrSig) + idx := make(map[errorSelector][]ErrSig) for tv, jsonABI := range registry.GetAllABIs() { a, err := abi.JSON(strings.NewReader(jsonABI)) if err != nil { return nil, fmt.Errorf("parse ABI for %s: %w", tv, err) } for name, e := range a.Errors { - var key [4]byte + var key errorSelector copy(key[:], e.ID[:4]) // selector is first 4 bytes of the keccak(sig) idx[key] = append(idx[key], ErrSig{ TypeVer: tv, @@ -181,7 +185,7 @@ func (d *ErrDecoder) decodeRecursive(revertData []byte, preferredABIJSON string) } // --- B) Registry lookup - var key [4]byte + var key errorSelector copy(key[:], sel) cands, ok := d.bySelector[key] if !ok { @@ -619,6 +623,160 @@ func prettyRevertFromError(err error, preferredABIJSON string, dec *ErrDecoder) return "", false } +// DecodedExecutionError contains the decoded revert reasons from an ExecutionError. +type DecodedExecutionError struct { + RevertReason string + RevertReasonDecoded bool + UnderlyingReason string + UnderlyingReasonDecoded bool +} + +// tryDecodeExecutionError decodes an evm.ExecutionError into human-readable strings. +// It first checks for RevertReasonDecoded and UnderlyingReasonDecoded fields. +// If those are not available, it extracts RevertReasonRaw and UnderlyingReasonRaw from the struct +// and decodes them using the provided ErrDecoder to match error selectors against the ABI registry. +func tryDecodeExecutionError(execError *evm.ExecutionError, dec *ErrDecoder) DecodedExecutionError { + if execError == nil { + return DecodedExecutionError{} + } + + revertReason, revertDecoded := decodeRevertReasonWithStatus(execError, dec) + underlyingReason, underlyingDecoded := decodeUnderlyingReasonWithStatus(execError, dec) + + return DecodedExecutionError{ + RevertReason: revertReason, + RevertReasonDecoded: revertDecoded, + UnderlyingReason: underlyingReason, + UnderlyingReasonDecoded: underlyingDecoded, + } +} + +// decodeRevertReasonWithStatus decodes the revert reason and returns both the reason and decoded status. +func decodeRevertReasonWithStatus(execError *evm.ExecutionError, dec *ErrDecoder) (string, bool) { + if execError.RevertReasonDecoded != "" { + return execError.RevertReasonDecoded, true + } + + if execError.RevertReasonRaw == nil { + return "", false + } + + hasData := len(execError.RevertReasonRaw.Data) > 0 + hasSelector := execError.RevertReasonRaw.Selector != emptySelector + + if hasData { + if reason, decoded := tryDecodeFromData(execError.RevertReasonRaw, dec); decoded { + return reason, true + } + } + + if hasSelector && !hasData { + reason := decodeSelectorOnly(execError.RevertReasonRaw.Selector, dec) + return reason, reason != "" + } + + return "", false +} + +// tryDecodeFromData attempts to decode revert data from the CustomErrorData. +func tryDecodeFromData(raw *evm.CustomErrorData, dec *ErrDecoder) (string, bool) { + if len(raw.Data) >= 4 { + if reason, decoded := decodeRevertDataFromBytes(raw.Data, dec, ""); decoded { + return reason, true + } + } + + if raw.Selector != emptySelector { + if combined := raw.Combined(); len(combined) > 4 { + return decodeRevertDataFromBytes(combined, dec, "") + } + } + + return "", false +} + +// decodeSelectorOnly decodes an error when only the selector is available. +func decodeSelectorOnly(selector errorSelector, dec *ErrDecoder) string { + if dec == nil { + return formatSelectorHex(selector) + } + + if matched, ok := dec.matchErrorSelector(selector); ok { + return matched + } + + return formatSelectorHex(selector) +} + +// formatSelectorHex formats a selector as a hex string. +func formatSelectorHex(selector errorSelector) string { + return "custom error 0x" + hex.EncodeToString(selector[:]) +} + +// decodeUnderlyingReasonWithStatus decodes the underlying reason and returns both the reason and decoded status. +func decodeUnderlyingReasonWithStatus(execError *evm.ExecutionError, dec *ErrDecoder) (string, bool) { + if execError.UnderlyingReasonDecoded != "" { + return execError.UnderlyingReasonDecoded, true + } + + if execError.UnderlyingReasonRaw == "" { + return "", false + } + + reason, decoded := decodeRevertData(execError.UnderlyingReasonRaw, dec, "") + + return reason, decoded +} + +// decodeRevertData decodes a hex string containing revert data into a human-readable error message. +func decodeRevertData(hexStr string, dec *ErrDecoder, preferredABIJSON string) (string, bool) { + if hexStr == "" { + return "", false + } + + data, err := hexutil.Decode(hexStr) + if err != nil || len(data) == 0 { + return "", false + } + + return decodeRevertDataFromBytes(data, dec, preferredABIJSON) +} + +// matchErrorSelector tries to resolve a 4-byte selector to an error name. +// Returns "ErrorName(...) @Type@Version" if found in registry, or empty string if not found. +func (d *ErrDecoder) matchErrorSelector(sel4 errorSelector) (string, bool) { + if d == nil || d.bySelector == nil { + return "", false + } + + cands, ok := d.bySelector[sel4] + if !ok || len(cands) == 0 { + return "", false + } + + // If multiple ABIs define the same selector, pick the first. + c := cands[0] + + return fmt.Sprintf("%s(...) @%s", c.Name, c.TypeVer), true +} + +// decodeRevertDataFromBytes decodes revert data bytes into a human-readable error message. +func decodeRevertDataFromBytes(data []byte, dec *ErrDecoder, preferredABIJSON string) (string, bool) { + if len(data) == 0 { + return "", false + } + + if dec == nil { + if len(data) >= 4 { + return "custom error 0x" + hex.EncodeToString(data[:4]), true + } + + return "", false + } + + return prettyFromBytes(data, preferredABIJSON, dec) +} + type callContractClient interface { CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) } diff --git a/engine/cld/legacy/cli/mcmsv2/err_decode_helpers_test.go b/engine/cld/legacy/cli/mcmsv2/err_decode_helpers_test.go index 2e7db14e..a98ab00c 100644 --- a/engine/cld/legacy/cli/mcmsv2/err_decode_helpers_test.go +++ b/engine/cld/legacy/cli/mcmsv2/err_decode_helpers_test.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" mcmsbindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" timelockbindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_0/timelock" + "github.com/smartcontractkit/mcms/sdk/evm" "github.com/smartcontractkit/mcms/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -43,7 +44,7 @@ func mustType(t *testing.T, typ string) abi.Type { return ty } -func errorSelector(name string, args abi.Arguments) []byte { +func getErrorSelector(name string, args abi.Arguments) []byte { ts := make([]string, len(args)) for i, a := range args { ts[i] = a.Type.String() @@ -59,7 +60,7 @@ func buildCustomErrorRevert(t *testing.T, name string, args abi.Arguments, vals enc, err := args.Pack(vals...) require.NoError(t, err) - return append(errorSelector(name, args), enc...) + return append(getErrorSelector(name, args), enc...) } func buildStdErrorRevert(t *testing.T, msg string) []byte { @@ -466,3 +467,159 @@ func Test_DiagnoseTimelockRevert(t *testing.T) { assert.Contains(t, es, "first revert") assert.Contains(t, es, "second revert") } + +func Test_tryDecodeExecutionError(t *testing.T) { + t.Parallel() + + // Create test ABI with custom error + abiJSON := `[ + {"type":"error","name":"InsufficientBalance","inputs":[ + {"name":"required","type":"uint256"}, + {"name":"available","type":"uint256"}]} + ]` + + // Build custom error revert data + u256Ty := mustType(t, "uint256") + errArgs := abi.Arguments{ + {Name: "required", Type: u256Ty}, + {Name: "available", Type: u256Ty}, + } + required := big.NewInt(100) + available := big.NewInt(50) + customRevert := buildCustomErrorRevert(t, "InsufficientBalance", errArgs, required, available) + + // Create registry with the ABI + ds := cldfds.NewMemoryDataStore() + reg, err := analyzer.NewEnvironmentEVMRegistry(cldf.Environment{ + ExistingAddresses: cldf.NewMemoryAddressBook(), + DataStore: ds.Seal(), + }, map[string]string{ + "TestContract@1.0.0": abiJSON, + }) + require.NoError(t, err) + + dec, err := NewErrDecoder(reg) + require.NoError(t, err) + + t.Run("nil error returns empty result", func(t *testing.T) { + t.Parallel() + + result := tryDecodeExecutionError(nil, dec) + assert.False(t, result.RevertReasonDecoded) + assert.False(t, result.UnderlyingReasonDecoded) + assert.Empty(t, result.RevertReason) + assert.Empty(t, result.UnderlyingReason) + }) + + t.Run("decodes revert reason from Data field", func(t *testing.T) { + t.Parallel() + + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{ + Data: customRevert, + }, + } + + result := tryDecodeExecutionError(execErr, dec) + require.True(t, result.RevertReasonDecoded, "should decode revert reason") + assert.Contains(t, result.RevertReason, "InsufficientBalance") + assert.Contains(t, result.RevertReason, "@TestContract@1.0.0") + assert.Contains(t, result.RevertReason, required.String()) + assert.Contains(t, result.RevertReason, available.String()) + }) + + t.Run("decodes revert reason from Selector field", func(t *testing.T) { + t.Parallel() + + var selector [4]byte + copy(selector[:], customRevert[:4]) + + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{ + Selector: selector, + }, + } + + result := tryDecodeExecutionError(execErr, dec) + require.True(t, result.RevertReasonDecoded, "should decode revert reason from selector") + assert.Contains(t, result.RevertReason, "InsufficientBalance") + }) + + t.Run("decodes standard Error(string)", func(t *testing.T) { + t.Parallel() + + stdRevert := buildStdErrorRevert(t, "test error message") + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{ + Data: stdRevert, + }, + } + + result := tryDecodeExecutionError(execErr, dec) + require.True(t, result.RevertReasonDecoded, "should decode standard error") + assert.Equal(t, "test error message", result.RevertReason) + }) + + t.Run("decodes underlying reason", func(t *testing.T) { + t.Parallel() + + underlyingRevert := buildStdErrorRevert(t, "underlying error") + underlyingHex := "0x" + hex.EncodeToString(underlyingRevert) + + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{ + Data: customRevert, + }, + UnderlyingReasonRaw: underlyingHex, + } + + result := tryDecodeExecutionError(execErr, dec) + require.True(t, result.RevertReasonDecoded) + require.True(t, result.UnderlyingReasonDecoded, "should decode underlying reason") + assert.Equal(t, "underlying error", result.UnderlyingReason) + }) + + t.Run("handles nil decoder", func(t *testing.T) { + t.Parallel() + + var selector [4]byte + copy(selector[:], customRevert[:4]) + + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{ + Selector: selector, + }, + } + + result := tryDecodeExecutionError(execErr, nil) + require.True(t, result.RevertReasonDecoded, "should return selector even without decoder") + assert.Contains(t, result.RevertReason, "custom error 0x") + assert.Contains(t, result.RevertReason, hex.EncodeToString(selector[:])) + }) + + t.Run("handles empty RawRevertReason", func(t *testing.T) { + t.Parallel() + + execErr := &evm.ExecutionError{ + RevertReasonRaw: &evm.CustomErrorData{}, + } + + result := tryDecodeExecutionError(execErr, dec) + assert.False(t, result.RevertReasonDecoded) + assert.Empty(t, result.RevertReason) + }) + + t.Run("handles nil RawRevertReason", func(t *testing.T) { + t.Parallel() + + execErr := &evm.ExecutionError{ + RevertReasonRaw: nil, + UnderlyingReasonRaw: "0x12345678", + } + + result := tryDecodeExecutionError(execErr, dec) + assert.False(t, result.RevertReasonDecoded) + // Underlying reason should still be attempted + assert.NotEmpty(t, result.UnderlyingReason) + }) +} diff --git a/engine/cld/legacy/cli/mcmsv2/mcms_v2.go b/engine/cld/legacy/cli/mcmsv2/mcms_v2.go index f4dcf62f..cf17cae1 100644 --- a/engine/cld/legacy/cli/mcmsv2/mcms_v2.go +++ b/engine/cld/legacy/cli/mcmsv2/mcms_v2.go @@ -4,6 +4,7 @@ import ( "context" "crypto/ecdsa" "crypto/rand" + "encoding/json" "errors" "fmt" "math/big" @@ -118,6 +119,7 @@ func BuildMCMSv2Cmd(lggr logger.Logger, domain cldf_domain.Domain, proposalConte cmd.AddCommand(buildExecuteOperationv2Cmd(lggr, domain, proposalContextProvider)) cmd.AddCommand(buildSetRootv2Cmd(lggr, domain, proposalContextProvider)) cmd.AddCommand(buildGetOpCountV2Cmd(lggr, domain)) + cmd.AddCommand(buildMCMSErrorDecode(lggr, domain, proposalContextProvider)) cmd.AddCommand(buildRunTimelockIsPendingV2Cmd(lggr, domain)) cmd.AddCommand(buildRunTimelockIsReadyToExecuteV2Cmd(lggr, domain)) cmd.AddCommand(buildRunTimelockIsDoneV2Cmd(lggr, domain)) @@ -152,6 +154,118 @@ func newCLIStdErrLogger() (logger.Logger, error) { return lggr, nil } +func buildMCMSErrorDecode(lggr logger.Logger, domain cldf_domain.Domain, proposalCtxProvider analyzer.ProposalContextProvider) *cobra.Command { + var filePath string + + cmd := &cobra.Command{ + Use: "error-decode-evm", + Short: "Decodes the provided tx error data using the domain ABI registry", + PreRun: func(command *cobra.Command, args []string) { + // proposalPath and chainSelector are not needed for this command + command.InheritedFlags().Lookup(proposalPathFlag).Changed = true + command.InheritedFlags().Lookup(chainSelectorFlag).Changed = true + }, + RunE: func(cmd *cobra.Command, args []string) error { + if filePath == "" { + return errors.New("error-file flag is required") + } + + // Get environment from persistent flag + environmentStr, err := cmd.Flags().GetString(environmentFlag) + if err != nil { + return fmt.Errorf("error getting environment flag: %w", err) + } + if environmentStr == "" { + return errors.New("environment flag is required") + } + + // Read the failed transaction data file + data, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("error reading file %s: %w", filePath, err) + } + + // Unmarshal JSON and extract execution_error field + var jsonData map[string]any + if errUnmarshal := json.Unmarshal(data, &jsonData); errUnmarshal != nil { + return fmt.Errorf("error unmarshaling JSON: %w", errUnmarshal) + } + + execErrData, ok := jsonData["execution_error"] + if !ok { + return errors.New("no execution error to decode, json file must contain an 'execution_error' key to get revert reasons decoded") + } + + execErrBytes, err := json.Marshal(execErrData) + if err != nil { + return fmt.Errorf("error marshaling execution_error: %w", err) + } + + var execErr evm.ExecutionError + if errUnmarshal := json.Unmarshal(execErrBytes, &execErr); errUnmarshal != nil { + return fmt.Errorf("error unmarshaling execution_error: %w", errUnmarshal) + } + + // Load environment to get ABI registry (no chains needed to decode) + env, err := cldfenvironment.Load(cmd.Context(), domain, environmentStr, + cldfenvironment.OnlyLoadChainsFor([]uint64{}), + cldfenvironment.WithLogger(lggr), + cldfenvironment.WithoutJD()) + if err != nil { + return fmt.Errorf("error loading environment: %w", err) + } + + // Create ProposalContext to get EVM registry + proposalCtx, err := analyzer.NewDefaultProposalContext(env) + if err != nil { + lggr.Warnf("Failed to create default proposal context: %v. Proceeding without ABI registry.", err) + } + if proposalCtxProvider != nil { + proposalCtx, err = proposalCtxProvider(env) + if err != nil { + return fmt.Errorf("failed to create proposal context: %w", err) + } + } + + // Create error decoder from EVM registry + var errDec *ErrDecoder + if proposalCtx != nil && proposalCtx.GetEVMRegistry() != nil { + errDec, err = NewErrDecoder(proposalCtx.GetEVMRegistry()) + if err != nil { + return fmt.Errorf("error creating error decoder: %w", err) + } + } + + // Decode the error + decoded := tryDecodeExecutionError(&execErr, errDec) + + // Output decoded revert reason + if decoded.RevertReasonDecoded { + fmt.Printf("Revert Reason: %s - decoded: %s\n", execErr.RevertReasonRaw.Selector, decoded.RevertReason) + } else { + fmt.Println("Revert Reason: (could not decode)") + } + + // Output decoded underlying reason if available + if decoded.UnderlyingReasonDecoded { + fmt.Printf("Underlying Reason: %s - decoded: %s\n", execErr.UnderlyingReasonRaw, decoded.UnderlyingReason) + } + + return nil + }, + } + cmd.Flags().StringVar(&filePath, "error-file", "", "path to the json file containing tx error") + panicErr(cmd.MarkFlagRequired("error-file")) + cmd.SetHelpFunc(func(command *cobra.Command, args []string) { + // Hide flags that aren't needed for this command + panicErr(command.Flags().MarkHidden(proposalPathFlag)) + panicErr(command.Flags().MarkHidden(chainSelectorFlag)) + command.Parent().HelpFunc()(command, args) + }) + + return cmd +} + func buildMCMSCheckQuorumv2Cmd(lggr logger.Logger, domain cldf_domain.Domain) *cobra.Command { return &cobra.Command{ Use: "check-quorum", diff --git a/go.mod b/go.mod index 94de5917..7684a780 100644 --- a/go.mod +++ b/go.mod @@ -27,19 +27,19 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 github.com/segmentio/ksuid v1.0.4 github.com/smartcontractkit/ccip-owner-contracts v0.1.0 - github.com/smartcontractkit/chain-selectors v1.0.83 + github.com/smartcontractkit/chain-selectors v1.0.85 github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20250903115155-a68d8c28ae1d github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250805210128-7f8a0f403c3a github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250805210128-7f8a0f403c3a github.com/smartcontractkit/chainlink-protos/job-distributor v0.17.0 github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4 - github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.7 + github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1 github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2 github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358 - github.com/smartcontractkit/mcms v0.30.2 + github.com/smartcontractkit/mcms v0.31.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 @@ -81,7 +81,7 @@ require ( dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect - github.com/BurntSushi/toml v1.4.0 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect github.com/DataDog/zstd v1.5.6 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/VictoriaMetrics/fastcache v1.13.0 // indirect @@ -120,13 +120,13 @@ require ( github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/coder/websocket v1.8.14 // indirect - github.com/consensys/gnark-crypto v0.18.1 // indirect + github.com/consensys/gnark-crypto v0.19.2 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v1.0.0-rc.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect @@ -266,7 +266,7 @@ require ( github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect - github.com/urfave/cli/v2 v2.27.5 // indirect + github.com/urfave/cli/v2 v2.27.7 // indirect github.com/valyala/fastjson v1.6.4 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -294,7 +294,6 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.6.0 // indirect - go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect diff --git a/go.sum b/go.sum index 0a3393a1..3fc3c0b6 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj4 github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY= github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -154,8 +154,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAK github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= -github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/consensys/gnark-crypto v0.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80= +github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -172,16 +172,16 @@ github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4x github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= -github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= @@ -691,8 +691,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9LsA7vTMPv+0n7ClhSFnZFAk= github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= -github.com/smartcontractkit/chain-selectors v1.0.83 h1:FgNLzMCrSE67tTaLsmtBESuzVmStLxJHsiVeSYNW/Es= -github.com/smartcontractkit/chain-selectors v1.0.83/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= +github.com/smartcontractkit/chain-selectors v1.0.85 h1:A7eyN7KIACxmngn1MJJ0giVtfELK9vh/eYyNU/Q/sFo= +github.com/smartcontractkit/chain-selectors v1.0.85/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 h1:vGdeMwHO3ow88HvxfhA4DDPYNY0X9jmdux7L83UF/W8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20250903115155-a68d8c28ae1d h1:4tEhMQnJW5jndVxukgC+/CVf+FkHVKg3AYygkMtOVUQ= @@ -713,8 +713,8 @@ github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4 h1:AEnxv4HM3WD1Rb github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4/go.mod h1:PjZD54vr6rIKEKQj6HNA4hllvYI/QpT+Zefj3tqkFAs= github.com/smartcontractkit/chainlink-sui v0.0.0-20251104205009-00bd79b81471 h1:EaLuGs7jZ6Vm2iv6rNK3bQ3XN5CRbFd4knjjvaD1zFc= github.com/smartcontractkit/chainlink-sui v0.0.0-20251104205009-00bd79b81471/go.mod h1:VlyZhVw+a93Sk8rVHOIH6tpiXrMzuWLZrjs1eTIExW8= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.7 h1:jVlRG9GTpDGYtP0iabxHZW4s3pXdpN4/lTgZEdE64P4= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.7/go.mod h1:BTUmWJGbOQtMdDW8cy4fu0wLoj8tKFQiLR7SE+OyTXU= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1 h1:Ld3OrOQfLubJ+os0/oau2V6RISgsEdBg+Q002zkgXpQ= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1/go.mod h1:r6KXRM1u9ch5KFR2jspkgtyWEC1X+gxPCL8mR63U990= github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2 h1:ZJ/8Jx6Be5//TyjPi1pS1uotnmcYq5vVkSyISIymSj8= github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2/go.mod h1:kHYJnZUqiPF7/xN5273prV+srrLJkS77GbBXHLKQpx0= github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 h1:7bxYNrPpygn8PUSBiEKn8riMd7CXMi/4bjTy0fHhcrY= @@ -727,8 +727,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358 h1:+NVzR5LZVazRUunzVn34u+lwnpmn6NTVPCeZOVyQHLo= github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= -github.com/smartcontractkit/mcms v0.30.2 h1:xdvZZ5V4q6J/zzb2QV5wjWaZtGj+xvyHy8UVhsOMA8I= -github.com/smartcontractkit/mcms v0.30.2/go.mod h1:7GXnTUilJcUdzndp7HXDwjinjubG2Jsu2A1oRbtaKBs= +github.com/smartcontractkit/mcms v0.31.1 h1:sUIJG9pTMTpQ9WkLGSuPAIjq7z0b1KQ5rnL9KxaonXE= +github.com/smartcontractkit/mcms v0.31.1/go.mod h1:s/FrY+wVrmK7IfrSq8VPLGqqplX9Nv6Qek47ubz2+n8= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -795,8 +795,8 @@ github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfj github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= -github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= +github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= @@ -1127,6 +1127,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= +gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=