diff --git a/go.mod b/go.mod index 0c40542b44..8c095999ab 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f - github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3 + github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260303123527-79f0a3119973 github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e github.com/smartcontractkit/libocr v0.0.0-20260130195252-6e18e2a30acc diff --git a/go.sum b/go.sum index f41b6faeb7..7efbfa99d2 100644 --- a/go.sum +++ b/go.sum @@ -670,7 +670,6 @@ github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260401162955-be2bc6b5264b/go.mod h1:HG/aei0MgBOpsyRLexdKGtOUO8yjSJO3iUu0Uu8KBm4= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a h1:PsFckZp3Dhb5pVc0Xccj1lvnOEg0H3eQdjtZgnCKd+4= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a/go.mod h1:7ketk4ischPQW/JQgmyHz6zdzLUJv1VC29SiSgosydQ= - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= @@ -679,6 +678,8 @@ github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626 github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3 h1:X8Pekpv+cy0eW1laZTwATuYLTLZ6gRTxz1ZWOMtU74o= github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= +github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260303123527-79f0a3119973 h1:/YE1NoEpLWZTQd98rLlTPo6WX0KgWiJkcOhLXmId39c= +github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260303123527-79f0a3119973/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 h1:7bxYNrPpygn8PUSBiEKn8riMd7CXMi/4bjTy0fHhcrY= github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335/go.mod h1:ccjEgNeqOO+bjPddnL4lUrNLzyCvGCxgBjJdhFX3wa8= github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20250528121202-292529af39df h1:36e3ROIZyV/qE8SvFOACXtXfMOMd9vG4+zY2v2ScXkI= diff --git a/pkg/txm/metrics.go b/pkg/txm/metrics.go index 97dfe9c851..fc246451b0 100644 --- a/pkg/txm/metrics.go +++ b/pkg/txm/metrics.go @@ -210,14 +210,20 @@ func (m *txmMetrics) EmitTxMessage(ctx context.Context, txHash common.Hash, from toAddress = tx.ToAddress } + var dualBroadcastParams *string + if meta != nil && meta.DualBroadcast != nil && *meta.DualBroadcast { + dualBroadcastParams = meta.DualBroadcastParams + } + message := &svrv1.TxMessage{ - Hash: txHash.String(), - FromAddress: fromAddress.String(), - ToAddress: toAddress.String(), - Nonce: strconv.FormatUint(*tx.Nonce, 10), - CreatedAt: time.Now().UnixMicro(), - ChainId: m.chainID.String(), - FeedAddress: destAddress, + Hash: txHash.String(), + FromAddress: fromAddress.String(), + ToAddress: toAddress.String(), + Nonce: strconv.FormatUint(*tx.Nonce, 10), + CreatedAt: time.Now().UnixMicro(), + ChainId: m.chainID.String(), + FeedAddress: destAddress, + DualBroadcastParams: dualBroadcastParams, } messageBytes, err := proto.Marshal(message) diff --git a/pkg/txm/metrics_test.go b/pkg/txm/metrics_test.go index 1397b5cfa2..8234f7024e 100644 --- a/pkg/txm/metrics_test.go +++ b/pkg/txm/metrics_test.go @@ -1,6 +1,7 @@ package txm import ( + "encoding/json" "strconv" "testing" @@ -11,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/beholder/beholdertest" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-evm/pkg/testutils" "github.com/smartcontractkit/chainlink-evm/pkg/txm/types" svrv1 "github.com/smartcontractkit/chainlink-protos/svr/v1" @@ -116,6 +118,85 @@ func TestEmitTxMessage(t *testing.T) { assert.Equal(t, expectedChain.String(), actualMessage.ChainId) assert.Equal(t, "", actualMessage.FeedAddress) }) + + t.Run("populates dual_broadcast_params when tx is a dual-broadcast secondary tx", func(t *testing.T) { + // GIVEN + ctx := t.Context() + beholderTester := beholdertest.NewObserver(t) + + toAddress := testutils.NewAddress() + fromAddress := testutils.NewAddress() + expectedNonce := uint64(7) + expectedChain := testutils.FixtureChainID + expectedParams := "hint=calldata&hint=logs&builder=flashbots" + isDualBroadcast := true + + metaBytes, err := json.Marshal(types.TxMeta{ + DualBroadcast: &isDualBroadcast, + DualBroadcastParams: &expectedParams, + }) + require.NoError(t, err) + meta := sqlutil.JSON(metaBytes) + + txmMetrics := NewTxmMetrics(logger.Test(t), expectedChain) + + tx := &types.Transaction{ + IsPurgeable: false, + FromAddress: fromAddress, + ToAddress: toAddress, + Nonce: &expectedNonce, + Meta: &meta, + } + + // WHEN + err = txmMetrics.EmitTxMessage(ctx, common.Hash{}, fromAddress, tx) + require.NoError(t, err) + + // THEN + messages := beholderTester.Messages(t) + assert.Len(t, messages, 1) + + var actualMessage svrv1.TxMessage + err = proto.Unmarshal(messages[0].Body, &actualMessage) + require.NoError(t, err) + + require.NotNil(t, actualMessage.DualBroadcastParams) + assert.Equal(t, expectedParams, *actualMessage.DualBroadcastParams) + }) + + t.Run("does not set dual_broadcast_params for a primary (non-dual-broadcast) tx", func(t *testing.T) { + // GIVEN + ctx := t.Context() + beholderTester := beholdertest.NewObserver(t) + + toAddress := testutils.NewAddress() + fromAddress := testutils.NewAddress() + expectedNonce := uint64(3) + expectedChain := testutils.FixtureChainID + + txmMetrics := NewTxmMetrics(logger.Test(t), expectedChain) + + tx := &types.Transaction{ + IsPurgeable: false, + FromAddress: fromAddress, + ToAddress: toAddress, + Nonce: &expectedNonce, + } + + // WHEN + err := txmMetrics.EmitTxMessage(ctx, common.Hash{}, fromAddress, tx) + require.NoError(t, err) + + // THEN + messages := beholderTester.Messages(t) + assert.Len(t, messages, 1) + + var actualMessage svrv1.TxMessage + err = proto.Unmarshal(messages[0].Body, &actualMessage) + require.NoError(t, err) + + assert.Nil(t, actualMessage.DualBroadcastParams) + }) } func TestReachedMaxAttempts(t *testing.T) {