diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 594161034..b064a2aa1 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -10,7 +10,7 @@ on: env: # Ensure that a cached go version is used: # https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md#go - GO_VERSION: 1.26.4 + GO_VERSION: 1.26.6 GOPRIVATE: github.com/smartcontractkit/capabilities jobs: diff --git a/.tool-versions b/.tool-versions index dcd428560..4e58ac203 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ nodejs 20.18.1 pnpm 10.6.5 -golang 1.26.4 +golang 1.26.6 golangci-lint 2.11.4 diff --git a/chain_capabilities/aptos/actions/forwarder_client.go b/chain_capabilities/aptos/actions/forwarder_client.go index 92972d75e..1643cf01b 100644 --- a/chain_capabilities/aptos/actions/forwarder_client.go +++ b/chain_capabilities/aptos/actions/forwarder_client.go @@ -3,13 +3,13 @@ package actions import ( "context" "encoding/binary" + "encoding/hex" "encoding/json" "fmt" "slices" aptos_sdk "github.com/aptos-labs/aptos-go-sdk" "github.com/aptos-labs/aptos-go-sdk/bcs" - "github.com/ethereum/go-ethereum/common" aptos_forwarder "github.com/smartcontractkit/chainlink-aptos/bindings/platform/forwarder" aptoscap "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/aptos" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -109,7 +109,7 @@ func (fc *forwarderClient) InvokeOnReport(ctx context.Context, receiver []byte, "forwarderAddress", fmt.Sprintf("%x", fc.forwarderAddress), "moduleName", moduleInformation.ModuleName, ) - reply, err := fc.AptosService.SubmitTransaction(ctx, aptostypes.SubmitTransactionRequest{ + reply, err := fc.SubmitTransaction(ctx, aptostypes.SubmitTransactionRequest{ // TODO: do i really need ReceiverModuleID if my EncodedPayload is of type EntryFunction which has all the details ? ReceiverModuleID: aptostypes.ModuleID{ Address: aptostypes.AccountAddress(fc.forwarderAddress), @@ -134,7 +134,7 @@ type TransmissionID struct { } func (t TransmissionID) GetDebugID() string { - return fmt.Sprintf("receiver: %s, reportID: %s, workflowExecutionID %s", t.Receiver.String(), common.Bytes2Hex(t.ReportID[:]), common.Bytes2Hex(t.WorkflowExecutionID[:])) + return fmt.Sprintf("receiver: %s, reportID: %s, workflowExecutionID %s", t.Receiver.String(), hex.EncodeToString(t.ReportID[:]), hex.EncodeToString(t.WorkflowExecutionID[:])) } type TransmissionInfo struct { @@ -170,7 +170,7 @@ func (fc *forwarderClient) GetTransmissionInfo(ctx context.Context, transmission return TransmissionInfo{}, fmt.Errorf("failed to encode GetTransmitter: %w", err) } - viewReply, err := fc.AptosService.View(ctx, aptostypes.ViewRequest{ + viewReply, err := fc.View(ctx, aptostypes.ViewRequest{ Payload: &aptostypes.ViewPayload{ Module: aptostypes.ModuleID{ Address: aptostypes.AccountAddress(moduleInfo.Address), @@ -218,7 +218,7 @@ func (fc *forwarderClient) GetTransmitterTransactions(ctx context.Context, trans "hasStart", start != nil, "hasLimit", limit != nil, ) - reply, err := fc.AptosService.AccountTransactions(ctx, aptostypes.AccountTransactionsRequest{ + reply, err := fc.AccountTransactions(ctx, aptostypes.AccountTransactionsRequest{ Address: aptostypes.AccountAddress(transmitter), Start: start, Limit: limit, diff --git a/chain_capabilities/aptos/actions/tx_info_retriever.go b/chain_capabilities/aptos/actions/tx_info_retriever.go index 7188b5c62..ba5f96c85 100644 --- a/chain_capabilities/aptos/actions/tx_info_retriever.go +++ b/chain_capabilities/aptos/actions/tx_info_retriever.go @@ -470,11 +470,7 @@ func (thr *TxInfoRetriever) matchesTransmissionByReport(arguments []any) bool { reportHex, _ := arguments[1].(string) expectedReportHex := hex.EncodeToString(slices.Concat(thr.report.ReportContext, thr.report.RawReport)) - if strings.TrimPrefix(reportHex, "0x") != expectedReportHex { - return false - } - - return true + return strings.TrimPrefix(reportHex, "0x") == expectedReportHex } // receiverAddressesEqual compares a hex-encoded receiver from chain tx arguments diff --git a/chain_capabilities/aptos/actions/write_report.go b/chain_capabilities/aptos/actions/write_report.go index eda24c236..1c27ae1bb 100644 --- a/chain_capabilities/aptos/actions/write_report.go +++ b/chain_capabilities/aptos/actions/write_report.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "math" - "math/big" "slices" "strings" "time" @@ -38,11 +37,6 @@ import ( // Set to 2x with margin for gas schedule changes. const ForwarderGasOverhead uint64 = 4000 -// aptosOctasToAPT converts a fee in octas (10^-8 APT) to a *big.Float in APT. -func aptosOctasToAPT(octas uint64) *big.Float { - return new(big.Float).Quo(new(big.Float).SetUint64(octas), big.NewFloat(1e8)) -} - // WriteReport validates and submits a signed report to the Aptos chain via the CRE forwarder. func (s *Aptos) WriteReport( ctx context.Context, @@ -231,14 +225,13 @@ func (wr *writeReport) execute( ownLedgerVersion, ownFeeInOctas, ownVMStatus, ownBlockTimestamp, feeErr := wr.getTxnInfoFromChain(ctx, txReply.TxHash) if feeErr != nil { wr.lggr.Errorw("Failed to get transaction fee, using zero for metering", "txHash", txReply.TxHash, "error", feeErr) - ownMeteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), wr.chainSelector) + ownMeteringMetadata = metering.GetResponseMetadataWriteReport(0, wr.chainSelector) monitoring.LogAndEmitError(ctx, wr.lggr, wr.beholderProcessor, wr.messageBuilder.BuildWriteReportTxFeeCalculationError(telemetryContext, request, txReply.TxHash, feeErr.Error())) } else { pinnedLedgerVersion = &ownLedgerVersion - feeInAPT := aptosOctasToAPT(ownFeeInOctas) - ownMeteringMetadata = metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector) - wr.lggr.Debugw("WriteReport fee", "feeInAPT", feeInAPT.String(), "feeInOctas", ownFeeInOctas, "ledgerVersion", ownLedgerVersion) + ownMeteringMetadata = metering.GetResponseMetadataWriteReport(ownFeeInOctas, wr.chainSelector) + wr.lggr.Debugw("WriteReport fee", "feeInOctas", ownFeeInOctas, "ledgerVersion", ownLedgerVersion) } // Measured to the transaction's on-chain block timestamp rather than to when the submit call @@ -284,9 +277,8 @@ func (wr *writeReport) execute( return nil, capabilities.ResponseMetadata{}, fmt.Errorf("failed to get successful transmission hash: %w", txHashErr) } feeInOctas := successResult.GasUsed * successResult.GasUnitPrice - feeInAPT := aptosOctasToAPT(feeInOctas) - meteringMetadata := metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector) - wr.lggr.Debugw("WriteReport fee", "feeInAPT", feeInAPT.String(), "feeInOctas", feeInOctas) + meteringMetadata := metering.GetResponseMetadataWriteReport(feeInOctas, wr.chainSelector) + wr.lggr.Debugw("WriteReport fee", "feeInOctas", feeInOctas) monitoring.LogAndEmitSuccess(ctx, "WriteReport sent a duplicate transaction, report already on-chain", wr.lggr, wr.beholderProcessor, @@ -294,7 +286,7 @@ func (wr *writeReport) execute( if txReply.TxStatus == aptostypes.TxFatal { wr.lggr.Errorw("Transaction failed to get processed, but report was already submitted, this is unexpected and should be investigated", "txHash", txReply.TxHash) - meteringMetadata = metering.GetResponseMetadataWriteReport(big.NewFloat(0), wr.chainSelector) + meteringMetadata = metering.GetResponseMetadataWriteReport(0, wr.chainSelector) } return &aptoscap.WriteReportReply{ @@ -362,8 +354,7 @@ func (wr *writeReport) execute( // charge the user for the failed txs if it was reverted on user contract var replyMeta capabilities.ResponseMetadata if recvStatus != nil && *recvStatus == aptoscap.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED { - feeInAPT := aptosOctasToAPT(feeOctas) - replyMeta = metering.GetResponseMetadataWriteReport(feeInAPT, wr.chainSelector) + replyMeta = metering.GetResponseMetadataWriteReport(feeOctas, wr.chainSelector) } return &aptoscap.WriteReportReply{ TxStatus: aptoscap.TxStatus_TX_STATUS_FATAL, @@ -382,32 +373,6 @@ func (wr *writeReport) execute( return nil, capabilities.ResponseMetadata{}, nil // should never happen } -// buildPreSubmissionFatalReply evaluates node 0's failed tx and returns a fatal reply -// if we should NOT submit, or (nil, empty) if we should proceed to submit. -func (wr *writeReport) buildPreSubmissionFatalReply(failedResult TransmissionTxInfo, ourMaxGasAmount uint64) (*aptoscap.WriteReportReply, capabilities.ResponseMetadata) { - if isOutOfGas(failedResult.VMStatus) && ourMaxGasAmount > failedResult.MaxGasAmount { - // We have more gas headroom than node 0 — proceed to submit. - return nil, capabilities.ResponseMetadata{} - } - - // Either not OOG (user error, unrecoverable) or our gas isn't higher — return fatal. - // No metering: we never submitted, so we incurred no gas cost. - feeOctas := failedResult.GasUsed * failedResult.GasUnitPrice - return &aptoscap.WriteReportReply{ - TxStatus: aptoscap.TxStatus_TX_STATUS_FATAL, - TxHash: &failedResult.TxHash, - TransactionFee: &feeOctas, - ErrorMessage: ptrIfNonEmpty(failedResult.VMStatus), - ReceiverContractExecutionStatus: receiverContractExecutionStatusFromFailedVMStatus(failedResult.VMStatus, wr.forwarderAddress), - }, capabilities.ResponseMetadata{} -} - -// isOutOfGas returns true if the VM status string indicates the transaction -// exhausted its total gas budget. The Aptos VM returns exactly "Out of gas". -func isOutOfGas(vmStatus string) bool { - return vmStatus == "Out of gas" -} - // getTxnInfoFromChain returns the committed ledger version, fee in octas (gasUsed * gasUnitPrice), // and VM status for a submitted tx, looked up via AptosService.TransactionByHash. func (wr *writeReport) getTxnInfoFromChain(ctx context.Context, txHash string) (uint64, uint64, string, uint64, error) { diff --git a/chain_capabilities/aptos/go.mod b/chain_capabilities/aptos/go.mod index 272e06715..54236d57c 100644 --- a/chain_capabilities/aptos/go.mod +++ b/chain_capabilities/aptos/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/capabilities/chain_capabilities/aptos -go 1.26.4 +go 1.26.6 require ( github.com/aptos-labs/aptos-go-sdk v1.12.1 @@ -8,7 +8,7 @@ require ( github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 github.com/smartcontractkit/chain-selectors v1.0.104 github.com/smartcontractkit/chainlink-aptos v0.0.0-20260506112908-f0d993b5bd6d - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 ) require ( @@ -20,7 +20,8 @@ require ( github.com/jonboulle/clockwork v0.5.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe // indirect + github.com/stretchr/objx v0.5.3 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 // indirect go.uber.org/goleak v1.3.0 // indirect golang.org/x/sync v0.21.0 // indirect @@ -39,9 +40,8 @@ require ( github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 // indirect github.com/cloudevents/sdk-go/v2 v2.16.1 // indirect github.com/coder/websocket v1.8.14 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/ethereum/go-ethereum v1.17.4 + github.com/ethereum/go-ethereum v1.17.4 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect @@ -82,7 +82,6 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect @@ -90,14 +89,14 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260713185857-30ad2e76c0f4 - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 // indirect + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee + github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/libocr v0.0.0-20260810200708-618b5bf7f342 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.12.0 github.com/valyala/fastjson v1.6.10 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect diff --git a/chain_capabilities/aptos/go.sum b/chain_capabilities/aptos/go.sum index 7c33ef01d..a6d2b6238 100644 --- a/chain_capabilities/aptos/go.sum +++ b/chain_capabilities/aptos/go.sum @@ -42,8 +42,6 @@ github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= @@ -216,8 +214,6 @@ github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -243,16 +239,18 @@ github.com/smartcontractkit/chain-selectors v1.0.104 h1:/n9pPGM5W/+r1eHoWZv4VwX9 github.com/smartcontractkit/chain-selectors v1.0.104/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-aptos v0.0.0-20260506112908-f0d993b5bd6d h1:KMZmEzlZ+iknVFCuv+8o9iEKK52HXyeauIWbo+KhYv8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20260506112908-f0d993b5bd6d/go.mod h1:zfE2R7887kiwXkGTHKPe5NBgwhFwIC3pnA2uAxrbvig= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260713185857-30ad2e76c0f4 h1:KSg0EnUdefIGyR3Fa6/nXhWXaCUlMP5qFAsLHwzi6Fk= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260713185857-30ad2e76c0f4/go.mod h1:snfVBRRQTpC2x5O3bQHZe9SvJX5yv/SbG8oHkJTKLtE= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 h1:o7vfwNQjQbMKQ9YsZFQOxvU7RMXD/wKnZsX5N9sDS3w= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee h1:tgmFTPN8Aj/pXeVWCQiTDKmNmbFS8G2nUFUE2dy3QWk= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee/go.mod h1:HXAfE3CpzesS8GTPLc9W4S4spmBLBTLbGggb5VwK5HQ= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 h1:uWEwl7i2ryuRVoV4DmIKm6mqYevf1lH/8cQYhw/JXko= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72/go.mod h1:UYcRMb4dZcoaIPgZJ3hckCySTqtJc9K4Q+tOKErwTq0= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 h1:oW88YVT5ENU6rCPVOLV/hofmFBux2Mu1EOwz8KJu5ic= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 h1:Vk0CZJakAUS/djfBhIJENH4WvM4xl6bY8dYD8cIY/sk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= +github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe h1:MDnY5wQbWTpFdDnMRicEnoMfSP5nM/KncARr4skP1ug= +github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe/go.mod h1:z7lx7wI3XZ4u9kmUtAVdwn1BCC9T8aieWSDcuDgPTdQ= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 h1:/vkKPJoweLkRd56V4YHGRAtTG4+/JAlgklGEfvH6l4c= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260528173149-f5b8336b19d9 h1:LQy2j2+TdKLSWsUTUYuqmQPn8kjqCLjGI3ZJYGtDc08= @@ -268,8 +266,8 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -277,8 +275,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= 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.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= diff --git a/chain_capabilities/aptos/metering/metering.go b/chain_capabilities/aptos/metering/metering.go index f48e2c611..c25d3fa7a 100644 --- a/chain_capabilities/aptos/metering/metering.go +++ b/chain_capabilities/aptos/metering/metering.go @@ -3,18 +3,24 @@ package metering import ( "fmt" "math/big" + "strconv" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" ) var WriteReportSpendUnitFormat = "GAS.%d" // %d will be replaced with the chain selector -func GetResponseMetadataWriteReport(fee *big.Float, chainSelector uint64) capabilities.ResponseMetadata { +// GetResponseMetadataWriteReport returns billing ResponseMetadata for a completed write-report +// submission. feeInOctas is the transaction fee in octas (native fixed-point integer). +// The legacy SpendValue (in APT) is derived from feeInOctas for backwards compatibility. +func GetResponseMetadataWriteReport(feeInOctas uint64, chainSelector uint64) capabilities.ResponseMetadata { + feeInAPT := new(big.Float).Quo(new(big.Float).SetUint64(feeInOctas), big.NewFloat(1e8)) return capabilities.ResponseMetadata{ Metering: []capabilities.MeteringNodeDetail{ { - SpendValue: fee.Text('f', -1), // stored in APT - SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), + SpendValue: feeInAPT.Text('f', -1), + SpendValueInGasUnits: strconv.FormatUint(feeInOctas, 10), + SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), }, }, } diff --git a/chain_capabilities/aptos/metering/metering_test.go b/chain_capabilities/aptos/metering/metering_test.go index 1f9b4f72c..4f8018c69 100644 --- a/chain_capabilities/aptos/metering/metering_test.go +++ b/chain_capabilities/aptos/metering/metering_test.go @@ -2,6 +2,7 @@ package metering import ( "math/big" + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -11,35 +12,35 @@ import ( func TestGetResponseMetadataWriteReport(t *testing.T) { tests := []struct { name string - fee *big.Float + feeInOctas uint64 chainSelector uint64 expectedSpendUnit string expectedValue string }{ { name: "Standard Aptos fee (500 octas = 0.000005 APT)", - fee: new(big.Float).Quo(new(big.Float).SetUint64(500), big.NewFloat(1e8)), + feeInOctas: 500, chainSelector: 1, expectedSpendUnit: "GAS.1", expectedValue: "0.000005", }, { name: "Large fee (1 APT)", - fee: new(big.Float).SetFloat64(1.0), + feeInOctas: 100_000_000, chainSelector: 42, expectedSpendUnit: "GAS.42", expectedValue: "1", }, { name: "Zero fee", - fee: new(big.Float).SetFloat64(0), + feeInOctas: 0, chainSelector: 100, expectedSpendUnit: "GAS.100", expectedValue: "0", }, { name: "Typical fee (gasUsed=500 * gasUnitPrice=100 = 50000 octas = 0.0005 APT)", - fee: new(big.Float).Quo(new(big.Float).SetUint64(50_000), big.NewFloat(1e8)), + feeInOctas: 50_000, chainSelector: 1, expectedSpendUnit: "GAS.1", expectedValue: "0.0005", @@ -48,11 +49,17 @@ func TestGetResponseMetadataWriteReport(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - result := GetResponseMetadataWriteReport(test.fee, test.chainSelector) + result := GetResponseMetadataWriteReport(test.feeInOctas, test.chainSelector) require.Len(t, result.Metering, 1) assert.Equal(t, test.expectedSpendUnit, result.Metering[0].SpendUnit) assert.Equal(t, test.expectedValue, result.Metering[0].SpendValue) + assert.Equal(t, strconv.FormatUint(test.feeInOctas, 10), result.Metering[0].SpendValueInGasUnits) assert.Empty(t, result.Metering[0].Peer2PeerID, "Peer2PeerID should be empty") }) } } + +func TestAptosOctasToAPT(t *testing.T) { + assert.Equal(t, "0.000005", new(big.Float).Quo(new(big.Float).SetUint64(500), big.NewFloat(1e8)).Text('f', -1)) + assert.Equal(t, "1", new(big.Float).Quo(new(big.Float).SetUint64(100_000_000), big.NewFloat(1e8)).Text('f', -1)) +} diff --git a/chain_capabilities/evm/actions/write_report.go b/chain_capabilities/evm/actions/write_report.go index 2bba7b204..bb0fe9ce8 100644 --- a/chain_capabilities/evm/actions/write_report.go +++ b/chain_capabilities/evm/actions/write_report.go @@ -103,7 +103,7 @@ func (e *EVM) executeWriteReport(ctx context.Context, request *evm.WriteReportRe return wr.executeWriteReport(ctx, request, metadata, telemetryContext) } -func (e *WriteReport) getFee(ctx context.Context, txIdempotencyKey string) (*big.Float, error) { +func (e *WriteReport) getFee(ctx context.Context, txIdempotencyKey string) (*big.Int, error) { if txIdempotencyKey == "" { return nil, fmt.Errorf("txIdempotencyKey is empty, cannot retrieve transaction fee") } @@ -114,7 +114,7 @@ func (e *WriteReport) getFee(ctx context.Context, txIdempotencyKey string) (*big } feeInEth := new(big.Float).Quo(new(big.Float).SetInt(feeInWei.TransactionFee), big.NewFloat(1e18)) e.lggr.Debugw("WriteReport fee", "feeInEth", feeInEth.String(), "feeInWei", feeInWei.TransactionFee.String()) - return feeInEth, nil + return feeInWei.TransactionFee, nil } func (e *WriteReport) executeWriteReport(ctx context.Context, request *evm.WriteReportRequest, metadata capabilities.RequestMetadata, telemetryContext monitoring.TelemetryContext) (*evm.WriteReportReply, capabilities.ResponseMetadata, error) { @@ -243,11 +243,11 @@ func (e *WriteReport) executeWriteReport(ctx context.Context, request *evm.Write e.lggr.Infow("Got final transmission status", newTransmissionInfo.LogAttrs()...) var meteringMetadata capabilities.ResponseMetadata - transactionFee, err := e.getFee(ctx, transactionResult.TxIdempotencyKey) + feeInWei, err := e.getFee(ctx, transactionResult.TxIdempotencyKey) if err != nil { monitoring.LogAndEmitError(ctx, e.lggr, e.beholderProcessor, e.messageBuilder.BuildWriteReportTxFeeCalculationError(telemetryContext, request, transactionResult.TxIdempotencyKey, err.Error())) } else { - meteringMetadata = metering.GetResponseMetadataWriteReport(transactionFee, e.chainSelector) + meteringMetadata = metering.GetResponseMetadataWriteReport(feeInWei, e.chainSelector) } switch newTransmissionInfo.State { @@ -256,11 +256,14 @@ func (e *WriteReport) executeWriteReport(ctx context.Context, request *evm.Write if err != nil { return nil, capabilities.ResponseMetadata{}, err } - if transactionResult.TxStatus == evmtypes.TxReverted { + switch transactionResult.TxStatus { + case evmtypes.TxReverted: // Report for this transaction has already been submitted and we sent a duplicate tx onchain which is fine, but wastes ethereum gas monitoring.LogAndEmitSuccess(ctx, "Made a new transmission attempt - transmission succeeded, but it reverted due to being a duplicate", e.lggr, e.beholderProcessor, e.messageBuilder.BuildWriteReportDuplicateTx(telemetryContext, request, common.Bytes2Hex(transactionResult.TxHash[:]), common.Bytes2Hex((txHash)[:]))) - } else if transactionResult.TxStatus == evmtypes.TxFatal { + case evmtypes.TxFatal: e.lggr.Debugw("Made a new transmission attempt - transmission succeeded, but can't find the tx locally") + case evmtypes.TxSuccess: + // Expected happy path — nothing extra to log. } e.lggr.Infow("Made a new transmission attempt - transmission succeeded", "txIdempotencyKey", transactionResult.TxIdempotencyKey, "txHash", common.Bytes2Hex((txHash)[:])) reply, err := e.buildSuccessReply(ctx, *txHash) diff --git a/chain_capabilities/evm/actions/write_report_test.go b/chain_capabilities/evm/actions/write_report_test.go index 362c562a6..e77ca0a5d 100644 --- a/chain_capabilities/evm/actions/write_report_test.go +++ b/chain_capabilities/evm/actions/write_report_test.go @@ -1021,7 +1021,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { }, txResult.Response) // Retried tx => should be metered. - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") }) t.Run("TX first transmission - Successful TX execution (ensures non-nil + positive gas config passed to forwarder)", func(t *testing.T) { @@ -1093,7 +1093,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { TransactionFee: pb.NewBigIntFromInt(big.NewInt(retryTxFee)), }, txResult.Response) - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") }) t.Run("TX first transmission - Error submitting TX (ensures gas config passed is non-nil + positive)", func(t *testing.T) { @@ -1193,7 +1193,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { TransactionFee: pb.NewBigIntFromInt(big.NewInt(2000)), }, txResult.Response) - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") }) t.Run("TX first transmission - Duplicate tx: txmgr reports reverted but transmission succeeded => use onchain tx hash", func(t *testing.T) { @@ -1271,7 +1271,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { TransactionFee: pb.NewBigIntFromInt(big.NewInt(txFee)), }, txResult.Response) - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") }) t.Run("TX first transmission - Fatal tx but transmission succeeded => use onchain tx hash", func(t *testing.T) { @@ -1344,7 +1344,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { TransactionFee: pb.NewBigIntFromInt(big.NewInt(txFee)), }, txResult.Response) - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") }) t.Run("TX first transmission - Fatal tx and GetSuccessfulTransmissionHash fails => returns error", func(t *testing.T) { @@ -1518,7 +1518,7 @@ func TestWriteReport_ExecuteWriteReport(t *testing.T) { require.Equal(t, receiptTxHash[:], txResult.Response.TxHash) require.NotNil(t, txResult.Response.ReceiverContractExecutionStatus) require.Equal(t, evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED.Enum(), txResult.Response.ReceiverContractExecutionStatus.Enum()) - evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, txResult.ResponseMetadata, 1, "0.0000000000000003", "300") if queuePosition == 0 { mockForwarderClient.AssertNotCalled(t, "GetReportProcessedEvents", mock.Anything, mock.Anything, mock.Anything, mock.Anything) @@ -2253,7 +2253,7 @@ func TestWriteReport_RevertReceiptFetchFailsReturnsUserError(t *testing.T) { assertMetadata: func(t *testing.T, metadata capabilities.ResponseMetadata) { t.Helper() - evmtest.ValidateMeteringWriteReport(t, metadata, 1, "0.0000000000000003") + evmtest.ValidateMeteringWriteReport(t, metadata, 1, "0.0000000000000003", "300") }, }, } diff --git a/chain_capabilities/evm/go.mod b/chain_capabilities/evm/go.mod index 12628bd08..5633ba196 100644 --- a/chain_capabilities/evm/go.mod +++ b/chain_capabilities/evm/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/capabilities/chain_capabilities/evm -go 1.26.4 +go 1.26.6 require ( github.com/ethereum/go-ethereum v1.17.4 @@ -8,12 +8,12 @@ require ( github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13 github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 github.com/smartcontractkit/chain-selectors v1.0.106 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260714130758-475cb096a3e1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260410162948-2dca02f24e98 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251022073203-7d8ae8cf67c1 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 - github.com/stretchr/testify v1.11.1 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 + github.com/stretchr/testify v1.12.0 go.opentelemetry.io/otel v1.43.0 go.uber.org/zap v1.27.1 google.golang.org/protobuf v1.36.11 @@ -90,13 +90,14 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/smartcontractkit/chainlink-common/keystore v1.1.1-0.20260529092756-a94bc8ce96d6 // indirect - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 // indirect + github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 // indirect github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260326122810-b657beadfb57 // indirect github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect + github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe // indirect github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 // indirect github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260528173149-f5b8336b19d9 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/objx v0.5.3 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tidwall/gjson v1.18.0 // indirect @@ -173,7 +174,6 @@ require ( github.com/oklog/run v1.2.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect diff --git a/chain_capabilities/evm/go.sum b/chain_capabilities/evm/go.sum index cdb7ab7be..3e2b9a457 100644 --- a/chain_capabilities/evm/go.sum +++ b/chain_capabilities/evm/go.sum @@ -18,8 +18,8 @@ github.com/XSAM/otelsql v0.37.0 h1:ya5RNw028JW0eJW8Ma4AmoKxAYsJSGuNVbC7F1J457A= github.com/XSAM/otelsql v0.37.0/go.mod h1:LHbCu49iU8p255nCn1oi04oX2UjSoRcUMiKEHo2a5qM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM= +github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/apache/arrow-go/v18 v18.3.1 h1:oYZT8FqONiK74JhlH3WKVv+2NKYoyZ7C2ioD4Dj3ixk= github.com/apache/arrow-go/v18 v18.3.1/go.mod h1:12QBya5JZT6PnBihi5NJTzbACrDGXYkrgjujz3MRQXU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= @@ -470,12 +470,12 @@ github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64/go.mod h1:DZkOtlIRV6ecpCskdXMF+k2es3uJQqTT1m5TRB9etjQ= github.com/smartcontractkit/chain-selectors v1.0.106 h1:6Mz7FDooWJEcfvuOX3nH7oh5s44fqg/WqVDQS63Mjzs= github.com/smartcontractkit/chain-selectors v1.0.106/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260714130758-475cb096a3e1 h1:qxSP9Rlaq9hxyLsDUdGj21MdHLhiHF7HhEtwaHSvWcw= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260714130758-475cb096a3e1/go.mod h1:snfVBRRQTpC2x5O3bQHZe9SvJX5yv/SbG8oHkJTKLtE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee h1:tgmFTPN8Aj/pXeVWCQiTDKmNmbFS8G2nUFUE2dy3QWk= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee/go.mod h1:HXAfE3CpzesS8GTPLc9W4S4spmBLBTLbGggb5VwK5HQ= github.com/smartcontractkit/chainlink-common/keystore v1.1.1-0.20260529092756-a94bc8ce96d6 h1:fWsYxxj35fp1/6YZngoTsOTMLqDie4N5X0osAOdhUTE= github.com/smartcontractkit/chainlink-common/keystore v1.1.1-0.20260529092756-a94bc8ce96d6/go.mod h1:6JexOOhPhknQ0QMuppFIlOpm6wCp54yZMxai+tWugwY= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 h1:o7vfwNQjQbMKQ9YsZFQOxvU7RMXD/wKnZsX5N9sDS3w= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 h1:uWEwl7i2ryuRVoV4DmIKm6mqYevf1lH/8cQYhw/JXko= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72/go.mod h1:UYcRMb4dZcoaIPgZJ3hckCySTqtJc9K4Q+tOKErwTq0= github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260410162948-2dca02f24e98 h1:h/L6wrXYLQalI/vHm6qg/KBv6d7kMb3geMHV5hCM1t4= github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260410162948-2dca02f24e98/go.mod h1:6vCMfxz7cMW0wWseNKtct+b1JJbbRVJJhh/t6pQWN3M= github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251022073203-7d8ae8cf67c1 h1:NTODgwAil7BLoijS7y6KnEuNbQ9v60VUhIR9FcAzIhg= @@ -488,10 +488,12 @@ github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512- github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a/go.mod h1:7ketk4ischPQW/JQgmyHz6zdzLUJv1VC29SiSgosydQ= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 h1:oW88YVT5ENU6rCPVOLV/hofmFBux2Mu1EOwz8KJu5ic= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 h1:Vk0CZJakAUS/djfBhIJENH4WvM4xl6bY8dYD8cIY/sk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= +github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe h1:MDnY5wQbWTpFdDnMRicEnoMfSP5nM/KncARr4skP1ug= +github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe/go.mod h1:z7lx7wI3XZ4u9kmUtAVdwn1BCC9T8aieWSDcuDgPTdQ= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 h1:/vkKPJoweLkRd56V4YHGRAtTG4+/JAlgklGEfvH6l4c= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260528173149-f5b8336b19d9 h1:LQy2j2+TdKLSWsUTUYuqmQPn8kjqCLjGI3ZJYGtDc08= @@ -507,8 +509,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -519,8 +521,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= diff --git a/chain_capabilities/evm/internal/contracts/cre_forwarder.go b/chain_capabilities/evm/internal/contracts/cre_forwarder.go index 8c4bccec4..501a0a866 100644 --- a/chain_capabilities/evm/internal/contracts/cre_forwarder.go +++ b/chain_capabilities/evm/internal/contracts/cre_forwarder.go @@ -17,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" evmcap "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/evm" - "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" evmtypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/forwarder" workflowpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" @@ -120,8 +119,8 @@ func NewCREForwarderClient(EVMService types.EVMService, forwarderAddress common. }, nil } -func (cfclient *creForwarderClient) GetReportProcessedEvents(ctx context.Context, receiver common.Address, workflowExecutionID [32]byte, reportID [2]byte) ([]*evm.Log, error) { - latest, err := cfclient.evmService.HeaderByNumber(ctx, evm.HeaderByNumberRequest{Number: big.NewInt(rpc.LatestBlockNumber.Int64())}) +func (cfclient *creForwarderClient) GetReportProcessedEvents(ctx context.Context, receiver common.Address, workflowExecutionID [32]byte, reportID [2]byte) ([]*evmtypes.Log, error) { + latest, err := cfclient.evmService.HeaderByNumber(ctx, evmtypes.HeaderByNumberRequest{Number: big.NewInt(rpc.LatestBlockNumber.Int64())}) if err != nil { return nil, err } @@ -164,7 +163,7 @@ func padBytes2ToBytes32(b2 [2]byte) common.Hash { type CREForwarderClient interface { GetTransmissionInfo(ctx context.Context, transmissionID TransmissionID) (TransmissionInfo, error) InvokeOnReport(ctx context.Context, receiverAddress common.Address, report *workflowpb.ReportResponse, gasConfig *evmcap.GasConfig) (*evmtypes.TransactionResult, error) - GetReportProcessedEvents(ctx context.Context, receiver common.Address, workflowExecutionID [32]byte, reportID [2]byte) ([]*evm.Log, error) + GetReportProcessedEvents(ctx context.Context, receiver common.Address, workflowExecutionID [32]byte, reportID [2]byte) ([]*evmtypes.Log, error) } type CREForwarderCodec interface { diff --git a/chain_capabilities/evm/internal/contracts/cre_forwarder_test.go b/chain_capabilities/evm/internal/contracts/cre_forwarder_test.go index 5545a26f5..d3814b92e 100644 --- a/chain_capabilities/evm/internal/contracts/cre_forwarder_test.go +++ b/chain_capabilities/evm/internal/contracts/cre_forwarder_test.go @@ -19,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" evmtypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" mocks2 "github.com/smartcontractkit/chainlink-common/pkg/types/mocks" "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/forwarder" @@ -140,7 +139,7 @@ func TestCREForwarderClient_GetReportProcessedEvents(t *testing.T) { mockEVMService := mocks2.NewEVMService(t) mockEVMService.EXPECT().HeaderByNumber(mock.Anything, mock.Anything).Return(&evmtypes.HeaderByNumberReply{Header: &evmtypes.Header{Number: big.NewInt(100)}}, nil).Maybe() forwarderClient, _ := contracts.NewCREForwarderClient(mockEVMService, forwarderAddress, contracts.DefaultLookbackBlocks, testLogger) - mockLogs := []*evm.Log{{ + mockLogs := []*evmtypes.Log{{ TxHash: expectedHash, }} mockEVMService.EXPECT().FilterLogs(ctx, mock.Anything).Return(&evmtypes.FilterLogsReply{Logs: mockLogs}, nil) @@ -270,7 +269,7 @@ func TestNewCREForwarderClient_LookbackConfig(t *testing.T) { // FromBlock 50 == 150 - 100 (default value) = 90 return big.NewInt(50).Cmp(req.FilterQuery.FromBlock) == 0 })). - Return(&evmtypes.FilterLogsReply{Logs: []*evm.Log{}}, nil) + Return(&evmtypes.FilterLogsReply{Logs: []*evmtypes.Log{}}, nil) _, err = forwarderClient.GetReportProcessedEvents(ctx, common.BytesToAddress(test.RandomBytes(20)), [32]byte(test.RandomBytes(32)), [2]byte(test.RandomBytes(2))) require.NoError(t, err) @@ -292,7 +291,7 @@ func TestNewCREForwarderClient_LookbackConfig(t *testing.T) { // FromBlock 90 == 100 - 10 = 90 return big.NewInt(90).Cmp(req.FilterQuery.FromBlock) == 0 })). - Return(&evmtypes.FilterLogsReply{Logs: []*evm.Log{}}, nil) + Return(&evmtypes.FilterLogsReply{Logs: []*evmtypes.Log{}}, nil) _, err = forwarderClient.GetReportProcessedEvents(ctx, common.BytesToAddress(test.RandomBytes(20)), [32]byte(test.RandomBytes(32)), [2]byte(test.RandomBytes(2))) require.NoError(t, err) diff --git a/chain_capabilities/evm/metering/metering.go b/chain_capabilities/evm/metering/metering.go index 77aea3949..8b3132fe4 100644 --- a/chain_capabilities/evm/metering/metering.go +++ b/chain_capabilities/evm/metering/metering.go @@ -39,14 +39,18 @@ func GetResponseMetadata(action SpendValueCredits) capabilities.ResponseMetadata } } -// GetMeteringNodeDetail returns a MeteringNodeDetail for a given SpendValueCredits. -func GetResponseMetadataWriteReport(fee *big.Float, chainSelector uint64) capabilities.ResponseMetadata { +// GetResponseMetadataWriteReport returns billing ResponseMetadata for a completed write-report +// submission. feeInWei is the transaction fee in wei (native fixed-point integer). +// The legacy SpendValue (in ETH) is derived from feeInWei for backwards compatibility. +func GetResponseMetadataWriteReport(feeInWei *big.Int, chainSelector uint64) capabilities.ResponseMetadata { + feeInEth := new(big.Float).Quo(new(big.Float).SetInt(feeInWei), big.NewFloat(1e18)) return capabilities.ResponseMetadata{ Metering: []capabilities.MeteringNodeDetail{ { //Peer2PeerID will be assigned by the engine, leaving it empty here. - SpendValue: fee.Text('f', -1), // have to be stored in eth - SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), + SpendValue: feeInEth.Text('f', -1), + SpendValueInGasUnits: feeInWei.String(), + SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), }, }, } diff --git a/chain_capabilities/evm/monitoring/messages.go b/chain_capabilities/evm/monitoring/messages.go index 27091d72e..f70e19b8b 100644 --- a/chain_capabilities/evm/monitoring/messages.go +++ b/chain_capabilities/evm/monitoring/messages.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" evmtypes "github.com/smartcontractkit/chainlink-common/pkg/types/chains/evm" commonmon "github.com/smartcontractkit/capabilities/chain_capabilities/common/monitoring" @@ -38,15 +37,15 @@ func NewMessageBuilder(chainInfo types.ChainInfo, capInfo capabilities.Capabilit } } -func (m *MessageBuilder) BuildCallContractInitiated(tc TelemetryContext, msg *evm.CallMsg, bn int64) *CallContractInitiated { +func (m *MessageBuilder) BuildCallContractInitiated(tc TelemetryContext, msg *evmtypes.CallMsg, bn int64) *CallContractInitiated { return &CallContractInitiated{Req: &CallContractRequest{BlockNumber: bn, ContractAddress: common.Bytes2Hex(msg.To[:])}, ExecutionContext: m.BuildExecutionContext(tc)} } -func (m *MessageBuilder) BuildCallContractSuccess(tc TelemetryContext, msg *evm.CallMsg, bn int64) Message { +func (m *MessageBuilder) BuildCallContractSuccess(tc TelemetryContext, msg *evmtypes.CallMsg, bn int64) Message { return &CallContractSuccess{Req: &CallContractRequest{BlockNumber: bn, ContractAddress: common.Bytes2Hex(msg.To[:])}, ExecutionContext: m.BuildExecutionContext(tc)} } -func (m *MessageBuilder) BuildCallContractError(tc TelemetryContext, msg *evm.CallMsg, bn int64, summary string, err caperrors.Error) ErrorMessage { +func (m *MessageBuilder) BuildCallContractError(tc TelemetryContext, msg *evmtypes.CallMsg, bn int64, summary string, err caperrors.Error) ErrorMessage { return &CallContractError{Req: &CallContractRequest{BlockNumber: bn, ContractAddress: common.Bytes2Hex(msg.To[:])}, Summary: summary, Cause: err.Error(), IsUserError: err.Origin() == caperrors.OriginUser, ExecutionContext: m.BuildExecutionContext(tc)} } @@ -216,7 +215,7 @@ func (m *MessageBuilder) BuildLogTriggerCleanUpError(tc TelemetryContext, summar } } -func (m *MessageBuilder) BuildLogTriggerEventDroppedError(tc TelemetryContext, triggerID string, log *evm.Log, summary, cause string, isLimitError bool) ErrorMessage { +func (m *MessageBuilder) BuildLogTriggerEventDroppedError(tc TelemetryContext, triggerID string, log *evmtypes.Log, summary, cause string, isLimitError bool) ErrorMessage { return &LogTriggerEventDroppedError{ TriggerID: triggerID, TxHash: common.Bytes2Hex(log.TxHash[:]), diff --git a/chain_capabilities/evm/monitoring/processor.go b/chain_capabilities/evm/monitoring/processor.go index 566890adf..099eff880 100644 --- a/chain_capabilities/evm/monitoring/processor.go +++ b/chain_capabilities/evm/monitoring/processor.go @@ -28,7 +28,6 @@ func NewProcessor(lggr logger.Logger, metrics Metrics) (beholder.ProtoProcessor, // Process dispatches telemetry messages to metrics and logs for all EVM operations func (p *processor) Process(ctx context.Context, m proto.Message, attrKVs ...any) error { - // Process metrics for known message types switch msg := m.(type) { // -- Initiated messages -- diff --git a/chain_capabilities/evm/test/test_utils.go b/chain_capabilities/evm/test/test_utils.go index 117fcf416..1be71de8f 100644 --- a/chain_capabilities/evm/test/test_utils.go +++ b/chain_capabilities/evm/test/test_utils.go @@ -19,11 +19,12 @@ func ValidateMetering(t *testing.T, metadata capabilities.ResponseMetadata, expe require.Empty(t, meteringNodeDetail.Peer2PeerID, "Peer2PeerID should be empty as it will be assigned by the engine") } -func ValidateMeteringWriteReport(t *testing.T, metadata capabilities.ResponseMetadata, chainSelector int, expectedValue string) { +func ValidateMeteringWriteReport(t *testing.T, metadata capabilities.ResponseMetadata, chainSelector int, expectedValue string, expectedValueInGasUnits string) { require.Len(t, metadata.Metering, 1) meteringNodeDetail := metadata.Metering[0] require.Equal(t, fmt.Sprintf(metering.WriteReportSpendUnitFormat, chainSelector), meteringNodeDetail.SpendUnit) require.Equal(t, expectedValue, meteringNodeDetail.SpendValue) + require.Equal(t, expectedValueInGasUnits, meteringNodeDetail.SpendValueInGasUnits) require.Empty(t, meteringNodeDetail.Peer2PeerID, "Peer2PeerID should be empty as it will be assigned by the engine") } diff --git a/chain_capabilities/evm/trigger/trigger.go b/chain_capabilities/evm/trigger/trigger.go index 5f11cfcef..dce5db614 100644 --- a/chain_capabilities/evm/trigger/trigger.go +++ b/chain_capabilities/evm/trigger/trigger.go @@ -145,11 +145,11 @@ func NewLogTriggerService(evmService types.EVMService, store LogTriggerStore, lg } func (lts *LogTriggerService) initLimiters(limitsFactory limits.Factory) (err error) { - lts.filterAddressLimiter, err = limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.FilterAddressLimit) + lts.filterAddressLimiter, err = limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.FilterAddressLimit) if err != nil { return } - lts.filterTopicsPerSlotLimiter, err = limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.FilterTopicsPerSlotLimit) + lts.filterTopicsPerSlotLimiter, err = limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.FilterTopicsPerSlotLimit) if err != nil { return } @@ -157,7 +157,7 @@ func (lts *LogTriggerService) initLimiters(limitsFactory limits.Factory) (err er if err != nil { return } - lts.eventPayloadSizeLimiter, err = limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.EventSizeLimit) + lts.eventPayloadSizeLimiter, err = limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.EventSizeLimit) if err != nil { return } @@ -319,6 +319,7 @@ func (lts *LogTriggerService) RegisterLogTrigger(ctx context.Context, triggerID lts.srvcEng.Go(func(ctx context.Context) { ctx, cancel := context.WithCancel(ctx) + defer cancel() lts.triggers.Write(triggerID, logTriggerState{ cancelFunc: cancel, lastBlock: fromBlock, diff --git a/chain_capabilities/solana/actions/forwarder_client.go b/chain_capabilities/solana/actions/forwarder_client.go index e08caffa2..8ddc61712 100644 --- a/chain_capabilities/solana/actions/forwarder_client.go +++ b/chain_capabilities/solana/actions/forwarder_client.go @@ -189,7 +189,10 @@ func toPayload(report *sdk.ReportResponse) ([]byte, error) { ret := make([]byte, 0, 1+len(report.Sigs)*signatureLen+len(report.RawReport)+reportContextLen) // 1. data_size ret[0] - ret = append(ret, byte(len(report.Sigs))) + if len(report.Sigs) > 255 { + return nil, fmt.Errorf("too many signatures: %d, max 255", len(report.Sigs)) + } + ret = append(ret, byte(len(report.Sigs))) //nolint:gosec // G115: bounds-checked above // 2. add N signatures for _, sig := range report.Sigs { diff --git a/chain_capabilities/solana/actions/transmission_info_provider.go b/chain_capabilities/solana/actions/transmission_info_provider.go index 89862c53e..2d8086e4f 100644 --- a/chain_capabilities/solana/actions/transmission_info_provider.go +++ b/chain_capabilities/solana/actions/transmission_info_provider.go @@ -73,18 +73,17 @@ func (p *OnChainTransmissionInfoProvider) GetTransmissionInfo(ctx context.Contex return TransmissionInfo{}, fmt.Errorf("failed to derive execution state PDA: %w", err) } - reply, err := p.SolanaService.GetAccountInfoWithOpts(ctx, soltypes.GetAccountInfoRequest{ + reply, err := p.GetAccountInfoWithOpts(ctx, soltypes.GetAccountInfoRequest{ Account: soltypes.PublicKey(execStateAddr), Opts: &soltypes.GetAccountInfoOpts{ Commitment: soltypes.CommitmentProcessed, }, }) if err != nil { - if isExecutionStateAccountMissing(err) { - reply = &soltypes.GetAccountInfoReply{} - } else { + if !isExecutionStateAccountMissing(err) { return TransmissionInfo{}, fmt.Errorf("failed to get execution state account: %w", err) } + reply = &soltypes.GetAccountInfoReply{} } sig, sigErr := signatureFromInProgressLogs(inProgressLogs) @@ -217,16 +216,6 @@ func deriveExecutionStatePDA(forwarderState solana.PublicKey, transmissionID [32 return ret, err } -func accountDataBytes(acc *soltypes.Account) ([]byte, bool) { - if acc == nil || acc.Data == nil { - return nil, false - } - if len(acc.Data.AsDecodedBinary) > 0 { - return acc.Data.AsDecodedBinary, true - } - return nil, false -} - func isExecutionStateAccountMissing(err error) bool { if err == nil { return false diff --git a/chain_capabilities/solana/actions/write_report.go b/chain_capabilities/solana/actions/write_report.go index b90aa5cc4..f47ef903c 100644 --- a/chain_capabilities/solana/actions/write_report.go +++ b/chain_capabilities/solana/actions/write_report.go @@ -7,7 +7,6 @@ import ( "encoding/hex" "errors" "fmt" - "math/big" "strings" "time" @@ -224,12 +223,11 @@ func (wr *WriteReport) executeWriteReport( } var meteringMetadata capabilities.ResponseMetadata - transactionFee, err := wr.getFee(ctx, last.Signature) + feeInLamports, err := wr.getFee(ctx, last.Signature) if err != nil { monitoring.LogAndEmitError(ctx, wr.lggr, wr.beholderProcessor, wr.messageBuilder.BuildWriteReportTxFeeCalculationError(telemetryContext, request, last.Signature, err.Error())) } else { - meteringMetadata = metering.GetResponseMetadataWriteReport(transactionFee, - wr.chainSelector) + meteringMetadata = metering.GetResponseMetadataWriteReport(feeInLamports, wr.chainSelector) } switch last.State { @@ -451,22 +449,22 @@ func (wr *WriteReport) pollTransmissionInfo( } } -func (wr *WriteReport) getFee(ctx context.Context, sig solana.Signature) (*big.Float, error) { +func (wr *WriteReport) getFee(ctx context.Context, sig solana.Signature) (uint64, error) { tx, err := wr.GetTransaction(ctx, soltypes.GetTransactionRequest{Signature: soltypes.Signature(sig)}) if err != nil { - return nil, fmt.Errorf("failed to get transaction: %w", err) + return 0, fmt.Errorf("failed to get transaction: %w", err) } if tx == nil { - return nil, errors.New("failed to get transaction fee: empty transaction response") + return 0, errors.New("failed to get transaction fee: empty transaction response") } if tx.Meta == nil { - return nil, errors.New("failed to get transaction fee: empty transaction meta") + return 0, errors.New("failed to get transaction fee: empty transaction meta") } - feeInSol := new(big.Float).Quo(new(big.Float).SetUint64(tx.Meta.Fee), big.NewFloat(1e9)) + feeInLamports := tx.Meta.Fee - wr.lggr.Debugw("WriteReport fee", "feeInSol", feeInSol.String(), "feeInLamports", tx.Meta.Fee) - return feeInSol, nil + wr.lggr.Debugw("WriteReport fee", "feeInLamports", feeInLamports) + return feeInLamports, nil } func (wr *WriteReport) successWriteReportReply(sig *solana.Signature) *solcap.WriteReportReply { diff --git a/chain_capabilities/solana/actions/write_report_test.go b/chain_capabilities/solana/actions/write_report_test.go index 59a6a900a..33b0d56b1 100644 --- a/chain_capabilities/solana/actions/write_report_test.go +++ b/chain_capabilities/solana/actions/write_report_test.go @@ -684,10 +684,10 @@ func TestValidateRemainingAccountHash(t *testing.T) { // Borsh-encode ForwarderReport: fixed [u8;32] hash + Vec payload (4-byte LE length prefix) payloadLen := make([]byte, 4) - payloadLen[0] = byte(len(payload)) - payloadLen[1] = byte(len(payload) >> 8) - payloadLen[2] = byte(len(payload) >> 16) - payloadLen[3] = byte(len(payload) >> 24) + payloadLen[0] = byte(len(payload)) //nolint:gosec // G115: test payload length is always small + payloadLen[1] = byte(len(payload) >> 8) //nolint:gosec // G115: test payload length is always small + payloadLen[2] = byte(len(payload) >> 16) //nolint:gosec // G115: test payload length is always small + payloadLen[3] = byte(len(payload) >> 24) //nolint:gosec // G115: test payload length is always small raw := make([]byte, 0, len(header)+32+4+len(payload)) raw = append(raw, header...) @@ -787,9 +787,9 @@ func TestGetFee(t *testing.T) { Meta: &soltypes.TransactionMeta{Fee: txFeeInLamports}, }, nil) - fee, err := wr.getFee(t.Context(), sig) + feeInLamports, err := wr.getFee(t.Context(), sig) require.NoError(t, err) - require.Equal(t, "0.000005", fee.Text('f', -1)) + require.Equal(t, txFeeInLamports, feeInLamports) }) t.Run("Handles large fee values", func(t *testing.T) { @@ -807,9 +807,9 @@ func TestGetFee(t *testing.T) { Meta: &soltypes.TransactionMeta{Fee: txFeeInLamports}, }, nil) - fee, err := wr.getFee(t.Context(), sig) + feeInLamports, err := wr.getFee(t.Context(), sig) require.NoError(t, err) - require.Equal(t, "1", fee.Text('f', -1)) + require.Equal(t, txFeeInLamports, feeInLamports) }) t.Run("Returns error when GetTransaction fails", func(t *testing.T) { @@ -880,7 +880,7 @@ func TestToPayload(t *testing.T) { require.NoError(t, err) expectedLen := 1 + len(report.Sigs)*signatureLen + len(report.RawReport) + reportContextLen require.Len(t, payload, expectedLen) - require.Equal(t, byte(len(report.Sigs)), payload[0]) + require.Equal(t, byte(len(report.Sigs)), payload[0]) //nolint:gosec // G115: test, sig count is small }) t.Run("Too many signatures", func(t *testing.T) { diff --git a/chain_capabilities/solana/config/config.go b/chain_capabilities/solana/config/config.go index 5a4117588..a00f0d97e 100644 --- a/chain_capabilities/solana/config/config.go +++ b/chain_capabilities/solana/config/config.go @@ -49,15 +49,15 @@ func (c *Config) UnmarshalJSON(bs []byte) error { c.IsLocal = cfg.IsLocal c.Network = cfg.Network c.DeltaStage = cfg.DeltaStage - c.CREForwarderAddress, err = solana.PublicKeyFromBase58(string(cfg.CREForwarderAddress)) + c.CREForwarderAddress, err = solana.PublicKeyFromBase58(cfg.CREForwarderAddress) if err != nil { return fmt.Errorf("invalid forwarder address: %w", err) } - c.CREForwarderState, err = solana.PublicKeyFromBase58(string(cfg.CREForwarderState)) + c.CREForwarderState, err = solana.PublicKeyFromBase58(cfg.CREForwarderState) if err != nil { return fmt.Errorf("invalid forwarder state address: %w", err) } - c.Transmitter, err = solana.PublicKeyFromBase58(string(cfg.Transmitter)) + c.Transmitter, err = solana.PublicKeyFromBase58(cfg.Transmitter) if err != nil { return fmt.Errorf("invalid transmitter address: %w", err) } diff --git a/chain_capabilities/solana/go.mod b/chain_capabilities/solana/go.mod index 37cef8057..0477c93c1 100644 --- a/chain_capabilities/solana/go.mod +++ b/chain_capabilities/solana/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/capabilities/chain_capabilities/solana -go 1.26.4 +go 1.26.6 require ( github.com/gagliardetto/solana-go v1.14.0 @@ -9,13 +9,13 @@ require ( github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13 github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 github.com/smartcontractkit/chain-selectors v1.0.104 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260803161028-985f5a5a03d9 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 github.com/smartcontractkit/chainlink-solana v1.3.1-0.20260803170030-90043607d911 github.com/smartcontractkit/chainlink-solana/contracts v0.0.0-20260803170030-90043607d911 github.com/smartcontractkit/libocr v0.0.0-20260810200708-618b5bf7f342 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.12.0 go.opentelemetry.io/otel v1.43.0 google.golang.org/protobuf v1.36.11 ) @@ -116,7 +116,6 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect @@ -140,7 +139,7 @@ require ( github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/objx v0.5.3 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tidwall/gjson v1.18.0 // indirect diff --git a/chain_capabilities/solana/go.sum b/chain_capabilities/solana/go.sum index 6eeb0ad5b..201268589 100644 --- a/chain_capabilities/solana/go.sum +++ b/chain_capabilities/solana/go.sum @@ -56,8 +56,8 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM= +github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/apache/arrow-go/v18 v18.3.1 h1:oYZT8FqONiK74JhlH3WKVv+2NKYoyZ7C2ioD4Dj3ixk= github.com/apache/arrow-go/v18 v18.3.1/go.mod h1:12QBya5JZT6PnBihi5NJTzbACrDGXYkrgjujz3MRQXU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= @@ -629,8 +629,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288/go.mod h1:jPHlo/IN2YAArI001JJixmm6ZHQwgnAVJXY8VBFiFTc= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 h1:eEjTgIQn4RW0ZPRepUDYTdgGwaRCMawMwgXkHItUc9U= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288/go.mod h1:67YbnoglYD61Pz/jTVCgav9wFq7S35OU8UyQSvPllRw= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260803161028-985f5a5a03d9 h1:oyBg6nkl1SDDUB+Z1GNYKTNtepabGkq7pudbyJHgtM8= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260803161028-985f5a5a03d9/go.mod h1:euYQ2WxVYGU2ivHXPBRpbU0Z3/SkekfIK5YPf7hdDY8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee h1:tgmFTPN8Aj/pXeVWCQiTDKmNmbFS8G2nUFUE2dy3QWk= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee/go.mod h1:HXAfE3CpzesS8GTPLc9W4S4spmBLBTLbGggb5VwK5HQ= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 h1:uWEwl7i2ryuRVoV4DmIKm6mqYevf1lH/8cQYhw/JXko= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72/go.mod h1:UYcRMb4dZcoaIPgZJ3hckCySTqtJc9K4Q+tOKErwTq0= github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340 h1:PsjEI+5jZIz9AS4eOsLS5VpSWJINf38clXV3wryPyMk= @@ -641,8 +641,8 @@ github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805- github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243/go.mod h1:7ketk4ischPQW/JQgmyHz6zdzLUJv1VC29SiSgosydQ= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 h1:oW88YVT5ENU6rCPVOLV/hofmFBux2Mu1EOwz8KJu5ic= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 h1:Vk0CZJakAUS/djfBhIJENH4WvM4xl6bY8dYD8cIY/sk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe h1:MDnY5wQbWTpFdDnMRicEnoMfSP5nM/KncARr4skP1ug= @@ -679,8 +679,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -691,8 +691,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= diff --git a/chain_capabilities/solana/main.go b/chain_capabilities/solana/main.go index e4d3c0421..614cd237b 100644 --- a/chain_capabilities/solana/main.go +++ b/chain_capabilities/solana/main.go @@ -264,11 +264,11 @@ func (c *capabilityGRPCService) Initialise(ctx context.Context, dependencies cor return nil } -func (s *capabilityGRPCService) setSelector(cfg *config.Config) error { +func (c *capabilityGRPCService) setSelector(cfg *config.Config) error { // When we run against a local validator (e.g. local CRE) we can't resolve chain selector // since ChainID is always different if cfg.IsLocal { - s.chainSelector = chain_selectors.TEST_22222222222222222222222222222222222222222222.Selector + c.chainSelector = chain_selectors.TEST_22222222222222222222222222222222222222222222.Selector return nil } @@ -277,7 +277,7 @@ func (s *capabilityGRPCService) setSelector(cfg *config.Config) error { return fmt.Errorf("chain selector not found for chainID: %s", cfg.ChainID) } - s.chainSelector = cs + c.chainSelector = cs return nil } @@ -329,13 +329,13 @@ func (c *capabilityGRPCService) unmarshalConfig(configStr string) (*config.Confi return &cfg, nil } -func (s *capabilityGRPCService) RegisterLogTrigger( +func (c *capabilityGRPCService) RegisterLogTrigger( ctx context.Context, triggerID string, metadata capabilities.RequestMetadata, input *solana.FilterLogTriggerRequest) (<-chan capabilities.TriggerAndId[*solana.Log], caperrors.Error) { - return s.triggerService.RegisterLogTrigger(ctx, triggerID, metadata, input) + return c.triggerService.RegisterLogTrigger(ctx, triggerID, metadata, input) } -func (s *capabilityGRPCService) UnregisterLogTrigger(ctx context.Context, triggerID string, metadata capabilities.RequestMetadata, input *solana.FilterLogTriggerRequest) caperrors.Error { - return s.triggerService.UnregisterLogTrigger(ctx, triggerID, metadata, input) +func (c *capabilityGRPCService) UnregisterLogTrigger(ctx context.Context, triggerID string, metadata capabilities.RequestMetadata, input *solana.FilterLogTriggerRequest) caperrors.Error { + return c.triggerService.UnregisterLogTrigger(ctx, triggerID, metadata, input) } type closeFunc func() error diff --git a/chain_capabilities/solana/metering/metering.go b/chain_capabilities/solana/metering/metering.go index dfabe19a3..a9bd3d42c 100644 --- a/chain_capabilities/solana/metering/metering.go +++ b/chain_capabilities/solana/metering/metering.go @@ -3,6 +3,7 @@ package metering import ( "fmt" "math/big" + "strconv" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" ) @@ -16,14 +17,18 @@ const ( var WriteReportSpendUnitFormat = "GAS.%d" // %d will be replaced with the chain selector -// GetMeteringNodeDetail returns a MeteringNodeDetail for a given SpendValueCredits. -func GetResponseMetadataWriteReport(fee *big.Float, chainSelector uint64) capabilities.ResponseMetadata { +// GetResponseMetadataWriteReport returns billing ResponseMetadata for a completed write-report +// submission. feeInLamports is the transaction fee in lamports (native fixed-point integer). +// The legacy SpendValue (in SOL) is derived from feeInLamports for backwards compatibility. +func GetResponseMetadataWriteReport(feeInLamports uint64, chainSelector uint64) capabilities.ResponseMetadata { + feeInSol := new(big.Float).Quo(new(big.Float).SetUint64(feeInLamports), big.NewFloat(1e9)) return capabilities.ResponseMetadata{ Metering: []capabilities.MeteringNodeDetail{ { //Peer2PeerID will be assigned by the engine, leaving it empty here. - SpendValue: fee.Text('f', -1), // have to be stored in SOL - SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), + SpendValue: feeInSol.Text('f', -1), + SpendValueInGasUnits: strconv.FormatUint(feeInLamports, 10), + SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), }, }, } diff --git a/chain_capabilities/solana/metering/metering_test.go b/chain_capabilities/solana/metering/metering_test.go index 8dc4cfbca..34903ef41 100644 --- a/chain_capabilities/solana/metering/metering_test.go +++ b/chain_capabilities/solana/metering/metering_test.go @@ -2,6 +2,7 @@ package metering import ( "math/big" + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -11,35 +12,35 @@ import ( func TestGetResponseMetadataWriteReport(t *testing.T) { tests := []struct { name string - fee *big.Float + feeInLamports uint64 chainSelector uint64 expectedSpendUnit string expectedValue string }{ { name: "Standard Solana fee (5000 lamports)", - fee: new(big.Float).Quo(new(big.Float).SetUint64(5000), big.NewFloat(1e9)), + feeInLamports: 5000, chainSelector: 1, expectedSpendUnit: "GAS.1", expectedValue: "0.000005", }, { name: "Large fee (1 SOL)", - fee: new(big.Float).SetFloat64(1.0), + feeInLamports: 1_000_000_000, chainSelector: 42, expectedSpendUnit: "GAS.42", expectedValue: "1", }, { name: "Zero fee", - fee: new(big.Float).SetFloat64(0), + feeInLamports: 0, chainSelector: 100, expectedSpendUnit: "GAS.100", expectedValue: "0", }, { name: "Sub-lamport precision fee", - fee: new(big.Float).Quo(new(big.Float).SetUint64(1), big.NewFloat(1e9)), + feeInLamports: 1, chainSelector: 1, expectedSpendUnit: "GAS.1", expectedValue: "0.000000001", @@ -48,11 +49,17 @@ func TestGetResponseMetadataWriteReport(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - result := GetResponseMetadataWriteReport(test.fee, test.chainSelector) + result := GetResponseMetadataWriteReport(test.feeInLamports, test.chainSelector) require.Len(t, result.Metering, 1) assert.Equal(t, test.expectedSpendUnit, result.Metering[0].SpendUnit) assert.Equal(t, test.expectedValue, result.Metering[0].SpendValue) + assert.Equal(t, strconv.FormatUint(test.feeInLamports, 10), result.Metering[0].SpendValueInGasUnits) assert.Empty(t, result.Metering[0].Peer2PeerID, "Peer2PeerID should be empty") }) } } + +func TestSolanaLamportsToSol(t *testing.T) { + assert.Equal(t, "0.000005", new(big.Float).Quo(new(big.Float).SetUint64(5000), big.NewFloat(1e9)).Text('f', -1)) + assert.Equal(t, "1", new(big.Float).Quo(new(big.Float).SetUint64(1_000_000_000), big.NewFloat(1e9)).Text('f', -1)) +} diff --git a/chain_capabilities/solana/monitoring/messages.go b/chain_capabilities/solana/monitoring/messages.go index e6e4c965f..0e9b87576 100644 --- a/chain_capabilities/solana/monitoring/messages.go +++ b/chain_capabilities/solana/monitoring/messages.go @@ -6,13 +6,12 @@ import ( solgo "github.com/gagliardetto/solana-go" "go.opentelemetry.io/otel/attribute" - solcap "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/solana" + solanacappb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/solana" sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" "github.com/mr-tron/base58" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - solanacappb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/chain-capabilities/solana" capmon "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/monitoring" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/chains/solana" @@ -49,7 +48,7 @@ func (m *MessageBuilder) CapabilityMetricsAttributes() []attribute.KeyValue { } } -func (m *MessageBuilder) BuildWriteReportTxFeeCalculationError(tc TelemetryContext, req *solcap.WriteReportRequest, signature solgo.Signature, cause string) ErrorMessage { +func (m *MessageBuilder) BuildWriteReportTxFeeCalculationError(tc TelemetryContext, req *solanacappb.WriteReportRequest, signature solgo.Signature, cause string) ErrorMessage { summary := "Failed to calculate transaction fee" if !signature.IsZero() { summary = fmt.Sprintf("Failed to calculate transaction fee for tx: %s", signature) diff --git a/chain_capabilities/solana/trigger/trigger.go b/chain_capabilities/solana/trigger/trigger.go index 60f11ff2c..279a9100e 100644 --- a/chain_capabilities/solana/trigger/trigger.go +++ b/chain_capabilities/solana/trigger/trigger.go @@ -3,6 +3,7 @@ package trigger import ( "context" "fmt" + "math" "strconv" "strings" "time" @@ -175,6 +176,9 @@ func (lts *SolanaLogTriggerService) getFinalizedBlockNumber(ctx context.Context, return 0, fmt.Errorf("failed to get latest finalized block: '%w' for triggerID: %s", err, triggerID) } lts.lggr.Debugf("Latest finalized block number: %d, triggerID: %s", block.Height, triggerID) + if block.Height > math.MaxInt64 { + return 0, fmt.Errorf("block height %d exceeds int64 max", block.Height) + } return int64(block.Height), nil } @@ -293,7 +297,7 @@ func (lts *SolanaLogTriggerService) initLimiters(limitsFactory limits.Factory) e if err != nil { return fmt.Errorf("failed to create event rate limiter: %w", err) } - lts.eventPayloadSizeLimiter, err = limits.MakeBoundLimiter(limitsFactory, + lts.eventPayloadSizeLimiter, err = limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.LogTrigger.EventSizeLimit) if err != nil { return fmt.Errorf("failed to create event payload size limiter: %w", err) diff --git a/chain_capabilities/solana/trigger/trigger_integration_test.go b/chain_capabilities/solana/trigger/trigger_integration_test.go index b5fd5d41d..e86d045ca 100644 --- a/chain_capabilities/solana/trigger/trigger_integration_test.go +++ b/chain_capabilities/solana/trigger/trigger_integration_test.go @@ -841,12 +841,12 @@ func downloadLogReadTestProgram(t *testing.T) string { cacheDir := filepath.Join(os.TempDir(), "chainlink-solana-artifacts-"+sha) programPath := filepath.Join(cacheDir, "log_read_test.so") - if _, err := os.Stat(programPath); err == nil { + if _, err := os.Stat(programPath); err == nil { //nolint:gosec // G703: test code, path is constructed from known values t.Logf("Using cached log_read_test.so at %s", programPath) return programPath } - require.NoError(t, os.MkdirAll(cacheDir, 0o755)) + require.NoError(t, os.MkdirAll(cacheDir, 0o755)) //nolint:gosec // G703: test code, path is constructed from known values err := downloadChainlinkSolanaProgramArtifacts(t.Context(), cacheDir, sha) require.NoError(t, err, "failed to download chainlink-solana program artifacts") @@ -870,12 +870,12 @@ func downloadChainlinkSolanaProgramArtifacts(ctx context.Context, targetDir stri } func downloadProgramArtifacts(ctx context.Context, url string, targetDir string) error { - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) //nolint:gosec // G704: test code, URL is controlled by test if err != nil { return err } - res, err := (&http.Client{}).Do(req) + res, err := (&http.Client{}).Do(req) //nolint:gosec // G704: test code, URL is controlled by test if err != nil { return err } @@ -926,11 +926,11 @@ func downloadProgramArtifacts(ctx context.Context, url string, targetDir string) } outPath := filepath.Join(targetDir, filepath.Base(header.Name)) - if err := os.MkdirAll(filepath.Dir(outPath), os.ModePerm); err != nil { + if err := os.MkdirAll(filepath.Dir(outPath), os.ModePerm); err != nil { //nolint:gosec // G703: test code, path is constructed from known values return err } - outFile, err := os.Create(outPath) + outFile, err := os.Create(outPath) //nolint:gosec // G703: test code, path is constructed from known values if err != nil { return err } diff --git a/chain_capabilities/solana/trigger/trigger_test.go b/chain_capabilities/solana/trigger/trigger_test.go index da79c7735..afe1d353b 100644 --- a/chain_capabilities/solana/trigger/trigger_test.go +++ b/chain_capabilities/solana/trigger/trigger_test.go @@ -1006,9 +1006,7 @@ func TestStartPolling(t *testing.T) { <-ctx.Done() mockSolana.AssertExpectations(t) }) - } - func TestErrorHandling(t *testing.T) { t.Run("build query expressions error handling", func(t *testing.T) { request := &solanacappb.FilterLogTriggerRequest{ diff --git a/chain_capabilities/stellar/actions/write_report_test.go b/chain_capabilities/stellar/actions/write_report_test.go index 908960130..4c9ed3f3f 100644 --- a/chain_capabilities/stellar/actions/write_report_test.go +++ b/chain_capabilities/stellar/actions/write_report_test.go @@ -297,6 +297,7 @@ func validateWRMetering(t *testing.T, meta capabilities.ResponseMetadata, chainS m := meta.Metering[0] require.Equal(t, fmt.Sprintf(metering.WriteReportSpendUnitFormat, chainSelector), m.SpendUnit) require.Equal(t, fmt.Sprintf("%d", expectedStroops), m.SpendValue) + require.Equal(t, fmt.Sprintf("%d", expectedStroops), m.SpendValueInGasUnits) require.Empty(t, m.Peer2PeerID) } diff --git a/chain_capabilities/stellar/go.mod b/chain_capabilities/stellar/go.mod index 3b64b08ba..13b19d246 100644 --- a/chain_capabilities/stellar/go.mod +++ b/chain_capabilities/stellar/go.mod @@ -1,10 +1,10 @@ module github.com/smartcontractkit/capabilities/chain_capabilities/stellar -go 1.26.4 +go 1.26.6 require ( github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260717225314-5fc9656c1b02 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee github.com/stellar/go-stellar-sdk v0.7.1 ) @@ -24,7 +24,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 // indirect github.com/cloudevents/sdk-go/v2 v2.16.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect @@ -70,7 +69,6 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect @@ -80,16 +78,16 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13 github.com/smartcontractkit/chain-selectors v1.0.104 - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 // indirect + github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/libocr v0.0.0-20260810200708-618b5bf7f342 - github.com/stretchr/objx v0.5.2 // indirect - github.com/stretchr/testify v1.11.1 + github.com/stretchr/objx v0.5.3 // indirect + github.com/stretchr/testify v1.12.0 github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect diff --git a/chain_capabilities/stellar/go.sum b/chain_capabilities/stellar/go.sum index b95c5a4c1..c56752c48 100644 --- a/chain_capabilities/stellar/go.sum +++ b/chain_capabilities/stellar/go.sum @@ -29,8 +29,6 @@ github.com/cloudevents/sdk-go/v2 v2.16.1/go.mod h1:v/kVOaWjNfbvc6tkhhlkhvLapj8Aa github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= @@ -191,8 +189,6 @@ github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -216,18 +212,18 @@ github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64/go.mod h1:DZkOtlIRV6ecpCskdXMF+k2es3uJQqTT1m5TRB9etjQ= github.com/smartcontractkit/chain-selectors v1.0.104 h1:/n9pPGM5W/+r1eHoWZv4VwX9LNS1af4+ICyhM8zKRNM= github.com/smartcontractkit/chain-selectors v1.0.104/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260717225314-5fc9656c1b02 h1:+zR0LxBXwyNxx04Jk0otLHcPnOw9htWKK0mtWngp+Xg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260717225314-5fc9656c1b02/go.mod h1:tAsXbMsNrwIp7vCqeauNsT4f3gVATbTmIviCkZPDgdo= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62 h1:o7vfwNQjQbMKQ9YsZFQOxvU7RMXD/wKnZsX5N9sDS3w= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260626151909-052e55e62e62/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee h1:tgmFTPN8Aj/pXeVWCQiTDKmNmbFS8G2nUFUE2dy3QWk= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260821143015-dd4fa25f7fee/go.mod h1:HXAfE3CpzesS8GTPLc9W4S4spmBLBTLbGggb5VwK5HQ= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 h1:uWEwl7i2ryuRVoV4DmIKm6mqYevf1lH/8cQYhw/JXko= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72/go.mod h1:UYcRMb4dZcoaIPgZJ3hckCySTqtJc9K4Q+tOKErwTq0= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b h1:L1So1EDBDRET3j/TdV1Gjv3qWARoa/NPRaU7k4r30yA= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b/go.mod h1:HG/aei0MgBOpsyRLexdKGtOUO8yjSJO3iUu0Uu8KBm4= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243 h1:71PGTkjdFZ0JrloEC2Fs8eHl1b1gmUuH+bq7q23usKk= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243/go.mod h1:7ketk4ischPQW/JQgmyHz6zdzLUJv1VC29SiSgosydQ= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33 h1:oW88YVT5ENU6rCPVOLV/hofmFBux2Mu1EOwz8KJu5ic= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260707203317-661b54b51a33/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138 h1:Vk0CZJakAUS/djfBhIJENH4WvM4xl6bY8dYD8cIY/sk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260821155228-fa1d775e2138/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe h1:MDnY5wQbWTpFdDnMRicEnoMfSP5nM/KncARr4skP1ug= @@ -249,8 +245,8 @@ github.com/stellar/go-xdr v0.0.0-20260529210834-0bf8f4956364/go.mod h1:If+U9Z1W5 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -258,8 +254,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= 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/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= diff --git a/chain_capabilities/stellar/main.go b/chain_capabilities/stellar/main.go index 6bdd0dba3..be707b48a 100644 --- a/chain_capabilities/stellar/main.go +++ b/chain_capabilities/stellar/main.go @@ -164,19 +164,18 @@ func (c *capabilityGRPCService) Initialise(ctx context.Context, dependencies cor } var scheduler ts.TransmissionScheduler - if cfg.DeltaStage > 0 { - myDON, err := ts.InitMyDON(ctx, dependencies.CapabilityRegistry, c.id, dependencies.CapabilityDonID, c.lggr, cfg.IsLocal) - if err != nil { - return fmt.Errorf("failed to init DON: %w", err) - } - c.DON = &myDON - scheduler, err = ts.InitialiseTransmissionScheduler(ctx, dependencies.CapabilityRegistry, cfg.DeltaStage, c.lggr, c.DON, cfg.IsLocal) - if err != nil { - return fmt.Errorf("failed to initialize transmission scheduler: %w", err) - } - } else { + if cfg.DeltaStage <= 0 { return fmt.Errorf("delta stage has to be set") } + myDON, err := ts.InitMyDON(ctx, dependencies.CapabilityRegistry, c.id, dependencies.CapabilityDonID, c.lggr, cfg.IsLocal) + if err != nil { + return fmt.Errorf("failed to init DON: %w", err) + } + c.DON = &myDON + scheduler, err = ts.InitialiseTransmissionScheduler(ctx, dependencies.CapabilityRegistry, cfg.DeltaStage, c.lggr, c.DON, cfg.IsLocal) + if err != nil { + return fmt.Errorf("failed to initialize transmission scheduler: %w", err) + } consensusMetrics, err := consMetrics.NewConsensusMetrics(chainInfo) if err != nil { diff --git a/chain_capabilities/stellar/metering/metering.go b/chain_capabilities/stellar/metering/metering.go index 0aac1ee19..6cc3fb120 100644 --- a/chain_capabilities/stellar/metering/metering.go +++ b/chain_capabilities/stellar/metering/metering.go @@ -20,6 +20,7 @@ const ( GetLatestLedger SpendValueCredits = "1" // WriteReportSpendUnitFormat is the spend unit for write operations, parameterised by chain selector. + // TODO: Switch to "GAS.%d" after the workflow DON accepts SpendValueInGasUnits WriteReportSpendUnitFormat = "STROOP.%d" ) @@ -43,8 +44,9 @@ func GetResponseMetadataWriteReport(feeStroops uint64, chainSelector uint64) cap Metering: []capabilities.MeteringNodeDetail{ { // Peer2PeerID is assigned by the engine, leaving it empty here. - SpendValue: strconv.FormatUint(feeStroops, 10), - SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), + SpendValue: strconv.FormatUint(feeStroops, 10), + SpendValueInGasUnits: strconv.FormatUint(feeStroops, 10), + SpendUnit: fmt.Sprintf(WriteReportSpendUnitFormat, chainSelector), }, }, } diff --git a/go.mod b/go.mod index 9b5738e8d..280f22eb0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/capabilities -go 1.26.4 +go 1.26.6 require ( github.com/stretchr/testify v1.11.1 diff --git a/integration_tests/evm/evm_logtrigger_test.go b/integration_tests/evm/evm_logtrigger_test.go index c6efb9b4a..52185a16d 100644 --- a/integration_tests/evm/evm_logtrigger_test.go +++ b/integration_tests/evm/evm_logtrigger_test.go @@ -1,3 +1,5 @@ +//go:build evm_integration + package evmlogtrigger import ( diff --git a/integration_tests/go.mod b/integration_tests/go.mod index 2cd03b82b..7e168de9c 100644 --- a/integration_tests/go.mod +++ b/integration_tests/go.mod @@ -1,15 +1,11 @@ module github.com/smartcontractkit/capabilities/integration_tests -go 1.26.4 +go 1.26.6 replace github.com/smartcontractkit/capabilities/http_action => ../http_action replace github.com/smartcontractkit/capabilities/http_trigger => ../http_trigger -replace github.com/smartcontractkit/capabilities/chain_capabilities/evm => ../chain_capabilities/evm - -replace github.com/smartcontractkit/capabilities/chain_capabilities/common => ../chain_capabilities/common - replace github.com/fbsobreira/gotron-sdk => github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15 replace github.com/olekukonko/tablewriter => github.com/olekukonko/tablewriter v0.0.5 @@ -20,7 +16,7 @@ require ( github.com/ethereum/go-ethereum v1.17.4 github.com/google/uuid v1.6.0 github.com/jonboulle/clockwork v0.5.0 - github.com/smartcontractkit/capabilities/chain_capabilities/evm v0.0.0-00010101000000-000000000000 + github.com/smartcontractkit/capabilities/chain_capabilities/evm v0.0.0-20260821094917-664a97612240 github.com/smartcontractkit/capabilities/http_action v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/capabilities/http_trigger v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chain-selectors v1.0.106 diff --git a/integration_tests/go.sum b/integration_tests/go.sum index 39ddce138..d1e01c31f 100644 --- a/integration_tests/go.sum +++ b/integration_tests/go.sum @@ -1131,6 +1131,10 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13 h1:zUTJ8iBWZsDiiR01sDr4H2q47NBtLHl9ejPq6VOIlkg= +github.com/smartcontractkit/capabilities/chain_capabilities/common v0.0.0-20260729165045-b00a39493e13/go.mod h1:8TpRObM98bypYj+xj6cMFyQs3ti1kqz+Po+m6MMTWnQ= +github.com/smartcontractkit/capabilities/chain_capabilities/evm v0.0.0-20260821094917-664a97612240 h1:+0IOSNXHTnMYmOoVusgf7Y90dmvV4R1sTSzgrzGB/AM= +github.com/smartcontractkit/capabilities/chain_capabilities/evm v0.0.0-20260821094917-664a97612240/go.mod h1:qlIIOCvx7Cb494cnRkXTXqi5/0Gb3u4gK4RZbzYXP5k= github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64 h1:D+N1i+pa+lmmd8llrSgCYmUxG3TX+iyGda5ac2sO4tc= github.com/smartcontractkit/capabilities/libs v0.0.0-20260714133332-db2a5f11cd64/go.mod h1:DZkOtlIRV6ecpCskdXMF+k2es3uJQqTT1m5TRB9etjQ= github.com/smartcontractkit/chain-selectors v1.0.106 h1:6Mz7FDooWJEcfvuOX3nH7oh5s44fqg/WqVDQS63Mjzs= diff --git a/integration_tests/http/http_test.go b/integration_tests/http/http_test.go index 9c7d41e72..3b7f33813 100644 --- a/integration_tests/http/http_test.go +++ b/integration_tests/http/http_test.go @@ -1,3 +1,4 @@ +//nolint:staticcheck // SA1019: Response.Headers is deprecated but tests still use it package http import ( @@ -62,7 +63,7 @@ const serviceConfigTemplate = ` ` func startTestHTTPServer(t *testing.T, handler http.Handler) (net.Listener, func()) { - listener, err := net.Listen("tcp", "127.0.0.1:0") + listener, err := new(net.ListenConfig).Listen(context.Background(), "tcp", "127.0.0.1:0") //nolint:noctx // test code require.NoError(t, err) srv := &http.Server{ diff --git a/integration_tests/utils/deploy.go b/integration_tests/utils/deploy.go index 1dff056d7..16e44c54a 100644 --- a/integration_tests/utils/deploy.go +++ b/integration_tests/utils/deploy.go @@ -20,7 +20,7 @@ func DeployCapability(t *testing.T, capabilityName string) (string, error) { absoluteBinaryPath, err := filepath.Abs(outputBinary) require.NoError(t, err) - cmd := exec.Command("go", "build", "-gcflags", "all=-N -l", "-o", absoluteBinaryPath) + cmd := exec.CommandContext(t.Context(), "go", "build", "-gcflags", "all=-N -l", "-o", absoluteBinaryPath) //nolint:noctx // test code cmd.Dir = projectPath output, err := cmd.CombinedOutput() require.NoError(t, err, string(output)) diff --git a/integration_tests/utils/wasm.go b/integration_tests/utils/wasm.go index 85037114c..26e37443b 100644 --- a/integration_tests/utils/wasm.go +++ b/integration_tests/utils/wasm.go @@ -2,6 +2,7 @@ package utils import ( "bytes" + "context" "encoding/base64" "os" "os/exec" @@ -28,7 +29,7 @@ func GetCompressedWorkflowWasm(t *testing.T, workflowWasmPath string) ([]byte, s } func CreateWasmBinary(t *testing.T, goFile string, wasmFile string) { - cmd := exec.Command("go", "build", "-o", wasmFile, goFile) // #nosec + cmd := exec.CommandContext(context.Background(), "go", "build", "-o", wasmFile, goFile) //nolint:noctx,gosec // test code cmd.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm") output, err := cmd.CombinedOutput()