diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 141720346..e973d9f70 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -23,7 +23,7 @@ jobs: echo "version=${version}" | tee -a "$GITHUB_OUTPUT" - name: Run golangci-lint (integration-tests) if: ${{ always() && !contains(join(github.event.pull_request.labels.*.name, ' '), 'allow-lint-issues') }} - uses: smartcontractkit/.github/actions/ci-lint-go@cdcf67030997adc322ddb2ad48949f394f5b04a3 #ci-lint-go/3.0.0 + uses: smartcontractkit/.github/actions/ci-lint-go@ci-lint-go/v4 env: checkout-repo: false golangci-lint-version: v${{ steps.get-version.outputs.version }} @@ -50,7 +50,7 @@ jobs: - name: Run golangci-lint (relay) if: ${{ always() && !contains(join(github.event.pull_request.labels.*.name, ' '), 'allow-lint-issues') }} - uses: smartcontractkit/.github/actions/ci-lint-go@cdcf67030997adc322ddb2ad48949f394f5b04a3 #ci-lint-go/3.0.0 + uses: smartcontractkit/.github/actions/ci-lint-go@ci-lint-go/v4 with: checkout-repo: false golangci-lint-version: v${{ steps.get-version.outputs.version }} diff --git a/.tool-versions b/.tool-versions index 6ab6f5efa..a933607a3 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,8 +1,8 @@ nodejs 20.18.0 yarn 1.22.19 rust 1.59.0 -golang 1.25.3 -golangci-lint 2.6.1 +golang 1.26.2 +golangci-lint 2.12.2 actionlint 1.6.22 shellcheck 0.8.0 helm 3.18.4 diff --git a/contracts/go.mod b/contracts/go.mod index d57640cc6..e41cd983b 100644 --- a/contracts/go.mod +++ b/contracts/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink-solana/contracts -go 1.25.7 +go 1.26.2 require ( github.com/Unheilbar/anchor-go v1.0.3 @@ -108,9 +108,9 @@ require ( github.com/shirou/gopsutil/v4 v4.26.2 // indirect github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect github.com/sirupsen/logrus v1.9.4 // indirect - github.com/smartcontractkit/chain-selectors v1.0.98 // indirect + github.com/smartcontractkit/chain-selectors v1.0.100 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 // indirect - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71 // indirect + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa // indirect github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.6 // indirect github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260218133534-cbd44da2856b // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect @@ -137,14 +137,14 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect go.uber.org/zap v1.27.1 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect - golang.org/x/net v0.52.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect + golang.org/x/net v0.55.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/term v0.41.0 // indirect - golang.org/x/text v0.35.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/contracts/go.sum b/contracts/go.sum index dcd64caf0..9fafa6da9 100644 --- a/contracts/go.sum +++ b/contracts/go.sum @@ -419,10 +419,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= @@ -448,16 +448,16 @@ github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97M github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/smartcontractkit/chain-selectors v1.0.98 h1:fuI7CQ1o5cX64eO4/LvwtfhdpGFH5vnsM/bFHRwEiww= -github.com/smartcontractkit/chain-selectors v1.0.98/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chain-selectors v1.0.100 h1:wpiSpmI/eFjY+wx/nPr5VuNF4hki0prIBMKEaQWn3g4= +github.com/smartcontractkit/chain-selectors v1.0.100/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 h1:zrr/54Tr/aVqV/9c45DtyuOxTI4+OMETIKH5bSQSfhE= 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.20260421191147-d10b9943ac71 h1:WSNUds78NMlwDttROK/hJZ6ZOremyrR5JXJmPlT8hO8= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71/go.mod h1:kOIIjzxuRXK31j1JdZgUAGjqbGwmJ5gU5qI+FMkP6/I= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa h1:bd1aJVR6fPjyMsJKq5hEsR6SgpxacbMwG8LABkC5qq8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa/go.mod h1:fP9RqD25/gTx3XqRstN8o4lAI3jp42vwJBLRZwRoOOM= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8 h1:5O2qAtvBLzTHBeSIPcxt9i9BCqqOyeroVxN0xbXwoS0= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= github.com/smartcontractkit/chainlink-deployments-framework v0.75.0 h1:9ZjyePOYM5+M/d5JHOA5dUx6UdDWqqS0NRlvFRlHUII= github.com/smartcontractkit/chainlink-deployments-framework v0.75.0/go.mod h1:ik4yPeO0zESdC4Axjies+EvdLw7W0g1CEDTXsThNdRk= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243 h1:vaFBupfFfImQgqOeuC7Muk2GflbYP6Gpi0Y/TLroFU8= @@ -594,8 +594,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -605,14 +605,14 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -624,8 +624,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -659,30 +659,30 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go.mod b/go.mod index 37879ee4d..35e449f9e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink-solana -go 1.25.7 +go 1.26.2 require ( github.com/cometbft/cometbft v0.38.21 @@ -12,31 +12,31 @@ require ( github.com/gagliardetto/utilz v0.1.3 github.com/go-viper/mapstructure/v2 v2.5.0 github.com/google/uuid v1.6.0 - github.com/hashicorp/go-plugin v1.7.0 + github.com/hashicorp/go-plugin v1.8.0 github.com/jackc/pgx/v4 v4.18.3 github.com/lib/pq v1.11.1 github.com/pelletier/go-toml/v2 v2.2.4 github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_model v0.6.2 - github.com/smartcontractkit/chain-selectors v1.0.98 + github.com/smartcontractkit/chain-selectors v1.0.100 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340 github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260505131349-78e491b80735 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad github.com/smartcontractkit/libocr v0.0.0-20260403184524-b6409238958d github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/metric v1.43.0 go.uber.org/zap v1.27.1 - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a golang.org/x/sync v0.20.0 - golang.org/x/text v0.35.0 + golang.org/x/text v0.37.0 ) require ( @@ -144,8 +144,8 @@ require ( github.com/pion/transport/v2 v2.2.10 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/riferrei/srclient v0.5.4 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect @@ -155,7 +155,7 @@ require ( github.com/shirou/gopsutil/v4 v4.25.9 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect + github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8 // 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-20260319180422-b5808c964785 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect @@ -176,6 +176,7 @@ require ( github.com/zeebo/xxh3 v1.0.2 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect @@ -195,17 +196,18 @@ require ( go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/atomic v1.11.0 // indirect + go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.52.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect - golang.org/x/term v0.41.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.45.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect diff --git a/go.sum b/go.sum index 1e16d54ec..16ca22530 100644 --- a/go.sum +++ b/go.sum @@ -384,8 +384,8 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= -github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= +github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -677,12 +677,12 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/riferrei/srclient v0.5.4 h1:dfwyR5u23QF7beuVl2WemUY2KXh5+Sc4DHKyPXBNYuc= github.com/riferrei/srclient v0.5.4/go.mod h1:vbkLmWcgYa7JgfPvuy/+K8fTS0p1bApqadxrxi/S1MI= @@ -726,28 +726,28 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/smartcontractkit/chain-selectors v1.0.98 h1:fuI7CQ1o5cX64eO4/LvwtfhdpGFH5vnsM/bFHRwEiww= -github.com/smartcontractkit/chain-selectors v1.0.98/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chain-selectors v1.0.100 h1:wpiSpmI/eFjY+wx/nPr5VuNF4hki0prIBMKEaQWn3g4= +github.com/smartcontractkit/chain-selectors v1.0.100/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70/go.mod h1:iZTLsjnvzUR4QODACgkvJ2Xd1z1YYJJvEnLZ61K/sfw= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 h1:zrr/54Tr/aVqV/9c45DtyuOxTI4+OMETIKH5bSQSfhE= 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.20260421191147-d10b9943ac71 h1:WSNUds78NMlwDttROK/hJZ6ZOremyrR5JXJmPlT8hO8= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71/go.mod h1:kOIIjzxuRXK31j1JdZgUAGjqbGwmJ5gU5qI+FMkP6/I= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa h1:bd1aJVR6fPjyMsJKq5hEsR6SgpxacbMwG8LABkC5qq8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa/go.mod h1:fP9RqD25/gTx3XqRstN8o4lAI3jp42vwJBLRZwRoOOM= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8 h1:5O2qAtvBLzTHBeSIPcxt9i9BCqqOyeroVxN0xbXwoS0= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340 h1:PsjEI+5jZIz9AS4eOsLS5VpSWJINf38clXV3wryPyMk= github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340/go.mod h1:P/0OSXUlFaxxD4B/P6HWbxYtIRmmWGDJAvanq19879c= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243 h1:vaFBupfFfImQgqOeuC7Muk2GflbYP6Gpi0Y/TLroFU8= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243/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/cre/go v0.0.0-20260505131349-78e491b80735 h1:5bxDnwI0wuPoC0H5H3H2n9CnQPb5iakR6UmAY4j8KUg= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260505131349-78e491b80735/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f h1:t+OoYaXLdH0WHK2pbWKjTSnSQa5JBQD1+gf0yISYfQk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f/go.mod h1:vTFHTCbLui4Vn8fTmAadfE3rdnvfrDwOmMujmW857D0= 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/node-platform v0.0.0-20260319180422-b5808c964785 h1:oli+2uLU6jcrJGCuYFqk3475hiwL17SWlITWLv+tx/w= @@ -857,6 +857,8 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 h1:w3zlHYETbDwXyWHZlyyR58ZC39XGi8rAhkBgUgJ9d5w= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0/go.mod h1:GR/mClR2nn7vE8RLwxKjoBNg+QtgdDhRzxVa93koy5o= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= @@ -931,8 +933,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -953,8 +955,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -965,8 +967,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -991,8 +993,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1031,8 +1033,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1113,10 +1115,10 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 h1:2EucmYlcIsc8Y6aLj+kX90Y00hmjqLNlw935kc13R2k= +golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2/go.mod h1:Eqhaxk/wZsWEH8CRxLwj6xzEJbz7k1EFGqx7nyCoabE= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1126,8 +1128,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1141,13 +1143,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1193,8 +1195,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 9b900ecbf..921a5b7ac 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink-solana/integration-tests -go 1.25.7 +go 1.26.2 replace github.com/smartcontractkit/chainlink-solana => ../ @@ -19,10 +19,10 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.34.0 - github.com/smartcontractkit/chain-selectors v1.0.98 + github.com/smartcontractkit/chain-selectors v1.0.100 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260505131349-78e491b80735 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f github.com/smartcontractkit/chainlink-solana v1.1.2-0.20260409203251-51e31d9d11e9 github.com/smartcontractkit/chainlink-solana/contracts v0.0.0-20260217175957-8f1af02c5075 github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.3 @@ -32,7 +32,7 @@ require ( github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.40.0 go.uber.org/zap v1.27.1 - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a golang.org/x/sync v0.20.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -118,7 +118,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-plugin v1.7.0 // indirect + github.com/hashicorp/go-plugin v1.8.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -169,8 +169,8 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -183,7 +183,7 @@ require ( github.com/sirupsen/logrus v1.9.4 // indirect github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 // indirect - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect + github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8 // indirect github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260521164805-26d78d5e1243 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect @@ -227,20 +227,21 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect + go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect golang.org/x/arch v0.11.0 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.52.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect - golang.org/x/term v0.41.0 // indirect - golang.org/x/text v0.35.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.45.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 3a5b7d3bd..05f3307f2 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -416,8 +416,8 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= -github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= +github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -690,12 +690,12 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= @@ -738,26 +738,26 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/smartcontractkit/chain-selectors v1.0.98 h1:fuI7CQ1o5cX64eO4/LvwtfhdpGFH5vnsM/bFHRwEiww= -github.com/smartcontractkit/chain-selectors v1.0.98/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chain-selectors v1.0.100 h1:wpiSpmI/eFjY+wx/nPr5VuNF4hki0prIBMKEaQWn3g4= +github.com/smartcontractkit/chain-selectors v1.0.100/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70/go.mod h1:iZTLsjnvzUR4QODACgkvJ2Xd1z1YYJJvEnLZ61K/sfw= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 h1:zrr/54Tr/aVqV/9c45DtyuOxTI4+OMETIKH5bSQSfhE= 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.20260421191147-d10b9943ac71 h1:WSNUds78NMlwDttROK/hJZ6ZOremyrR5JXJmPlT8hO8= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260421191147-d10b9943ac71/go.mod h1:kOIIjzxuRXK31j1JdZgUAGjqbGwmJ5gU5qI+FMkP6/I= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa h1:bd1aJVR6fPjyMsJKq5hEsR6SgpxacbMwG8LABkC5qq8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260610124317-1a3c32c46eaa/go.mod h1:fP9RqD25/gTx3XqRstN8o4lAI3jp42vwJBLRZwRoOOM= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8 h1:5O2qAtvBLzTHBeSIPcxt9i9BCqqOyeroVxN0xbXwoS0= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260528204832-58c7145c53f8/go.mod h1:HmUyH2oD9m+GRpKq7q3vuRnm1F2Uczf/Nd1v3ipMSK8= github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340 h1:PsjEI+5jZIz9AS4eOsLS5VpSWJINf38clXV3wryPyMk= github.com/smartcontractkit/chainlink-common/pkg/monitoring v0.0.0-20251215152504-b1e41f508340/go.mod h1:P/0OSXUlFaxxD4B/P6HWbxYtIRmmWGDJAvanq19879c= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243 h1:vaFBupfFfImQgqOeuC7Muk2GflbYP6Gpi0Y/TLroFU8= github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260521164805-26d78d5e1243/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/cre/go v0.0.0-20260505131349-78e491b80735 h1:5bxDnwI0wuPoC0H5H3H2n9CnQPb5iakR6UmAY4j8KUg= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260505131349-78e491b80735/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f h1:t+OoYaXLdH0WHK2pbWKjTSnSQa5JBQD1+gf0yISYfQk= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260604171908-6734db2d444f/go.mod h1:vTFHTCbLui4Vn8fTmAadfE3rdnvfrDwOmMujmW857D0= 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-testing-framework/framework v0.15.3 h1:wMxGJzQrKF5J9Msmpeal1Iw3h4RqPwOZ2I1ZjlSqhZo= @@ -939,8 +939,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4= golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -954,8 +954,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -966,8 +966,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -989,8 +989,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1023,8 +1023,8 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1099,16 +1099,16 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2 h1:2EucmYlcIsc8Y6aLj+kX90Y00hmjqLNlw935kc13R2k= +golang.org/x/telemetry v0.0.0-20260519152614-eab6ae52b5e2/go.mod h1:Eqhaxk/wZsWEH8CRxLwj6xzEJbz7k1EFGqx7nyCoabE= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1116,13 +1116,13 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1164,8 +1164,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/ops/monitoring/Dockerfile b/ops/monitoring/Dockerfile index 009df92c6..d594eeaff 100644 --- a/ops/monitoring/Dockerfile +++ b/ops/monitoring/Dockerfile @@ -1,6 +1,6 @@ # Build image -FROM golang:1.25 AS build +FROM golang:1.26 AS build # OS dependencies RUN apt-get update && apt-get install -y wget gcc diff --git a/pkg/monitoring/metrics/mocks/Fees.go b/pkg/monitoring/metrics/mocks/Fees.go index 9d6811e1b..6f9762597 100644 --- a/pkg/monitoring/metrics/mocks/Fees.go +++ b/pkg/monitoring/metrics/mocks/Fees.go @@ -5,7 +5,6 @@ package mocks import ( metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" fees "github.com/smartcontractkit/chainlink-solana/pkg/solana/fees" - mock "github.com/stretchr/testify/mock" ) diff --git a/pkg/monitoring/metrics/mocks/feed_balances.go b/pkg/monitoring/metrics/mocks/feed_balances.go index 7865d35e3..ebd8dd254 100644 --- a/pkg/monitoring/metrics/mocks/feed_balances.go +++ b/pkg/monitoring/metrics/mocks/feed_balances.go @@ -3,10 +3,9 @@ package mocks import ( + prometheus "github.com/prometheus/client_golang/prometheus" metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" mock "github.com/stretchr/testify/mock" - - prometheus "github.com/prometheus/client_golang/prometheus" ) // FeedBalances is an autogenerated mock type for the FeedBalances type diff --git a/pkg/monitoring/mocks/chain_reader.go b/pkg/monitoring/mocks/chain_reader.go index 79ed8eaba..6a8a35e52 100644 --- a/pkg/monitoring/mocks/chain_reader.go +++ b/pkg/monitoring/mocks/chain_reader.go @@ -7,11 +7,9 @@ import ( mock "github.com/stretchr/testify/mock" - pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" - - rpc "github.com/gagliardetto/solana-go/rpc" - solana "github.com/gagliardetto/solana-go" + rpc "github.com/gagliardetto/solana-go/rpc" + pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" ) // ChainReader is an autogenerated mock type for the ChainReader type diff --git a/pkg/solana/CONFIG.md b/pkg/solana/CONFIG.md index 5981ad2df..86a79a299 100644 --- a/pkg/solana/CONFIG.md +++ b/pkg/solana/CONFIG.md @@ -357,6 +357,7 @@ GasLimitDefault = 300_000 # Default Local = false # Default PollPeriod = '3s' # Default TxAcceptanceState = 3 # Default +RequestSizeLimit = 0 # Default ``` @@ -411,6 +412,13 @@ TxAcceptanceState = 3 # Default ``` TxAcceptanceState is the default acceptance state for writer DON tranmissions. +### RequestSizeLimit +```toml +RequestSizeLimit = 0 # Default +``` +RequestSizeLimit caps the size in bytes of HTTP responses from Solana RPC for requests originated +by workflow capabilities (external requests). Set to 0 to disable the cap. + ## Nodes ```toml [[Nodes]] diff --git a/pkg/solana/chainreader/mocks/events_reader.go b/pkg/solana/chainreader/mocks/events_reader.go index f6b541e75..06aef368d 100644 --- a/pkg/solana/chainreader/mocks/events_reader.go +++ b/pkg/solana/chainreader/mocks/events_reader.go @@ -6,9 +6,8 @@ import ( context "context" query "github.com/smartcontractkit/chainlink-common/pkg/types/query" - mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/types" + mock "github.com/stretchr/testify/mock" ) // EventsReader is an autogenerated mock type for the EventsReader type diff --git a/pkg/solana/client/client.go b/pkg/solana/client/client.go index a309f08eb..55c57ae99 100644 --- a/pkg/solana/client/client.go +++ b/pkg/solana/client/client.go @@ -4,12 +4,15 @@ import ( "context" "errors" "fmt" + "net/http" "time" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" + "github.com/gagliardetto/solana-go/rpc/jsonrpc" "golang.org/x/sync/singleflight" + commonhttp "github.com/smartcontractkit/chainlink-common/pkg/http" "github.com/smartcontractkit/chainlink-common/pkg/logger" mn "github.com/smartcontractkit/chainlink-framework/multinode" @@ -48,11 +51,12 @@ type ReaderWriter interface { type Reader interface { AccountReader Balance(ctx context.Context, addr solana.PublicKey) (uint64, error) - BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (uint64, error) + BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetBalanceResult, error) SlotHeight(ctx context.Context) (uint64, error) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) ChainID(ctx context.Context) (mn.StringID, error) GetFeeForMessage(ctx context.Context, msg string) (uint64, error) + GetFeeForMessageWithCommitment(ctx context.Context, msg string, commitment rpc.CommitmentType) (*rpc.GetFeeForMessageResult, error) GetFirstAvailableBlock(ctx context.Context) (out uint64, err error) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) // GetLatestBlockHeight returns the latest block height of the node based on the configured commitment type @@ -70,6 +74,7 @@ type Reader interface { type AccountReader interface { GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) GetMultipleAccountsWithOpts(ctx context.Context, accounts []solana.PublicKey, opts *rpc.GetMultipleAccountsOpts) (out *rpc.GetMultipleAccountsResult, err error) + GetProgramAccountsWithOpts(ctx context.Context, program solana.PublicKey, opts *rpc.GetProgramAccountsOpts) (out rpc.GetProgramAccountsResult, err error) GetAccountDataBorshInto(ctx context.Context, addr solana.PublicKey, accountType any) (err error) } @@ -115,10 +120,23 @@ func NewTestClient(endpoint string, cfg *config.TOMLConfig, requestTimeout time. log: log, requestGroup: &singleflight.Group{}, } - rpcClient.rpc = rpc.New(endpoint) + rpcClient.rpc = newRPCClientWithLimitedTransport(endpoint) return &rpcClient, rpcClient.rpc, nil } +// newRPCClientWithLimitedTransport constructs a solana-go *rpc.Client whose HTTP transport is +// wrapped with commonhttp.LimitedTransport. The size cap is opt-in per request via +// commonhttp.WithResponseSizeLimit on the request context; when no limit is set the wrapper is a +// no-op. The underlying transport is http.DefaultTransport, so time bounds come from each method's +// context.WithTimeout(ctx, c.contextDuration) wrapper. +func newRPCClientWithLimitedTransport(endpoint string) *rpc.Client { + httpClient := &http.Client{ + Transport: &commonhttp.LimitedTransport{RoundTripper: http.DefaultTransport}, + } + jrpc := jsonrpc.NewClientWithOpts(endpoint, &jsonrpc.RPCClientOpts{HTTPClient: httpClient}) + return rpc.NewWithCustomRPCClient(jrpc) +} + func NewClient(endpoint string, cfg *config.TOMLConfig, requestTimeout time.Duration, log logger.Logger) (*Client, error) { rpcClient, _, err := NewTestClient(endpoint, cfg, requestTimeout, log) return rpcClient, err @@ -154,7 +172,7 @@ func (c *Client) Balance(ctx context.Context, addr solana.PublicKey) (bal uint64 return res.Value, err } -func (c *Client) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (bal uint64, err error) { +func (c *Client) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (bal *rpc.GetBalanceResult, err error) { done := c.latency("balance") defer func() { done(err) }() @@ -166,16 +184,16 @@ func (c *Client) BalanceWithCommitment(ctx context.Context, addr solana.PublicKe }) if err != nil { - return 0, err + return nil, err } res, ok := v.(*rpc.GetBalanceResult) if !ok { - return 0, fmt.Errorf("result is unexpected type %T, expected %T", v, &rpc.GetBalanceResult{}) + return nil, fmt.Errorf("result is unexpected type %T, expected %T", v, &rpc.GetBalanceResult{}) } if res == nil { - return 0, errors.New("BalanceWithCommitment returned nil result") + return nil, errors.New("BalanceWithCommitment returned nil result") } - return res.Value, err + return res, err } func (c *Client) SlotHeight(ctx context.Context) (uint64, error) { @@ -258,6 +276,19 @@ func (c *Client) GetMultipleAccountsWithOpts(ctx context.Context, accounts []sol return c.rpc.GetMultipleAccountsWithOpts(ctx, accounts, opts) } +func (c *Client) GetProgramAccountsWithOpts(ctx context.Context, program solana.PublicKey, opts *rpc.GetProgramAccountsOpts) (out rpc.GetProgramAccountsResult, err error) { + done := c.latency("program_accounts") + defer func() { done(err) }() + + ctx, cancel := context.WithTimeout(ctx, c.contextDuration) + defer cancel() + if opts == nil { + opts = &rpc.GetProgramAccountsOpts{} + } + opts.Commitment = c.commitment // overrides passed in value - use defined client commitment type + return c.rpc.GetProgramAccountsWithOpts(ctx, program, opts) +} + func (c *Client) GetAccountDataBorshInto(ctx context.Context, addr solana.PublicKey, inVar interface{}) (err error) { done := c.latency("get_account_data_borsh_into") defer func() { done(err) }() @@ -365,6 +396,25 @@ func (c *Client) GetFeeForMessage(ctx context.Context, msg string) (fee uint64, return *res.Value, nil } +func (c *Client) GetFeeForMessageWithCommitment(ctx context.Context, msg string, commitment rpc.CommitmentType) (result *rpc.GetFeeForMessageResult, err error) { + done := c.latency("fee_for_message") + defer func() { done(err) }() + + // msg is base58 encoded data + + ctx, cancel := context.WithTimeout(ctx, c.contextDuration) + defer cancel() + res, err := c.rpc.GetFeeForMessage(ctx, msg, commitment) + if err != nil { + return nil, fmt.Errorf("error in GetFeeForMessage: %w", err) + } + + if res == nil || res.Value == nil { + return nil, errors.New("nil pointer in GetFeeForMessage") + } + return res, nil +} + // https://docs.solana.com/developing/clients/jsonrpc-api#getsignaturestatuses func (c *Client) SignatureStatuses(ctx context.Context, sigs []solana.Signature) (statuses []*rpc.SignatureStatusesResult, err error) { done := c.latency("signature_statuses") diff --git a/pkg/solana/client/client_response_size_test.go b/pkg/solana/client/client_response_size_test.go new file mode 100644 index 000000000..1640051bd --- /dev/null +++ b/pkg/solana/client/client_response_size_test.go @@ -0,0 +1,79 @@ +package client + +import ( + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commonhttp "github.com/smartcontractkit/chainlink-common/pkg/http" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" +) + +// TestClient_ResponseSizeLimit_FromContext exercises the full path from NewClient through +// jsonrpc.NewClientWithOpts to the commonhttp.LimitedTransport wrapper. It proves three things: +// - The transport is actually wired into the underlying solana-go *rpc.Client (otherwise the +// context limit would have no effect). +// - commonhttp.WithResponseSizeLimit propagates through Client.requestGroup.Do(...) into the +// outbound *http.Request.Context() (singleflight callback closure preservation). +// - An oversized RPC response surfaces to the caller as an error (not silent truncation). +func TestClient_ResponseSizeLimit_FromContext(t *testing.T) { + t.Parallel() + + // Pad the "result" string so the JSON body is comfortably larger than any per-test limit + // but still a syntactically valid JSON-RPC response envelope. + bigResult := strings.Repeat("x", 64*1024) // 64 KiB + body := fmt.Sprintf(`{"jsonrpc":"2.0","result":"%s","id":1}`, bigResult) + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, err := w.Write([]byte(body)) + assert.NoError(t, err) + })) + t.Cleanup(srv.Close) + + requestTimeout := 5 * time.Second + cfg := config.NewDefault() + + t.Run("no limit set -> body fully read, no size error", func(t *testing.T) { + c, err := NewClient(srv.URL, cfg, requestTimeout, logger.Test(t)) + require.NoError(t, err) + + // "result" is not a valid base58 genesis hash, so ChainID will return an error from + // solana-go's Hash parsing; the point is that the error MUST NOT be a size-cap error + // because no limit was set on the context. + _, err = c.ChainID(t.Context()) + require.Error(t, err) + require.NotContains(t, err.Error(), "response is too large", + "unexpected size-cap error when no limit is set") + }) + + t.Run("limit larger than body -> body fully read, no size error", func(t *testing.T) { + c, err := NewClient(srv.URL, cfg, requestTimeout, logger.Test(t)) + require.NoError(t, err) + + // Fixed headroom above body size; avoid uint32(len(body)) (G115 on int→uint32). + ctx := commonhttp.WithResponseSizeLimit(t.Context(), 2*1024*1024) + _, err = c.ChainID(ctx) + require.Error(t, err) + require.NotContains(t, err.Error(), "response is too large", + "unexpected size-cap error when limit exceeds body size") + }) + + t.Run("limit smaller than body -> size error surfaces", func(t *testing.T) { + c, err := NewClient(srv.URL, cfg, requestTimeout, logger.Test(t)) + require.NoError(t, err) + + ctx := commonhttp.WithResponseSizeLimit(t.Context(), 1024) + _, err = c.ChainID(ctx) + require.Error(t, err) + require.ErrorContains(t, err, "response is too large") + }) +} diff --git a/pkg/solana/client/mocks/reader_writer.go b/pkg/solana/client/mocks/reader_writer.go index 40375ca2d..33cf34ca4 100644 --- a/pkg/solana/client/mocks/reader_writer.go +++ b/pkg/solana/client/mocks/reader_writer.go @@ -5,12 +5,10 @@ package mocks import ( context "context" + solana "github.com/gagliardetto/solana-go" + rpc "github.com/gagliardetto/solana-go/rpc" multinode "github.com/smartcontractkit/chainlink-framework/multinode" mock "github.com/stretchr/testify/mock" - - rpc "github.com/gagliardetto/solana-go/rpc" - - solana "github.com/gagliardetto/solana-go" ) // ReaderWriter is an autogenerated mock type for the ReaderWriter type @@ -84,22 +82,24 @@ func (_c *ReaderWriter_Balance_Call) RunAndReturn(run func(context.Context, sola } // BalanceWithCommitment provides a mock function with given fields: ctx, addr, commitment -func (_m *ReaderWriter) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (uint64, error) { +func (_m *ReaderWriter) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetBalanceResult, error) { ret := _m.Called(ctx, addr, commitment) if len(ret) == 0 { panic("no return value specified for BalanceWithCommitment") } - var r0 uint64 + var r0 *rpc.GetBalanceResult var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (uint64, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetBalanceResult, error)); ok { return rf(ctx, addr, commitment) } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) uint64); ok { + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) *rpc.GetBalanceResult); ok { r0 = rf(ctx, addr, commitment) } else { - r0 = ret.Get(0).(uint64) + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBalanceResult) + } } if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { @@ -131,12 +131,12 @@ func (_c *ReaderWriter_BalanceWithCommitment_Call) Run(run func(ctx context.Cont return _c } -func (_c *ReaderWriter_BalanceWithCommitment_Call) Return(_a0 uint64, _a1 error) *ReaderWriter_BalanceWithCommitment_Call { +func (_c *ReaderWriter_BalanceWithCommitment_Call) Return(_a0 *rpc.GetBalanceResult, _a1 error) *ReaderWriter_BalanceWithCommitment_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *ReaderWriter_BalanceWithCommitment_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (uint64, error)) *ReaderWriter_BalanceWithCommitment_Call { +func (_c *ReaderWriter_BalanceWithCommitment_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetBalanceResult, error)) *ReaderWriter_BalanceWithCommitment_Call { _c.Call.Return(run) return _c } @@ -601,6 +601,66 @@ func (_c *ReaderWriter_GetFeeForMessage_Call) RunAndReturn(run func(context.Cont return _c } +// GetFeeForMessageWithCommitment provides a mock function with given fields: ctx, msg, commitment +func (_m *ReaderWriter) GetFeeForMessageWithCommitment(ctx context.Context, msg string, commitment rpc.CommitmentType) (*rpc.GetFeeForMessageResult, error) { + ret := _m.Called(ctx, msg, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetFeeForMessageWithCommitment") + } + + var r0 *rpc.GetFeeForMessageResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, rpc.CommitmentType) (*rpc.GetFeeForMessageResult, error)); ok { + return rf(ctx, msg, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, string, rpc.CommitmentType) *rpc.GetFeeForMessageResult); ok { + r0 = rf(ctx, msg, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetFeeForMessageResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, rpc.CommitmentType) error); ok { + r1 = rf(ctx, msg, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetFeeForMessageWithCommitment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeeForMessageWithCommitment' +type ReaderWriter_GetFeeForMessageWithCommitment_Call struct { + *mock.Call +} + +// GetFeeForMessageWithCommitment is a helper method to define mock.On call +// - ctx context.Context +// - msg string +// - commitment rpc.CommitmentType +func (_e *ReaderWriter_Expecter) GetFeeForMessageWithCommitment(ctx interface{}, msg interface{}, commitment interface{}) *ReaderWriter_GetFeeForMessageWithCommitment_Call { + return &ReaderWriter_GetFeeForMessageWithCommitment_Call{Call: _e.mock.On("GetFeeForMessageWithCommitment", ctx, msg, commitment)} +} + +func (_c *ReaderWriter_GetFeeForMessageWithCommitment_Call) Run(run func(ctx context.Context, msg string, commitment rpc.CommitmentType)) *ReaderWriter_GetFeeForMessageWithCommitment_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ReaderWriter_GetFeeForMessageWithCommitment_Call) Return(_a0 *rpc.GetFeeForMessageResult, _a1 error) *ReaderWriter_GetFeeForMessageWithCommitment_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetFeeForMessageWithCommitment_Call) RunAndReturn(run func(context.Context, string, rpc.CommitmentType) (*rpc.GetFeeForMessageResult, error)) *ReaderWriter_GetFeeForMessageWithCommitment_Call { + _c.Call.Return(run) + return _c +} + // GetFirstAvailableBlock provides a mock function with given fields: ctx func (_m *ReaderWriter) GetFirstAvailableBlock(ctx context.Context) (uint64, error) { ret := _m.Called(ctx) @@ -831,6 +891,66 @@ func (_c *ReaderWriter_GetMultipleAccountsWithOpts_Call) RunAndReturn(run func(c return _c } +// GetProgramAccountsWithOpts provides a mock function with given fields: ctx, program, opts +func (_m *ReaderWriter) GetProgramAccountsWithOpts(ctx context.Context, program solana.PublicKey, opts *rpc.GetProgramAccountsOpts) (rpc.GetProgramAccountsResult, error) { + ret := _m.Called(ctx, program, opts) + + if len(ret) == 0 { + panic("no return value specified for GetProgramAccountsWithOpts") + } + + var r0 rpc.GetProgramAccountsResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetProgramAccountsOpts) (rpc.GetProgramAccountsResult, error)); ok { + return rf(ctx, program, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetProgramAccountsOpts) rpc.GetProgramAccountsResult); ok { + r0 = rf(ctx, program, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rpc.GetProgramAccountsResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetProgramAccountsOpts) error); ok { + r1 = rf(ctx, program, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetProgramAccountsWithOpts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProgramAccountsWithOpts' +type ReaderWriter_GetProgramAccountsWithOpts_Call struct { + *mock.Call +} + +// GetProgramAccountsWithOpts is a helper method to define mock.On call +// - ctx context.Context +// - program solana.PublicKey +// - opts *rpc.GetProgramAccountsOpts +func (_e *ReaderWriter_Expecter) GetProgramAccountsWithOpts(ctx interface{}, program interface{}, opts interface{}) *ReaderWriter_GetProgramAccountsWithOpts_Call { + return &ReaderWriter_GetProgramAccountsWithOpts_Call{Call: _e.mock.On("GetProgramAccountsWithOpts", ctx, program, opts)} +} + +func (_c *ReaderWriter_GetProgramAccountsWithOpts_Call) Run(run func(ctx context.Context, program solana.PublicKey, opts *rpc.GetProgramAccountsOpts)) *ReaderWriter_GetProgramAccountsWithOpts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(*rpc.GetProgramAccountsOpts)) + }) + return _c +} + +func (_c *ReaderWriter_GetProgramAccountsWithOpts_Call) Return(out rpc.GetProgramAccountsResult, err error) *ReaderWriter_GetProgramAccountsWithOpts_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *ReaderWriter_GetProgramAccountsWithOpts_Call) RunAndReturn(run func(context.Context, solana.PublicKey, *rpc.GetProgramAccountsOpts) (rpc.GetProgramAccountsResult, error)) *ReaderWriter_GetProgramAccountsWithOpts_Call { + _c.Call.Return(run) + return _c +} + // GetSignaturesForAddressWithOpts provides a mock function with given fields: ctx, addr, opts func (_m *ReaderWriter) GetSignaturesForAddressWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { ret := _m.Called(ctx, addr, opts) diff --git a/pkg/solana/client/multi_client.go b/pkg/solana/client/multi_client.go index c68ef72dd..16c7ca4aa 100644 --- a/pkg/solana/client/multi_client.go +++ b/pkg/solana/client/multi_client.go @@ -77,6 +77,15 @@ func (m *MultiClient) GetMultipleAccountsWithOpts(ctx context.Context, accounts return r.GetMultipleAccountsWithOpts(ctx, accounts, opts) } +func (m *MultiClient) GetProgramAccountsWithOpts(ctx context.Context, program solana.PublicKey, opts *rpc.GetProgramAccountsOpts) (out rpc.GetProgramAccountsResult, err error) { + r, err := m.getClient(ctx) + if err != nil { + return nil, err + } + + return r.GetProgramAccountsWithOpts(ctx, program, opts) +} + func (m *MultiClient) GetAccountDataBorshInto(ctx context.Context, addr solana.PublicKey, inVar interface{}) (err error) { r, err := m.getClient(ctx) if err != nil { @@ -95,10 +104,10 @@ func (m *MultiClient) Balance(ctx context.Context, addr solana.PublicKey) (uint6 return r.Balance(ctx, addr) } -func (m *MultiClient) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (uint64, error) { +func (m *MultiClient) BalanceWithCommitment(ctx context.Context, addr solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetBalanceResult, error) { r, err := m.getClient(ctx) if err != nil { - return 0, err + return nil, err } return r.BalanceWithCommitment(ctx, addr, commitment) @@ -149,6 +158,15 @@ func (m *MultiClient) GetFeeForMessage(ctx context.Context, msg string) (uint64, return r.GetFeeForMessage(ctx, msg) } +func (m *MultiClient) GetFeeForMessageWithCommitment(ctx context.Context, msg string, commitment rpc.CommitmentType) (*rpc.GetFeeForMessageResult, error) { + r, err := m.getClient(ctx) + if err != nil { + return nil, err + } + + return r.GetFeeForMessageWithCommitment(ctx, msg, commitment) +} + func (m *MultiClient) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) { r, err := m.getClient(ctx) if err != nil { diff --git a/pkg/solana/config/config.go b/pkg/solana/config/config.go index f2a3a6352..28c16a3d0 100644 --- a/pkg/solana/config/config.go +++ b/pkg/solana/config/config.go @@ -56,6 +56,7 @@ type Workflow interface { PollPeriod() time.Duration GasLimitDefault() *uint64 TxAcceptanceState() *commontypes.TransactionStatus + RequestSizeLimit() uint32 Local() bool // shows if workflow is run against local network } @@ -77,6 +78,10 @@ type WorkflowConfig struct { Local *bool PollPeriod *config.Duration TxAcceptanceState *commontypes.TransactionStatus + // RequestSizeLimit caps the size in bytes of HTTP responses from Solana RPC for requests + // originated by workflow capabilities (external requests). Applied per request via + // commonhttp.WithResponseSizeLimit on the request context. Zero disables the cap. + RequestSizeLimit *uint32 } // IsEnabled reports whether workflow-style settings are configured: both AcceptanceTimeout and @@ -113,6 +118,9 @@ func (w *WorkflowConfig) SetFrom(f *WorkflowConfig) { if f.TxAcceptanceState != nil { w.TxAcceptanceState = f.TxAcceptanceState } + if f.RequestSizeLimit != nil { + w.RequestSizeLimit = f.RequestSizeLimit + } } type Chain struct { diff --git a/pkg/solana/config/docs.toml b/pkg/solana/config/docs.toml index f498c5f1b..c90ee4c38 100644 --- a/pkg/solana/config/docs.toml +++ b/pkg/solana/config/docs.toml @@ -119,6 +119,9 @@ Local = false # Default PollPeriod = '3s' # Default # TxAcceptanceState is the default acceptance state for writer DON tranmissions. TxAcceptanceState = 3 # Default +# RequestSizeLimit caps the size in bytes of HTTP responses from Solana RPC for requests originated +# by workflow capabilities (external requests). Set to 0 to disable the cap. +RequestSizeLimit = 0 # Default [[Nodes]] # Name is a unique (per-chain) identifier for this node. diff --git a/pkg/solana/config/mocks/config.go b/pkg/solana/config/mocks/config.go index bf08352b2..d7481190e 100644 --- a/pkg/solana/config/mocks/config.go +++ b/pkg/solana/config/mocks/config.go @@ -3,12 +3,11 @@ package mocks import ( - config "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - mock "github.com/stretchr/testify/mock" + time "time" rpc "github.com/gagliardetto/solana-go/rpc" - - time "time" + config "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" + mock "github.com/stretchr/testify/mock" ) // Config is an autogenerated mock type for the Config type diff --git a/pkg/solana/config/testdata/config-full.toml b/pkg/solana/config/testdata/config-full.toml index 8fb251826..f622420b2 100644 --- a/pkg/solana/config/testdata/config-full.toml +++ b/pkg/solana/config/testdata/config-full.toml @@ -36,6 +36,7 @@ GasLimitDefault = 3000000 Local = true PollPeriod = '9s' TxAcceptanceState = 3 +RequestSizeLimit = 1048576 [MultiNode] Enabled = false diff --git a/pkg/solana/config/toml.go b/pkg/solana/config/toml.go index 65ca6ccd0..710fdd45d 100644 --- a/pkg/solana/config/toml.go +++ b/pkg/solana/config/toml.go @@ -323,6 +323,12 @@ func (wc *workflowConfig) TxAcceptanceState() *types.TransactionStatus { func (wc *workflowConfig) Local() bool { return *wc.conf.Local } +func (wc *workflowConfig) RequestSizeLimit() uint32 { + if wc.conf.RequestSizeLimit == nil { + return 0 + } + return *wc.conf.RequestSizeLimit +} func (c *TOMLConfig) BlockTime() time.Duration { return c.Chain.BlockTime.Duration() diff --git a/pkg/solana/config/toml_test.go b/pkg/solana/config/toml_test.go index 8ac49be42..b4ee92183 100644 --- a/pkg/solana/config/toml_test.go +++ b/pkg/solana/config/toml_test.go @@ -66,6 +66,7 @@ var fullConfig = TOMLConfig{ Local: ptr(true), PollPeriod: config.MustNewDuration(9 * time.Second), TxAcceptanceState: ptr(types.Finalized), + RequestSizeLimit: ptr[uint32](1048576), }, MultiNode: mnCfg.MultiNodeConfig{ MultiNode: mnCfg.MultiNode{ diff --git a/pkg/solana/logpoller/filters.go b/pkg/solana/logpoller/filters.go index c32534f47..ce82b98fb 100644 --- a/pkg/solana/logpoller/filters.go +++ b/pkg/solana/logpoller/filters.go @@ -53,13 +53,31 @@ func newFilters(lggr logger.Logger, orm ORM, cpiEventExtractor *CPIEventExtracto } } -// IncrementSeqNum increments the sequence number for a filterID and returns the new -// number. This means the sequence number assigned to the first log matched after registration will be 1. -func (fl *filters) IncrementSeqNum(filterID int64) int64 { +// StageSeqNums assigns sequence numbers to logs from the current in-memory state +// without updating that state. CommitSeqNums must be called after a successful insert. +func (fl *filters) StageSeqNums(logs []types.Log) { fl.seqNumsMutex.Lock() defer fl.seqNumsMutex.Unlock() - fl.seqNums[filterID]++ - return fl.seqNums[filterID] + + pending := make(map[int64]int64) + for i := range logs { + filterID := logs[i].FilterID + pending[filterID]++ + logs[i].SequenceNum = fl.seqNums[filterID] + pending[filterID] + } +} + +// CommitSeqNums advances in-memory sequence numbers after logs are persisted. +func (fl *filters) CommitSeqNums(logs []types.Log) { + fl.seqNumsMutex.Lock() + defer fl.seqNumsMutex.Unlock() + + for i := range logs { + filterID := logs[i].FilterID + if logs[i].SequenceNum > fl.seqNums[filterID] { + fl.seqNums[filterID] = logs[i].SequenceNum + } + } } // PruneFilters - prunes all filters marked to be deleted from the database and all corresponding logs. @@ -165,8 +183,10 @@ func (fl *filters) RegisterFilter(ctx context.Context, filter types.Filter) erro defer fl.filtersMutex.Unlock() filter.IsBackfilled = false + // persist in memory existingFilter (if it exists) to wait to remove it from memory only if registration succeeds later. + var existingFilter *types.Filter if existingFilterID, ok := fl.filtersByName[filter.Name]; ok { - existingFilter := fl.filtersByID[existingFilterID] + existingFilter = fl.filtersByID[existingFilterID] if !existingFilter.MatchSameLogs(filter) { return ErrFilterNameConflict } @@ -179,14 +199,16 @@ func (fl *filters) RegisterFilter(ctx context.Context, filter types.Filter) erro filter.IsBackfilled = false } } - - fl.removeFilterFromIndexes(*existingFilter) } // ensure that the value of IncludeReverted isn't different from any other filters with the same address and event type if contractFilters, okAddr := fl.filtersByAddress[filter.Address]; okAddr { if similarFilters, okEv := contractFilters[filter.EventSig]; okEv { for id := range similarFilters { + // ignore existing filter so it doesn't conflict with itself + if existingFilter != nil && id == existingFilter.ID { + continue + } if conflicting := fl.filtersByID[id]; conflicting.IncludeReverted != filter.IncludeReverted { return fmt.Errorf("IncludeReverted=%v for filter %v conflicts with IncludeReverted=%v for filter %v", conflicting.IncludeReverted, conflicting, filter.IncludeReverted, filter) @@ -205,6 +227,11 @@ func (fl *filters) RegisterFilter(ctx context.Context, filter types.Filter) erro return fmt.Errorf("failed to insert filter: %w", err) } + // only remove existing filter from memory if registration succeeded + if existingFilter != nil { + fl.removeFilterFromIndexes(*existingFilter) + } + filter.ID = filterID fl.addToIndices(filter, decoder) @@ -295,6 +322,11 @@ func (fl *filters) UnregisterFilter(ctx context.Context, name string) error { fl.removeFilterFromIndexes(*filter) + // only update sequence numbers on Unregister so it doesn't reset to 0 when a filter gets updated. + fl.seqNumsMutex.Lock() + delete(fl.seqNums, filter.ID) + fl.seqNumsMutex.Unlock() + fl.filtersToDelete[filter.ID] = *filter return nil } @@ -305,9 +337,6 @@ func (fl *filters) removeFilterFromIndexes(filter types.Filter) { delete(fl.filtersByName, filter.Name) delete(fl.filtersToBackfill, filter.ID) delete(fl.filtersByID, filter.ID) - fl.seqNumsMutex.Lock() - delete(fl.seqNums, filter.ID) - fl.seqNumsMutex.Unlock() delete(fl.decoders, filter.ID) filtersForAddress, ok := fl.filtersByAddress[filter.Address] diff --git a/pkg/solana/logpoller/filters_test.go b/pkg/solana/logpoller/filters_test.go index 84a00effa..07e7724a9 100644 --- a/pkg/solana/logpoller/filters_test.go +++ b/pkg/solana/logpoller/filters_test.go @@ -9,6 +9,7 @@ import ( "strings" "sync" "testing" + "time" binary "github.com/gagliardetto/binary" "github.com/gagliardetto/solana-go" @@ -211,6 +212,34 @@ func TestFilters_RegisterFilter(t *testing.T) { err = fs.RegisterFilter(t.Context(), filter2) assert.NoError(t, err) }) + t.Run("Leaves in-memory state unchanged when re-register insert fails", func(t *testing.T) { + orm := mocks.NewMockORM(t) + fs := newFilters(lggr, orm, nil) + const filterName = "Filter" + addr := newRandomPublicKey(t) + registered := decoderReadyTestFilter(t, 100, filterName, "TestEvent", addr) + orm.On("SelectFilters", mock.Anything).Return(nil, nil).Once() + orm.On("SelectSeqNums", mock.Anything).Return(map[int64]int64{}, nil).Once() + const filterID = int64(1) + orm.On("InsertFilter", mock.Anything, mock.Anything).Return(filterID, nil).Once() + err := fs.RegisterFilter(t.Context(), registered) + require.NoError(t, err) + want := *fs.filtersByID[filterID] + requireIndexed(t, fs, want) + + updated := want + updated.StartingBlock = 200 + orm.On("InsertFilter", mock.Anything, mock.Anything).Return(int64(0), errors.New("failed to insert")).Once() + err = fs.RegisterFilter(t.Context(), updated) + require.EqualError(t, err, "failed to insert filter: failed to insert") + requireIndexed(t, fs, want) + + orm.On("InsertFilter", mock.Anything, mock.Anything).Return(filterID, nil).Once() + err = fs.RegisterFilter(t.Context(), updated) + require.NoError(t, err) + want.StartingBlock = 200 + requireIndexed(t, fs, want) + }) t.Run("Happy path", func(t *testing.T) { orm := mocks.NewMockORM(t) fs := newFilters(lggr, orm, nil) @@ -638,7 +667,54 @@ func TestFilters_ExtractField(t *testing.T) { } } -func TestFilters_IncrementSeqNum_Concurrent(t *testing.T) { +func TestFilters_RegisterFilter_PreservesSeqNumOnUpdate(t *testing.T) { + lggr := logger.Sugared(logger.Test(t)) + orm := mocks.NewMockORM(t) + fs := newFilters(lggr, orm, nil) + + const filterID = int64(1) + const filterName = "Filter" + addr := newRandomPublicKey(t) + filter := decoderReadyTestFilter(t, filterID, filterName, "TestEvent", addr) + + orm.On("SelectFilters", mock.Anything).Return([]types.Filter{filter}, nil).Once() + orm.On("SelectSeqNums", mock.Anything).Return(map[int64]int64{filterID: 42}, nil).Once() + require.NoError(t, fs.LoadFilters(t.Context())) + + filter.Retention = time.Hour + orm.On("InsertFilter", mock.Anything, mock.Anything).Return(filterID, nil).Once() + require.NoError(t, fs.RegisterFilter(t.Context(), filter)) + + logs := []types.Log{{FilterID: filterID}} + fs.StageSeqNums(logs) + require.Equal(t, int64(43), logs[0].SequenceNum) + fs.CommitSeqNums(logs) + require.Equal(t, int64(43), fs.seqNums[filterID]) +} + +func TestFilters_StageSeqNums_Commit(t *testing.T) { + fs := newFilters(logger.Sugared(logger.Test(t)), nil, nil) + fs.seqNums = map[int64]int64{1: 10, 2: 20} + + logs := []types.Log{ + {FilterID: 1}, + {FilterID: 1}, + {FilterID: 2}, + } + fs.StageSeqNums(logs) + + require.Equal(t, int64(11), logs[0].SequenceNum) + require.Equal(t, int64(12), logs[1].SequenceNum) + require.Equal(t, int64(21), logs[2].SequenceNum) + require.Equal(t, int64(10), fs.seqNums[1], "in-memory state unchanged before commit") + require.Equal(t, int64(20), fs.seqNums[2]) + + fs.CommitSeqNums(logs) + require.Equal(t, int64(12), fs.seqNums[1]) + require.Equal(t, int64(21), fs.seqNums[2]) +} + +func TestFilters_StageSeqNums_Commit_Concurrent(t *testing.T) { orm := mocks.NewMockORM(t) lggr := logger.Sugared(logger.Test(t)) fs := newFilters(lggr, orm, nil) @@ -660,14 +736,20 @@ func TestFilters_IncrementSeqNum_Concurrent(t *testing.T) { seqNumsFilter2 := make(chan int64, numGoroutines*incrementsPerGoroutine) var wg sync.WaitGroup + // prod code calls Process() sequentially, so for this concurrent test we lock around the stage/commit calls to simulate prod behavior. + var processMu sync.Mutex wg.Add(numGoroutines * 2) for range numGoroutines { go func() { defer wg.Done() for range incrementsPerGoroutine { - seqNum := fs.IncrementSeqNum(filter1.ID) - seqNumsFilter1 <- seqNum + logs := []types.Log{{FilterID: filter1.ID}} + processMu.Lock() + fs.StageSeqNums(logs) + fs.CommitSeqNums(logs) + processMu.Unlock() + seqNumsFilter1 <- logs[0].SequenceNum } }() } @@ -676,8 +758,12 @@ func TestFilters_IncrementSeqNum_Concurrent(t *testing.T) { go func() { defer wg.Done() for range incrementsPerGoroutine { - seqNum := fs.IncrementSeqNum(filter2.ID) - seqNumsFilter2 <- seqNum + logs := []types.Log{{FilterID: filter2.ID}} + processMu.Lock() + fs.StageSeqNums(logs) + fs.CommitSeqNums(logs) + processMu.Unlock() + seqNumsFilter2 <- logs[0].SequenceNum } }() } diff --git a/pkg/solana/logpoller/log_poller.go b/pkg/solana/logpoller/log_poller.go index 94cc00587..ef465af2c 100644 --- a/pkg/solana/logpoller/log_poller.go +++ b/pkg/solana/logpoller/log_poller.go @@ -60,7 +60,8 @@ type filtersI interface { UpdateStartingBlocks(startingBlocks int64) MatchingFiltersForEncodedEvent(event types.ProgramEvent) iter.Seq[types.Filter] DecodeSubKey(ctx context.Context, lggr logger.SugaredLogger, raw []byte, ID int64, subKeyPath []string) (any, error) - IncrementSeqNum(filterID int64) int64 + StageSeqNums(logs []types.Log) + CommitSeqNums(logs []types.Log) } type ReplayInfo struct { @@ -226,6 +227,7 @@ func (lp *Service) Process(ctx context.Context, programEvent types.ProgramEvent) } log.SubkeyValues = make([]types.IndexedValue, len(filter.SubkeyPaths)) + skipFilter := false for idx, path := range filter.SubkeyPaths { if len(path) == 0 { continue @@ -233,18 +235,27 @@ func (lp *Service) Process(ctx context.Context, programEvent types.ProgramEvent) subKeyVal, decodeSubKeyErr := lp.filters.DecodeSubKey(ctx, lp.lggr, log.Data, filter.ID, path) if decodeSubKeyErr != nil { - return decodeSubKeyErr + lp.lggr.Errorw("Failed to decode subkey", + "filterID", filter.ID, "filterName", filter.Name, "path", path, + "tx", programEvent.TransactionHash, "block", blockData.SlotNumber, "err", decodeSubKeyErr) + skipFilter = true + break } indexedVal, newIndexedValErr := types.NewIndexedValue(subKeyVal) if newIndexedValErr != nil { - return newIndexedValErr + lp.lggr.Errorw("Failed to index subkey", + "filterID", filter.ID, "filterName", filter.Name, "path", path, + "tx", programEvent.TransactionHash, "block", blockData.SlotNumber, "err", newIndexedValErr) + skipFilter = true + break } log.SubkeyValues[idx] = indexedVal } - - log.SequenceNum = lp.filters.IncrementSeqNum(filter.ID) + if skipFilter { + continue + } if filter.Retention > 0 { expiresAt := time.Now().Add(filter.Retention).UTC() @@ -259,7 +270,12 @@ func (lp *Service) Process(ctx context.Context, programEvent types.ProgramEvent) return nil } - return lp.orm.InsertLogs(ctx, logs) + lp.filters.StageSeqNums(logs) + if err := lp.orm.InsertLogs(ctx, logs); err != nil { + return err + } + lp.filters.CommitSeqNums(logs) + return nil } func (lp *Service) HasFilter(ctx context.Context, name string) bool { diff --git a/pkg/solana/logpoller/log_poller_test.go b/pkg/solana/logpoller/log_poller_test.go index 1857c278e..350da033b 100644 --- a/pkg/solana/logpoller/log_poller_test.go +++ b/pkg/solana/logpoller/log_poller_test.go @@ -671,7 +671,6 @@ func TestProcess(t *testing.T) { expectedLog.Address = addr expectedLog.LogIndex, err = makeLogIndex(txIndex, txLogIndex) require.NoError(t, err) - expectedLog.SequenceNum = 1 expectedLog.SubkeyValues = []types.IndexedValue{subKeyValA, subKeyValB} expectedLog.Data, err = bin.MarshalBorsh(&event) @@ -740,11 +739,42 @@ func TestProcess(t *testing.T) { err = lp.RegisterFilter(ctx, filter) require.NoError(t, err) + var nextSeqNum int64 + t.Run("accepts matching log", func(t *testing.T) { + nextSeqNum++ + want := expectedLog + want.SequenceNum = nextSeqNum + orm.EXPECT().InsertLogs(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, logs []types.Log) error { require.Len(t, logs, 1) - log := logs[0] - assert.Equal(t, expectedLog, log) + assert.Equal(t, want, logs[0]) + return nil + }).Once() + err = lp.Process(ctx, ev) + assert.NoError(t, err) + }) + + t.Run("does not advance sequence number when insert fails", func(t *testing.T) { + fl := lp.filters.(*filters) + + insertErr := errors.New("insert failed") + orm.EXPECT().InsertLogs(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, logs []types.Log) error { + require.Len(t, logs, 1) + assert.Equal(t, nextSeqNum+1, logs[0].SequenceNum, "insert should still receive the staged sequence number") + return insertErr + }).Once() + err = lp.Process(ctx, ev) + require.ErrorIs(t, err, insertErr) + assert.Equal(t, nextSeqNum, fl.seqNums[filterID], "in-memory counter must not advance after failed insert") + + nextSeqNum++ + want := expectedLog + want.SequenceNum = nextSeqNum + + orm.EXPECT().InsertLogs(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, logs []types.Log) error { + require.Len(t, logs, 1) + assert.Equal(t, want, logs[0]) return nil }).Once() err = lp.Process(ctx, ev) @@ -765,6 +795,8 @@ func TestProcess(t *testing.T) { log := logs[0] assert.Less(t, time.Until(*log.ExpiresAt), 30*time.Minute) // should be slightly less than 30 minutes from now assert.Greater(t, time.Until(*log.ExpiresAt), 29*time.Minute) + nextSeqNum++ + assert.Equal(t, nextSeqNum, log.SequenceNum) return nil }).Once() err = lp.Process(ctx, ev) @@ -791,13 +823,15 @@ func TestProcess(t *testing.T) { require.NoError(t, err) t.Run("accepts reverted log when IncludeReverted = true", func(t *testing.T) { - expectedLog.Error = new(string) - *expectedLog.Error = string(jsonErr) + nextSeqNum++ + want := expectedLog + want.SequenceNum = nextSeqNum + want.Error = new(string) + *want.Error = string(jsonErr) orm.EXPECT().InsertLogs(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, logs []types.Log) error { require.Len(t, logs, 1) - log := logs[0] - assert.Equal(t, expectedLog, log) + assert.Equal(t, want, logs[0]) return nil }).Once() @@ -819,6 +853,108 @@ func TestProcess(t *testing.T) { }) } +func TestProcess_skipsBadFilterWithoutBlockingOthers(t *testing.T) { + ctx := t.Context() + + addr := newRandomPublicKey(t) + eventName := "myEvent" + eventSig := types.NewEventSignatureFromName(eventName) + event := struct { + A int64 + B string + }{55, "hello"} + subKeyValA, err := types.NewIndexedValue(event.A) + require.NoError(t, err) + + goodFilterID := rand.Int63() + badFilterID := goodFilterID + 1 + + txIndex := int(rand.Int31()) + txLogIndex := uint(rand.Uint32()) + + expectedLog := newRandomLog(t, goodFilterID, chainID, eventName) + expectedLog.Address = addr + expectedLog.LogIndex, err = makeLogIndex(txIndex, txLogIndex) + require.NoError(t, err) + expectedLog.SubkeyValues = []types.IndexedValue{subKeyValA} + + expectedLog.Data, err = bin.MarshalBorsh(&event) + require.NoError(t, err) + expectedLog.Data = append(eventSig[:], expectedLog.Data...) + + ev := types.ProgramEvent{ + Program: addr.ToSolana().String(), + BlockData: types.BlockData{ + SlotNumber: uint64(expectedLog.BlockNumber), //nolint:gosec + BlockHash: expectedLog.BlockHash.ToSolana(), + BlockTime: solana.UnixTimeSeconds(expectedLog.BlockTimestamp.Unix()), + TransactionHash: expectedLog.TxHash.ToSolana(), + TransactionIndex: txIndex, + TransactionLogIndex: txLogIndex, + }, + Data: base64.StdEncoding.EncodeToString(expectedLog.Data), + } + + orm := mocks.NewMockORM(t) + cl := mocks.NewRPCClient(t) + lggr := logger.Sugared(logger.Test(t)) + lp, err := New(lggr, orm, cl, config.NewDefault(), chainID) + require.NoError(t, err) + + var idlTypeInt64 codecv1.IdlType + err = json.Unmarshal([]byte("\"i64\""), &idlTypeInt64) + require.NoError(t, err) + + idl := types.EventIdl{ + Event: codecv1.IdlEvent{ + Name: "myEvent", + Fields: []codecv1.IdlEventField{{ + Name: "A", + Type: idlTypeInt64, + }}, + }, + } + + goodFilter := types.Filter{ + Name: "good filter", + EventName: eventName, + Address: addr, + EventSig: eventSig, + EventIdl: idl, + SubkeyPaths: [][]string{{"A"}}, + } + badFilter := types.Filter{ + Name: "bad filter", + EventName: eventName, + Address: addr, + EventSig: eventSig, + EventIdl: idl, + SubkeyPaths: [][]string{{"MissingField"}}, + } + + orm.EXPECT().ChainID().Return(chainID).Maybe() + orm.EXPECT().SelectFilters(mock.Anything).Return([]types.Filter{}, nil).Once() + orm.EXPECT().SelectSeqNums(mock.Anything).Return(map[int64]int64{}, nil).Once() + orm.EXPECT().InsertFilter(mock.Anything, mock.MatchedBy(func(f types.Filter) bool { return f.Name == goodFilter.Name })). + RunAndReturn(func(ctx context.Context, f types.Filter) (int64, error) { return goodFilterID, nil }).Once() + orm.EXPECT().InsertFilter(mock.Anything, mock.MatchedBy(func(f types.Filter) bool { return f.Name == badFilter.Name })). + RunAndReturn(func(ctx context.Context, f types.Filter) (int64, error) { return badFilterID, nil }).Once() + + require.NoError(t, lp.RegisterFilter(ctx, goodFilter)) + require.NoError(t, lp.RegisterFilter(ctx, badFilter)) + + want := expectedLog + want.SequenceNum = 1 + + orm.EXPECT().InsertLogs(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, logs []types.Log) error { + require.Len(t, logs, 1) + assert.Equal(t, want, logs[0]) + return nil + }).Once() + + require.NoError(t, lp.Process(ctx, ev)) +} + func Test_LogPoller_Replay(t *testing.T) { t.Parallel() fromBlock := int64(5) diff --git a/pkg/solana/logpoller/mocks/mock_filters.go b/pkg/solana/logpoller/mocks/mock_filters.go index cdd6f9b97..bc03ad639 100644 --- a/pkg/solana/logpoller/mocks/mock_filters.go +++ b/pkg/solana/logpoller/mocks/mock_filters.go @@ -8,9 +8,8 @@ import ( logger "github.com/smartcontractkit/chainlink-common/pkg/logger" - mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/types" + mock "github.com/stretchr/testify/mock" ) // MockFilters is an autogenerated mock type for the filtersI type @@ -26,6 +25,39 @@ func (_m *MockFilters) EXPECT() *MockFilters_Expecter { return &MockFilters_Expecter{mock: &_m.Mock} } +// CommitSeqNums provides a mock function with given fields: logs +func (_m *MockFilters) CommitSeqNums(logs []types.Log) { + _m.Called(logs) +} + +// MockFilters_CommitSeqNums_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CommitSeqNums' +type MockFilters_CommitSeqNums_Call struct { + *mock.Call +} + +// CommitSeqNums is a helper method to define mock.On call +// - logs []types.Log +func (_e *MockFilters_Expecter) CommitSeqNums(logs interface{}) *MockFilters_CommitSeqNums_Call { + return &MockFilters_CommitSeqNums_Call{Call: _e.mock.On("CommitSeqNums", logs)} +} + +func (_c *MockFilters_CommitSeqNums_Call) Run(run func(logs []types.Log)) *MockFilters_CommitSeqNums_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]types.Log)) + }) + return _c +} + +func (_c *MockFilters_CommitSeqNums_Call) Return() *MockFilters_CommitSeqNums_Call { + _c.Call.Return() + return _c +} + +func (_c *MockFilters_CommitSeqNums_Call) RunAndReturn(run func([]types.Log)) *MockFilters_CommitSeqNums_Call { + _c.Run(run) + return _c +} + // DecodeSubKey provides a mock function with given fields: ctx, lggr, raw, ID, subKeyPath func (_m *MockFilters) DecodeSubKey(ctx context.Context, lggr logger.SugaredLogger, raw []byte, ID int64, subKeyPath []string) (interface{}, error) { ret := _m.Called(ctx, lggr, raw, ID, subKeyPath) @@ -309,52 +341,6 @@ func (_c *MockFilters_HasFilter_Call) RunAndReturn(run func(context.Context, str return _c } -// IncrementSeqNum provides a mock function with given fields: filterID -func (_m *MockFilters) IncrementSeqNum(filterID int64) int64 { - ret := _m.Called(filterID) - - if len(ret) == 0 { - panic("no return value specified for IncrementSeqNum") - } - - var r0 int64 - if rf, ok := ret.Get(0).(func(int64) int64); ok { - r0 = rf(filterID) - } else { - r0 = ret.Get(0).(int64) - } - - return r0 -} - -// MockFilters_IncrementSeqNum_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IncrementSeqNum' -type MockFilters_IncrementSeqNum_Call struct { - *mock.Call -} - -// IncrementSeqNum is a helper method to define mock.On call -// - filterID int64 -func (_e *MockFilters_Expecter) IncrementSeqNum(filterID interface{}) *MockFilters_IncrementSeqNum_Call { - return &MockFilters_IncrementSeqNum_Call{Call: _e.mock.On("IncrementSeqNum", filterID)} -} - -func (_c *MockFilters_IncrementSeqNum_Call) Run(run func(filterID int64)) *MockFilters_IncrementSeqNum_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int64)) - }) - return _c -} - -func (_c *MockFilters_IncrementSeqNum_Call) Return(_a0 int64) *MockFilters_IncrementSeqNum_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockFilters_IncrementSeqNum_Call) RunAndReturn(run func(int64) int64) *MockFilters_IncrementSeqNum_Call { - _c.Call.Return(run) - return _c -} - // LoadFilters provides a mock function with given fields: ctx func (_m *MockFilters) LoadFilters(ctx context.Context) error { ret := _m.Called(ctx) @@ -588,6 +574,39 @@ func (_c *MockFilters_RegisterFilter_Call) RunAndReturn(run func(context.Context return _c } +// StageSeqNums provides a mock function with given fields: logs +func (_m *MockFilters) StageSeqNums(logs []types.Log) { + _m.Called(logs) +} + +// MockFilters_StageSeqNums_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StageSeqNums' +type MockFilters_StageSeqNums_Call struct { + *mock.Call +} + +// StageSeqNums is a helper method to define mock.On call +// - logs []types.Log +func (_e *MockFilters_Expecter) StageSeqNums(logs interface{}) *MockFilters_StageSeqNums_Call { + return &MockFilters_StageSeqNums_Call{Call: _e.mock.On("StageSeqNums", logs)} +} + +func (_c *MockFilters_StageSeqNums_Call) Run(run func(logs []types.Log)) *MockFilters_StageSeqNums_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]types.Log)) + }) + return _c +} + +func (_c *MockFilters_StageSeqNums_Call) Return() *MockFilters_StageSeqNums_Call { + _c.Call.Return() + return _c +} + +func (_c *MockFilters_StageSeqNums_Call) RunAndReturn(run func([]types.Log)) *MockFilters_StageSeqNums_Call { + _c.Run(run) + return _c +} + // UnregisterFilter provides a mock function with given fields: ctx, name func (_m *MockFilters) UnregisterFilter(ctx context.Context, name string) error { ret := _m.Called(ctx, name) diff --git a/pkg/solana/logpoller/mocks/mock_logs_loader.go b/pkg/solana/logpoller/mocks/mock_logs_loader.go index 6179f643c..14882c919 100644 --- a/pkg/solana/logpoller/mocks/mock_logs_loader.go +++ b/pkg/solana/logpoller/mocks/mock_logs_loader.go @@ -5,9 +5,8 @@ package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" - types "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/types" + mock "github.com/stretchr/testify/mock" ) // MockLogsLoader is an autogenerated mock type for the logsLoader type diff --git a/pkg/solana/logpoller/mocks/mock_orm.go b/pkg/solana/logpoller/mocks/mock_orm.go index 3024d0028..f989858d5 100644 --- a/pkg/solana/logpoller/mocks/mock_orm.go +++ b/pkg/solana/logpoller/mocks/mock_orm.go @@ -5,11 +5,9 @@ package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" - query "github.com/smartcontractkit/chainlink-common/pkg/types/query" - types "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/types" + mock "github.com/stretchr/testify/mock" ) // MockORM is an autogenerated mock type for the ORM type diff --git a/pkg/solana/logpoller/mocks/rpc_client.go b/pkg/solana/logpoller/mocks/rpc_client.go index d59e803d6..3e1189f0f 100644 --- a/pkg/solana/logpoller/mocks/rpc_client.go +++ b/pkg/solana/logpoller/mocks/rpc_client.go @@ -5,11 +5,9 @@ package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" - - rpc "github.com/gagliardetto/solana-go/rpc" - solana "github.com/gagliardetto/solana-go" + rpc "github.com/gagliardetto/solana-go/rpc" + mock "github.com/stretchr/testify/mock" ) // RPCClient is an autogenerated mock type for the RPCClient type diff --git a/pkg/solana/logpoller/mocks/worker_group.go b/pkg/solana/logpoller/mocks/worker_group.go index bfe7dde31..cc51c2fdf 100644 --- a/pkg/solana/logpoller/mocks/worker_group.go +++ b/pkg/solana/logpoller/mocks/worker_group.go @@ -5,9 +5,8 @@ package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" - worker "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/worker" + mock "github.com/stretchr/testify/mock" ) // WorkerGroup is an autogenerated mock type for the WorkerGroup type diff --git a/pkg/solana/mocks/chain.go b/pkg/solana/mocks/chain.go index d4af0b967..4a47d72e3 100644 --- a/pkg/solana/mocks/chain.go +++ b/pkg/solana/mocks/chain.go @@ -3,20 +3,15 @@ package mocks import ( + context "context" big "math/big" + types "github.com/smartcontractkit/chainlink-common/pkg/types" + solana "github.com/smartcontractkit/chainlink-solana/pkg/solana" client "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" config "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - - context "context" - fees "github.com/smartcontractkit/chainlink-solana/pkg/solana/fees" - mock "github.com/stretchr/testify/mock" - - solana "github.com/smartcontractkit/chainlink-solana/pkg/solana" - - types "github.com/smartcontractkit/chainlink-common/pkg/types" ) // Chain is an autogenerated mock type for the Chain type diff --git a/pkg/solana/solana_service.go b/pkg/solana/solana_service.go index ba78e71a3..11e821eb2 100644 --- a/pkg/solana/solana_service.go +++ b/pkg/solana/solana_service.go @@ -12,6 +12,7 @@ import ( "github.com/gagliardetto/solana-go/rpc" "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-common/pkg/http" "github.com/smartcontractkit/chainlink-common/pkg/logger" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" commonsol "github.com/smartcontractkit/chainlink-common/pkg/types/chains/solana" @@ -50,9 +51,11 @@ func (ss *solanaService) GetBlock(ctx context.Context, req commonsol.GetBlockReq return nil, fmt.Errorf("failed to get reader: %w", err) } - result, err := reader.GetBlockWithOpts(ctx, req.Slot, &rpc.GetBlockOpts{ - Commitment: rpc.CommitmentType(req.Opts.Commitment), - }) + commitment := commonsol.CommitmentFinalized + if req.Opts != nil { + commitment = req.Opts.Commitment + } + result, err := reader.GetBlockWithOpts(ctx, req.Slot, client.HeadMetadataGetBlockOpts(rpc.CommitmentType(commitment))) if err != nil { return nil, fmt.Errorf("failed to get block: %w", err) } @@ -77,17 +80,24 @@ func (ss *solanaService) GetLatestLPBlock(ctx context.Context) (*commonsol.LPBlo } func (ss *solanaService) GetAccountInfoWithOpts(ctx context.Context, req commonsol.GetAccountInfoRequest) (*commonsol.GetAccountInfoReply, error) { + ctx = ss.wrapCtx(ctx, req.IsExternal) + reader, err := ss.chain.Reader() if err != nil { return nil, fmt.Errorf("failed to get reader: %w", err) } opts := convertAccountInfoOpts(req.Opts) + account, err := reader.GetAccountInfoWithOpts(ctx, solana.PublicKey(req.Account), opts) if err != nil { return nil, fmt.Errorf("failed to get account info: %w", err) } - return convertAccountResult(account, req.Opts.Encoding) + enc := commonsol.EncodingType("") + if req.Opts != nil { + enc = req.Opts.Encoding + } + return convertAccountResult(account, enc) } func (ss *solanaService) GetBalance(ctx context.Context, req commonsol.GetBalanceRequest) (*commonsol.GetBalanceReply, error) { @@ -102,29 +112,18 @@ func (ss *solanaService) GetBalance(ctx context.Context, req commonsol.GetBalanc } return &commonsol.GetBalanceReply{ - Value: balance, + Value: balance.Value, + Slot: balance.Context.Slot, }, nil } func (ss *solanaService) SimulateTX(ctx context.Context, req commonsol.SimulateTXRequest) (*commonsol.SimulateTXReply, error) { + ctx = ss.wrapCtx(ctx, req.IsExternal) tx, err := solana.TransactionFromBase64(req.EncodedTransaction) if err != nil { return nil, fmt.Errorf("failed to decode transaction: %w", err) } - accounts := &rpc.SimulateTransactionAccountsOpts{ - Encoding: solana.EncodingType(req.Opts.Accounts.Encoding), - Addresses: make([]solana.PublicKey, 0, len(req.Opts.Accounts.Addresses)), - } - for _, addr := range req.Opts.Accounts.Addresses { - accounts.Addresses = append(accounts.Addresses, solana.PublicKey(addr)) - } - - res, err := ss.chain.MultiClient().SimulateTx(ctx, tx, &rpc.SimulateTransactionOpts{ - SigVerify: req.Opts.SigVerify, - Commitment: rpc.CommitmentType(req.Opts.Commitment), - ReplaceRecentBlockhash: req.Opts.ReplaceRecentBlockhash, - Accounts: accounts, - }) + res, err := ss.chain.MultiClient().SimulateTx(ctx, tx, convertSimulateTXOpts(req.Opts)) if err != nil { return nil, fmt.Errorf("simulate tx failed: %w", err) } @@ -435,8 +434,9 @@ func (ss *solanaService) getPublicKeyWithHighestLamports(ctx context.Context, r ss.logger.Warnw("failed to get balance for account, skipping", "account", acct, "err", err) continue } - if !haveAnyBalance || balance > highestLamports { - highestLamports = balance + val := balance.Value + if !haveAnyBalance || val > highestLamports { + highestLamports = val selected = pk haveAnyBalance = true } @@ -459,6 +459,7 @@ func (ss *solanaService) getPublicKeyWithHighestLamports(ctx context.Context, r } func (ss *solanaService) GetMultipleAccountsWithOpts(ctx context.Context, req commonsol.GetMultipleAccountsRequest) (*commonsol.GetMultipleAccountsReply, error) { + ctx = ss.wrapCtx(ctx, req.IsExternal) r, err := ss.chain.Reader() if err != nil { return nil, fmt.Errorf("failed to get reader: %w", err) @@ -510,7 +511,77 @@ func (ss *solanaService) GetMultipleAccountsWithOpts(ctx context.Context, req co }, nil } +func convertProgramAccountsOpts(opts *commonsol.GetProgramAccountsOpts) (*rpc.GetProgramAccountsOpts, commonsol.EncodingType) { + if opts == nil { + return nil, "" + } + var ds *rpc.DataSlice + if opts.DataSlice != nil { + ds = &rpc.DataSlice{ + Offset: opts.DataSlice.Offset, + Length: opts.DataSlice.Length, + } + } + return &rpc.GetProgramAccountsOpts{ + Encoding: solana.EncodingType(opts.Encoding), + Commitment: rpc.CommitmentType(opts.Commitment), + DataSlice: ds, + Filters: convertRPCFilters(opts.Filters), + }, opts.Encoding +} + +func convertRPCFilters(filters []commonsol.RPCFilter) []rpc.RPCFilter { + if len(filters) == 0 { + return nil + } + out := make([]rpc.RPCFilter, 0, len(filters)) + for _, f := range filters { + var memcmp *rpc.RPCFilterMemcmp + if f.Memcmp != nil { + memcmp = &rpc.RPCFilterMemcmp{ + Offset: f.Memcmp.Offset, + Bytes: solana.Base58(f.Memcmp.Bytes), + } + } + out = append(out, rpc.RPCFilter{ + Memcmp: memcmp, + DataSize: f.DataSize, + }) + } + return out +} + +func convertProgramAccountsReply(res rpc.GetProgramAccountsResult, enc commonsol.EncodingType) (*commonsol.GetProgramAccountsReply, error) { + accounts := make([]*commonsol.KeyedAccount, 0, len(res)) + for _, ka := range res { + if ka == nil { + continue + } + var acc *commonsol.Account + if ka.Account != nil { + data, err := convertDataBytesOrJSON(ka.Account.Data, enc) + if err != nil { + return nil, fmt.Errorf("conversion data bytes or json failed: %w", err) + } + acc = &commonsol.Account{ + Lamports: ka.Account.Lamports, + Owner: commonsol.PublicKey(ka.Account.Owner), + Data: data, + Executable: ka.Account.Executable, + RentEpoch: ka.Account.RentEpoch, + Space: ka.Account.Space, + } + } + accounts = append(accounts, &commonsol.KeyedAccount{ + Pubkey: commonsol.PublicKey(ka.Pubkey), + Account: acc, + }) + } + return &commonsol.GetProgramAccountsReply{Value: accounts}, nil +} + func (ss *solanaService) GetTransaction(ctx context.Context, req commonsol.GetTransactionRequest) (*commonsol.GetTransactionReply, error) { + ctx = ss.wrapCtx(ctx, req.IsExternal) r, err := ss.chain.Reader() if err != nil { return nil, fmt.Errorf("failed to get reader: %w", err) @@ -540,16 +611,42 @@ func (ss *solanaService) GetTransaction(ctx context.Context, req commonsol.GetTr } func (ss *solanaService) GetFeeForMessage(ctx context.Context, req commonsol.GetFeeForMessageRequest) (*commonsol.GetFeeForMessageReply, error) { - fee, err := ss.chain.MultiClient().GetFeeForMessage(ctx, req.Message) + res, err := ss.chain.MultiClient().GetFeeForMessageWithCommitment(ctx, req.Message, rpc.CommitmentType(req.Commitment)) if err != nil { return nil, fmt.Errorf("failed to get fee for message: %w", err) } return &commonsol.GetFeeForMessageReply{ - Fee: fee, + Fee: *res.Value, + Slot: res.Context.Slot, }, nil } +func (ss *solanaService) GetProgramAccounts(ctx context.Context, req commonsol.GetProgramAccountsRequest) (*commonsol.GetProgramAccountsReply, error) { + ctx = ss.wrapCtx(ctx, req.IsExternal) + + r, err := ss.chain.Reader() + if err != nil { + return nil, fmt.Errorf("failed to get reader: %w", err) + } + + opts, enc := convertProgramAccountsOpts(req.Opts) + res, err := r.GetProgramAccountsWithOpts(ctx, solana.PublicKey(req.Program), opts) + if err != nil { + return nil, fmt.Errorf("failed to get program accounts: %w", err) + } + + return convertProgramAccountsReply(res, enc) +} + +func (ss *solanaService) wrapCtx(ctx context.Context, isExternal bool) context.Context { + if isExternal { + ctx = http.WithResponseSizeLimit(ctx, ss.chain.Config().WF().RequestSizeLimit()) + } + + return ctx +} + // converters func convertTransactionEnvelope(tx *rpc.GetTransactionResult) (*commonsol.TransactionResultEnvelope, error) { if tx == nil || tx.Transaction == nil { @@ -850,7 +947,35 @@ func convertAccountResult(acc *rpc.GetAccountInfoResult, enc commonsol.EncodingT }, nil } +func convertSimulateTXOpts(opts *commonsol.SimulateTXOpts) *rpc.SimulateTransactionOpts { + commitment := rpc.CommitmentFinalized + if opts != nil { + commitment = rpc.CommitmentType(opts.Commitment) + } + out := &rpc.SimulateTransactionOpts{ + Commitment: commitment, + } + if opts == nil { + return out + } + out.SigVerify = opts.SigVerify + out.ReplaceRecentBlockhash = opts.ReplaceRecentBlockhash + if opts.Accounts != nil { + out.Accounts = &rpc.SimulateTransactionAccountsOpts{ + Encoding: solana.EncodingType(opts.Accounts.Encoding), + Addresses: make([]solana.PublicKey, 0, len(opts.Accounts.Addresses)), + } + for _, addr := range opts.Accounts.Addresses { + out.Accounts.Addresses = append(out.Accounts.Addresses, solana.PublicKey(addr)) + } + } + return out +} + func convertAccountInfoOpts(opts *commonsol.GetAccountInfoOpts) *rpc.GetAccountInfoOpts { + if opts == nil { + return nil + } var ds *rpc.DataSlice if opts.DataSlice != nil { ds = &rpc.DataSlice{} diff --git a/pkg/solana/solana_service_test.go b/pkg/solana/solana_service_test.go index 0066235bc..a56e5b697 100644 --- a/pkg/solana/solana_service_test.go +++ b/pkg/solana/solana_service_test.go @@ -284,6 +284,77 @@ func Test_Converters(t *testing.T) { require.Equal(t, tx.Message.Header.NumReadonlyUnsignedAccounts, got.Message.Header.NumReadonlyUnsignedAccounts) require.Equal(t, tx.Message.Header.NumRequiredSignatures, got.Message.Header.NumRequiredSignatures) }) + + t.Run("convertSimulateTXOpts_nil", func(t *testing.T) { + opts := convertSimulateTXOpts(nil) + require.NotNil(t, opts) + require.Equal(t, rpc.CommitmentFinalized, opts.Commitment) + require.Nil(t, opts.Accounts) + }) + + t.Run("convertAccountInfoOpts_nil", func(t *testing.T) { + require.Nil(t, convertAccountInfoOpts(nil)) + }) + + t.Run("convertProgramAccountsOpts_nil", func(t *testing.T) { + opts, enc := convertProgramAccountsOpts(nil) + require.Nil(t, opts) + require.Equal(t, commonsol.EncodingType(""), enc) + }) + + t.Run("convertProgramAccountsOpts_full", func(t *testing.T) { + offset := uint64(13) + length := uint64(30) + filterKey := pk(7) + opts, enc := convertProgramAccountsOpts(&commonsol.GetProgramAccountsOpts{ + Encoding: commonsol.EncodingBase64, + Commitment: commonsol.CommitmentConfirmed, + DataSlice: &commonsol.DataSlice{Offset: &offset, Length: &length}, + Filters: []commonsol.RPCFilter{ + {DataSize: 165}, + {Memcmp: &commonsol.RPCFilterMemcmp{Offset: 0, Bytes: filterKey[:]}}, + }, + }) + require.Equal(t, commonsol.EncodingBase64, enc) + require.NotNil(t, opts) + require.Equal(t, solanago.EncodingBase64, opts.Encoding) + require.Equal(t, rpc.CommitmentConfirmed, opts.Commitment) + require.NotNil(t, opts.DataSlice) + require.Equal(t, &offset, opts.DataSlice.Offset) + require.Equal(t, &length, opts.DataSlice.Length) + require.Len(t, opts.Filters, 2) + require.Equal(t, uint64(165), opts.Filters[0].DataSize) + require.NotNil(t, opts.Filters[1].Memcmp) + require.Equal(t, uint64(0), opts.Filters[1].Memcmp.Offset) + require.Equal(t, solanago.Base58(filterKey[:]), opts.Filters[1].Memcmp.Bytes) + }) + + t.Run("convertRPCFilters_empty", func(t *testing.T) { + require.Nil(t, convertRPCFilters(nil)) + }) + + t.Run("convertProgramAccountsReply", func(t *testing.T) { + data := rpc.DataBytesOrJSONFromBytes([]byte{0xca, 0xfe}) + got, err := convertProgramAccountsReply(rpc.GetProgramAccountsResult{ + { + Pubkey: pk(3), + Account: &rpc.Account{ + Lamports: 500, + Owner: pk(4), + Data: data, + Executable: false, + Space: 32, + }, + }, + nil, + }, commonsol.EncodingBase64) + require.NoError(t, err) + require.Len(t, got.Value, 1) + require.Equal(t, cpk(3), got.Value[0].Pubkey) + require.Equal(t, uint64(500), got.Value[0].Account.Lamports) + require.Equal(t, cpk(4), got.Value[0].Account.Owner) + require.Equal(t, []byte{0xca, 0xfe}, got.Value[0].Account.Data.AsDecodedBinary) + }) } func Test_getPublicKeyWithHighestLamports(t *testing.T) { @@ -305,8 +376,8 @@ func Test_getPublicKeyWithHighestLamports(t *testing.T) { require.NoError(t, err) mockR := clientmocks.NewReaderWriter(t) - mockR.On("BalanceWithCommitment", mock.Anything, kLow.PublicKey(), rpc.CommitmentConfirmed).Return(uint64(100), nil).Once() - mockR.On("BalanceWithCommitment", mock.Anything, kHigh.PublicKey(), rpc.CommitmentConfirmed).Return(uint64(9000), nil).Once() + mockR.On("BalanceWithCommitment", mock.Anything, kLow.PublicKey(), rpc.CommitmentConfirmed).Return(&rpc.GetBalanceResult{Value: 100}, nil).Once() + mockR.On("BalanceWithCommitment", mock.Anything, kHigh.PublicKey(), rpc.CommitmentConfirmed).Return(&rpc.GetBalanceResult{Value: 9000}, nil).Once() got, err := ss.getPublicKeyWithHighestLamports(ctx, mockR, []string{kLow.PublicKey().String(), kHigh.PublicKey().String()}) require.NoError(t, err) @@ -320,7 +391,7 @@ func Test_getPublicKeyWithHighestLamports(t *testing.T) { require.NoError(t, err) mockR := clientmocks.NewReaderWriter(t) - mockR.On("BalanceWithCommitment", mock.Anything, mock.Anything, rpc.CommitmentConfirmed).Return(uint64(0), errors.New("rpc down")).Twice() + mockR.On("BalanceWithCommitment", mock.Anything, mock.Anything, rpc.CommitmentConfirmed).Return((*rpc.GetBalanceResult)(nil), errors.New("rpc down")).Twice() got, err := ss.getPublicKeyWithHighestLamports(ctx, mockR, []string{k0.PublicKey().String(), k1.PublicKey().String()}) require.NoError(t, err) @@ -386,6 +457,7 @@ func (w *stubWorkflow) ForwarderState() *solanago.PublicKey { retu func (w *stubWorkflow) GasLimitDefault() *uint64 { return nil } func (w *stubWorkflow) TxAcceptanceState() *commontypes.TransactionStatus { return nil } func (w *stubWorkflow) Local() bool { return false } +func (w *stubWorkflow) RequestSizeLimit() uint32 { return 0 } type stubTxManager struct { mock.Mock @@ -778,6 +850,112 @@ func TestSubmitTransaction_NilCfg(t *testing.T) { assert.Nil(t, capturedCfgs, "no tx configs should be set when Cfg is nil") } +func newGetProgramAccountsTestHarness(t *testing.T) (*solanaService, *clientmocks.ReaderWriter) { + t.Helper() + + mockReader := clientmocks.NewReaderWriter(t) + mockCfg := configmocks.NewConfig(t) + mockCfg.EXPECT().WF().Return(&stubWorkflow{}).Maybe() + + chain := &submitStubChain{ + reader: mockReader, + cfg: mockCfg, + } + + return &solanaService{ + chain: chain, + logger: logger.Nop(), + }, mockReader +} + +func TestGetProgramAccounts(t *testing.T) { + ctx := t.Context() + program := cpk(9) + + t.Run("success with opts", func(t *testing.T) { + ss, mockReader := newGetProgramAccountsTestHarness(t) + offset := uint64(0) + length := uint64(32) + req := commonsol.GetProgramAccountsRequest{ + Program: program, + Opts: &commonsol.GetProgramAccountsOpts{ + Encoding: commonsol.EncodingBase64, + Commitment: commonsol.CommitmentConfirmed, + DataSlice: &commonsol.DataSlice{Offset: &offset, Length: &length}, + Filters: []commonsol.RPCFilter{{DataSize: 165}}, + }, + } + + rpcResult := rpc.GetProgramAccountsResult{ + { + Pubkey: pk(1), + Account: &rpc.Account{ + Lamports: 1000, + Owner: solanago.PublicKey(program), + Data: rpc.DataBytesOrJSONFromBytes([]byte{0x01, 0x02}), + Space: 165, + }, + }, + } + mockReader.EXPECT(). + GetProgramAccountsWithOpts(mock.Anything, solanago.PublicKey(program), mock.MatchedBy(func(opts *rpc.GetProgramAccountsOpts) bool { + return opts != nil && + opts.Encoding == solanago.EncodingBase64 && + opts.Commitment == rpc.CommitmentConfirmed && + opts.DataSlice != nil && + *opts.DataSlice.Offset == offset && + *opts.DataSlice.Length == length && + len(opts.Filters) == 1 && + opts.Filters[0].DataSize == 165 + })). + Return(rpcResult, nil) + + reply, err := ss.GetProgramAccounts(ctx, req) + require.NoError(t, err) + require.Len(t, reply.Value, 1) + require.Equal(t, cpk(1), reply.Value[0].Pubkey) + require.Equal(t, uint64(1000), reply.Value[0].Account.Lamports) + require.Equal(t, program, reply.Value[0].Account.Owner) + require.Equal(t, []byte{0x01, 0x02}, reply.Value[0].Account.Data.AsDecodedBinary) + }) + + t.Run("success with nil opts", func(t *testing.T) { + ss, mockReader := newGetProgramAccountsTestHarness(t) + req := commonsol.GetProgramAccountsRequest{Program: program} + + mockReader.EXPECT(). + GetProgramAccountsWithOpts(mock.Anything, solanago.PublicKey(program), (*rpc.GetProgramAccountsOpts)(nil)). + Return(rpc.GetProgramAccountsResult{}, nil) + + reply, err := ss.GetProgramAccounts(ctx, req) + require.NoError(t, err) + require.Empty(t, reply.Value) + }) + + t.Run("reader error", func(t *testing.T) { + ss, mockReader := newGetProgramAccountsTestHarness(t) + req := commonsol.GetProgramAccountsRequest{Program: program} + + mockReader.EXPECT(). + GetProgramAccountsWithOpts(mock.Anything, solanago.PublicKey(program), (*rpc.GetProgramAccountsOpts)(nil)). + Return(rpc.GetProgramAccountsResult(nil), errors.New("rpc unavailable")) + + _, err := ss.GetProgramAccounts(ctx, req) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to get program accounts") + assert.Contains(t, err.Error(), "rpc unavailable") + }) + + t.Run("chain reader error", func(t *testing.T) { + ss := &solanaService{ + chain: &submitStubChain{readerErr: errors.New("no reader")}, + } + _, err := ss.GetProgramAccounts(ctx, commonsol.GetProgramAccountsRequest{Program: program}) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to get reader") + }) +} + // mockLogPoller is a minimal LogPoller implementation for testing readiness guards. type mockLogPoller struct { ready error diff --git a/pkg/solana/txm/mocks/tx_manager.go b/pkg/solana/txm/mocks/tx_manager.go index 82a8eefaa..b0c8a47ab 100644 --- a/pkg/solana/txm/mocks/tx_manager.go +++ b/pkg/solana/txm/mocks/tx_manager.go @@ -9,7 +9,6 @@ import ( mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink-common/pkg/types" - utils "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/utils" )