Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pkg/txm/clientwrappers/dualbroadcast/meta_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ func (a *MetaClient) SendTransaction(ctx context.Context, tx *types.Transaction,
// #2
if !tx.IsPurgeable && tx.AttemptCount > 1 && len(tx.Attempts) > 0 {
first := tx.Attempts[0]
// The first attempt is the only one signed with the auction's metacall payload. If it was pruned
// from the store, the remaining attempts carry the raw payload, which must not reach the public
// mempool, so refuse to rebroadcast. Ideally, the transaction will be purged by the stuck transaction
// detector before this condition is met, but even if it doesn't, eventually it will still be purged and
// the error will resolve.
if first.ID != 0 {
return fmt.Errorf("first attempt for transactionID(%d) was pruned, refusing to rebroadcast attemptID(%d)", tx.ID, first.ID)
}
if first.SignedTransaction != nil {
a.lggr.Infow("Intercepted attempt for tx(rebroadcasting first attempt)", "txID", tx.ID, "attempt", first)
return a.c.SendTransaction(ctx, nil, first)
Expand Down
25 changes: 25 additions & 0 deletions pkg/txm/clientwrappers/dualbroadcast/meta_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,40 @@ package dualbroadcast_test
import (
"encoding/hex"
"encoding/json"
"math/big"
"net/url"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

"github.com/smartcontractkit/chainlink-evm/pkg/txm"
"github.com/smartcontractkit/chainlink-evm/pkg/txm/clientwrappers/dualbroadcast"
"github.com/smartcontractkit/chainlink-evm/pkg/txm/types"
)

func TestMetaClient_SendTransaction_RefusesPrunedFirstAttempt(t *testing.T) {
customURL, err := url.Parse("https://test.url")
require.NoError(t, err)
client, err := dualbroadcast.NewMetaClient(logger.Test(t), nil, nil, customURL, big.NewInt(1337), nil, nil, txm.NewNoopTxmMetrics())
require.NoError(t, err)

nonce := uint64(0)
tx := &types.Transaction{
ID: 1,
Nonce: &nonce,
AttemptCount: 11,
// The original first attempt (ID 0) was pruned from the store; the oldest remaining attempt
// carries the raw payload and must not be rebroadcast.
Attempts: []*types.Attempt{{ID: 1, TxID: 1}},
}
err = client.SendTransaction(t.Context(), tx, tx.Attempts[0])
require.ErrorContains(t, err, "was pruned")
}

func TestMetaClient_VerifyResponse(t *testing.T) {
responseData := []byte(`{"jsonrpc":"2.0","result":{"userOperation":{"from":"0xb6065f79d99f29c3eda0ed1bda7ff88e7ee12f1e","to":"0x1b4cb47622705f0f67b6b18bbd1aa1a91fc77d37","value":"0x0","gas":"0x186a00","maxFeePerGas":"0x3b9aca00","nonce":"0xf","deadline":"0x9c834e6","dapp":"0xc38d38333687ea295753c214744e839eddc7aebb","control":"0xc38d38333687ea295753c214744e839eddc7aebb","callConfig":"0x2304","dappGasLimit":"0x1e8480","solverGasLimit":"0x5b8d80","bundlerSurchargeRate":"0x0","sessionKey":"0x0000000000000000000000000000000000000000","data":"0x02a688ed0000000000000000000000008ae79bb7cce2dc3d132c288971b0f74af02a3b4a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003646fadcf72000000000000000000000000b123c2e3a71b57f9678cf6212576f30d642ed89a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002e4ba0cb29e0001aeec9ec2ddb59123858e897b26f52e2173aca2c577dcce62e7ddc70f16020000000000000000000000000000000000000000000000000000000000418a059c756341541f2283d4f124ac39dc9e718f96453582f38acfa885e4ffaf26eb7800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000678010b601000203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000075542db800000000000000000000000000000000000000000000000000000000755c8e4000000000000000000000000000000000000000000000000000000000756106c80000000000000000000000000000000000000000000000000000000075961a520000000000000000000000000000000000000000000000000000000000000002b974b422c8e712d3320994bf4ecd31e37b35a117ef4102285206c45aef4b8709ae407e7a604410ef1e622ebdb4ad302638ff0cf49ad5ab33486c206bf8ecd7dd0000000000000000000000000000000000000000000000000000000000000002671dd95393e5963a3842a5f95d5e6b544de4906b1c304d41aebbb7c2acf9cb065fb96b17223872656de8f05a17ffb6ccc3261b606179cc33db445158aa408b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","signature":"0xb6ae5c173d3c7577ea3b8b4d35a0dc33e0f2798d74173c5e6fee2f08b8ce20271287a87443e778a114890140a08be5faf05ebcdd59051f9747fdd35d0afe6aa01b"},"solverOperations":[{"from":"0x377136653944bdd5d9f0db22987b7432e76c354f","to":"0x1b4cb47622705f0f67b6b18bbd1aa1a91fc77d37","value":"0x0","gas":"0x30d40","maxFeePerGas":"0x3b9aca00","deadline":"0x9c834e6","solver":"0x4b548c6faf4a3c74571c3e194e71cbf2a5172501","control":"0xc38d38333687ea295753c214744e839eddc7aebb","userOpHash":"0x0648e7c2a3b705562efd0e06adb8a63916ba5a06ee92a8544369a431298bce47","bidToken":"0x0000000000000000000000000000000000000000","bidAmount":"0x186a0","data":"0xc000a702000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000326a27250470f3a518db1334faaa277f8282082d7f54fd9b0f6cfff8f403a74fcb27a12a3860a1146cf7306eb49aa9fa03ccb10000000000000000000000000000","signature":"0x91537f835005fcd243b52b7b6436df810a1ea0b18769b2b1417ee9dacc9f9dac309a8b9ef82d82d6572e5feeb7209d12739067afd315434001a2aadd35af77701c"}],"dAppOperation":{"from":"0x1f3c5ec2ef75a9e1e09b1d46f208669e81000ee6","to":"0x1b4cb47622705f0f67b6b18bbd1aa1a91fc77d37","nonce":"0x0","deadline":"0x9c834e6","control":"0xc38d38333687ea295753c214744e839eddc7aebb","bundler":"0x7daae72fc3d948b1fa90502f1b84b6a02cce7dfd","userOpHash":"0x0648e7c2a3b705562efd0e06adb8a63916ba5a06ee92a8544369a431298bce47","callChainHash":"0x25c222f384dd726dc226053a74775e0a491fd531d79c447da90ccfb40cedf3fe","signature":"0xd83608483c9649ecf98f3641342d24c864f2143d090b8d2610f3fcdfbd365b1a513bc40af478bcc5f254cc1899022cefacecdb54aff69b7c3e21ef11a4ed49df1b"},"metacallDestination":"0x1b4cb47622705f0f67b6b18bbd1aa1a91fc77d37","metacallGasLimit":"0x3c97b8","metacallMaxFeePerGas":"0x3b9aca00","metacallCallData":"0x4317ca01000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000007200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b6065f79d99f29c3eda0ed1bda7ff88e7ee12f1e0000000000000000000000001b4cb47622705f0f67b6b18bbd1aa1a91fc77d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000009c834e6000000000000000000000000c38d38333687ea295753c214744e839eddc7aebb000000000000000000000000c38d38333687ea295753c214744e839eddc7aebb000000000000000000000000000000000000000000000000000000000000230400000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000005b8d80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000003e402a688ed0000000000000000000000008ae79bb7cce2dc3d132c288971b0f74af02a3b4a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003646fadcf72000000000000000000000000b123c2e3a71b57f9678cf6212576f30d642ed89a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002e4ba0cb29e0001aeec9ec2ddb59123858e897b26f52e2173aca2c577dcce62e7ddc70f16020000000000000000000000000000000000000000000000000000000000418a059c756341541f2283d4f124ac39dc9e718f96453582f38acfa885e4ffaf26eb7800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000678010b601000203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000075542db800000000000000000000000000000000000000000000000000000000755c8e4000000000000000000000000000000000000000000000000000000000756106c80000000000000000000000000000000000000000000000000000000075961a520000000000000000000000000000000000000000000000000000000000000002b974b422c8e712d3320994bf4ecd31e37b35a117ef4102285206c45aef4b8709ae407e7a604410ef1e622ebdb4ad302638ff0cf49ad5ab33486c206bf8ecd7dd0000000000000000000000000000000000000000000000000000000000000002671dd95393e5963a3842a5f95d5e6b544de4906b1c304d41aebbb7c2acf9cb065fb96b17223872656de8f05a17ffb6ccc3261b606179cc33db445158aa408b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041b6ae5c173d3c7577ea3b8b4d35a0dc33e0f2798d74173c5e6fee2f08b8ce20271287a87443e778a114890140a08be5faf05ebcdd59051f9747fdd35d0afe6aa01b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000377136653944bdd5d9f0db22987b7432e76c354f0000000000000000000000001b4cb47622705f0f67b6b18bbd1aa1a91fc77d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030d40000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000009c834e60000000000000000000000004b548c6faf4a3c74571c3e194e71cbf2a5172501000000000000000000000000c38d38333687ea295753c214744e839eddc7aebb0648e7c2a3b705562efd0e06adb8a63916ba5a06ee92a8544369a431298bce47000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000084c000a702000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000326a27250470f3a518db1334faaa277f8282082d7f54fd9b0f6cfff8f403a74fcb27a12a3860a1146cf7306eb49aa9fa03ccb1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004191537f835005fcd243b52b7b6436df810a1ea0b18769b2b1417ee9dacc9f9dac309a8b9ef82d82d6572e5feeb7209d12739067afd315434001a2aadd35af77701c000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f3c5ec2ef75a9e1e09b1d46f208669e81000ee60000000000000000000000001b4cb47622705f0f67b6b18bbd1aa1a91fc77d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009c834e6000000000000000000000000c38d38333687ea295753c214744e839eddc7aebb0000000000000000000000007daae72fc3d948b1fa90502f1b84b6a02cce7dfd0648e7c2a3b705562efd0e06adb8a63916ba5a06ee92a8544369a431298bce4725c222f384dd726dc226053a74775e0a491fd531d79c447da90ccfb40cedf3fe00000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000041d83608483c9649ecf98f3641342d24c864f2143d090b8d2610f3fcdfbd365b1a513bc40af478bcc5f254cc1899022cefacecdb54aff69b7c3e21ef11a4ed49df1b00000000000000000000000000000000000000000000000000000000000000"},"id":1}`)
txData, err := hex.DecodeString("6fadcf72000000000000000000000000b123c2e3a71b57f9678cf6212576f30d642ed89a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002e4ba0cb29e0001aeec9ec2ddb59123858e897b26f52e2173aca2c577dcce62e7ddc70f16020000000000000000000000000000000000000000000000000000000000418a059c756341541f2283d4f124ac39dc9e718f96453582f38acfa885e4ffaf26eb7800000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000678010b601000203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000075542db800000000000000000000000000000000000000000000000000000000755c8e4000000000000000000000000000000000000000000000000000000000756106c80000000000000000000000000000000000000000000000000000000075961a520000000000000000000000000000000000000000000000000000000000000002b974b422c8e712d3320994bf4ecd31e37b35a117ef4102285206c45aef4b8709ae407e7a604410ef1e622ebdb4ad302638ff0cf49ad5ab33486c206bf8ecd7dd0000000000000000000000000000000000000000000000000000000000000002671dd95393e5963a3842a5f95d5e6b544de4906b1c304d41aebbb7c2acf9cb065fb96b17223872656de8f05a17ffb6ccc3261b606179cc33db445158aa408b7000000000000000000000000000000000000000000000000000000000")
Expand Down
2 changes: 1 addition & 1 deletion pkg/txm/storage/inmemory_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func (m *InMemoryStore) MarkConfirmedAndReorgedTransactions(latestNonce uint64)
}
existingTx, exists := m.UnconfirmedTransactions[*tx.Nonce]
if exists {
m.lggr.Errorw("Another unconfirmed transaction with the same nonce exists. Transaction will overwritten.",
m.lggr.Errorw("Another unconfirmed transaction with the same nonce exists. Transaction will be overwritten.",
"existingTx", existingTx, "newTx", tx)
}
if *tx.Nonce >= latestNonce {
Expand Down
Loading
Loading