From 6bc39ade47a9344eb6097fb041daa6eebbe81c86 Mon Sep 17 00:00:00 2001 From: amit-momin Date: Fri, 24 May 2024 16:18:52 -0500 Subject: [PATCH] Adjusted to align as close as possible with the ChainWriter interface --- common/txmgr/mocks/tx_manager.go | 72 +++++++++++++---------------- common/txmgr/txmgr.go | 20 ++++---- core/chains/evm/txmgr/txmgr_test.go | 68 +++++++++++++-------------- 3 files changed, 74 insertions(+), 86 deletions(-) diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 9efa0b280ed..0a87e794d7a 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -6,10 +6,7 @@ import ( context "context" big "math/big" - client "github.com/smartcontractkit/chainlink/v2/common/client" - feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - mock "github.com/stretchr/testify/mock" null "gopkg.in/guregu/null.v4" @@ -19,6 +16,8 @@ import ( txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" types "github.com/smartcontractkit/chainlink/v2/common/types" + + uuid "github.com/google/uuid" ) // TxManager is an autogenerated mock type for the TxManager type @@ -332,6 +331,34 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetFor return r0, r1 } +// GetTransactionStatus provides a mock function with given fields: ctx, transactionID +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetTransactionStatus(ctx context.Context, transactionID uuid.UUID) (txmgrtypes.TxState, error) { + ret := _m.Called(ctx, transactionID) + + if len(ret) == 0 { + panic("no return value specified for GetTransactionStatus") + } + + var r0 txmgrtypes.TxState + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) (txmgrtypes.TxState, error)); ok { + return rf(ctx, transactionID) + } + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) txmgrtypes.TxState); ok { + r0 = rf(ctx, transactionID) + } else { + r0 = ret.Get(0).(txmgrtypes.TxState) + } + + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { + r1 = rf(ctx, transactionID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HealthReport provides a mock function with given fields: func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { ret := _m.Called() @@ -467,43 +494,6 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trigge _m.Called(addr) } -// TxStatusByIdempotencyKey provides a mock function with given fields: ctx, idempotency -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) TxStatusByIdempotencyKey(ctx context.Context, idempotency string) (txmgrtypes.TxState, client.TxError, error) { - ret := _m.Called(ctx, idempotency) - - if len(ret) == 0 { - panic("no return value specified for TxStatusByIdempotencyKey") - } - - var r0 txmgrtypes.TxState - var r1 client.TxError - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, string) (txmgrtypes.TxState, client.TxError, error)); ok { - return rf(ctx, idempotency) - } - if rf, ok := ret.Get(0).(func(context.Context, string) txmgrtypes.TxState); ok { - r0 = rf(ctx, idempotency) - } else { - r0 = ret.Get(0).(txmgrtypes.TxState) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) client.TxError); ok { - r1 = rf(ctx, idempotency) - } else { - if ret.Get(1) != nil { - r1 = ret.Get(1).(client.TxError) - } - } - - if rf, ok := ret.Get(2).(func(context.Context, string) error); ok { - r2 = rf(ctx, idempotency) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // NewTxManager creates a new instance of TxManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewTxManager[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence, FEE feetypes.Fee](t interface { diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index c409e2ba28d..c657f687fdf 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -65,7 +65,7 @@ type TxManager[ FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (nullv4.Time, error) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (nullv4.Int, error) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) - TxStatusByIdempotencyKey(ctx context.Context, idempotency string) (txmgrtypes.TxState, client.TxError, error) + GetTransactionStatus(ctx context.Context, transactionID uuid.UUID) (state txmgrtypes.TxState, err error) } type reset struct { @@ -632,14 +632,16 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTrans return b.txStore.CountTransactionsByState(ctx, state, b.chainID) } -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) TxStatusByIdempotencyKey(ctx context.Context, idempotencyKey string) (state txmgrtypes.TxState, txErr client.TxError, err error) { - tx, _ := b.txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, b.chainID) - // this check is more complete since a no-rows error returns nil err +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTransactionStatus(ctx context.Context, transactionID uuid.UUID) (status txmgrtypes.TxState, err error) { + tx, err := b.txStore.FindTxWithIdempotencyKey(ctx, transactionID.String(), b.chainID) + if err != nil { + return status, fmt.Errorf("failed to find transaction with IdempotencyKey %s: %w", transactionID.String(), err) + } + // This check is required since a no-rows error returns nil err if tx == nil { - return "", txErr, fmt.Errorf("failed to find transaction with IdempotencyKey: %s", idempotencyKey) + return status, fmt.Errorf("failed to find transaction with IdempotencyKey %s", transactionID.String()) } - txErr = b.newTxError(tx.GetError()) - return tx.State, txErr, nil + return tx.State, tx.GetError() } type NullTxManager[ @@ -725,8 +727,8 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Cou return count, errors.New(n.ErrMsg) } -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) TxStatusByIdempotencyKey(ctx context.Context, idempotencyKey string) (state txmgrtypes.TxState, txErr client.TxError, err error) { - return "", txErr, nil +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetTransactionStatus(ctx context.Context, transactionID uuid.UUID) (state txmgrtypes.TxState, err error) { + return } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pruneQueueAndCreateTxn( diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index f134f4dcd87..8478d90ef82 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -604,18 +604,18 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { require.NoError(t, err) t.Run("returns error if transaction not found", func(t *testing.T) { - idempotencyKey := uuid.New().String() - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + idempotencyKey := uuid.New() + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.Error(t, err, fmt.Sprintf("failed to find transaction with IdempotencyKey: %s", idempotencyKey)) require.Equal(t, txmgrtypes.TxState(""), state) - require.Nil(t, txErr) }) t.Run("returns unstarted state", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) tx := &txmgr.Tx{ - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -623,19 +623,19 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.NoError(t, err) require.Equal(t, txmgrcommon.TxUnstarted, state) - require.Nil(t, txErr) }) t.Run("returns in-progress state", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) nonce := evmtypes.Nonce(0) tx := &txmgr.Tx{ Sequence: &nonce, - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -643,20 +643,20 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.NoError(t, err) require.Equal(t, txmgrcommon.TxInProgress, state) - require.Nil(t, txErr) }) t.Run("returns unconfirmed state", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ Sequence: &nonce, - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -666,20 +666,20 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.NoError(t, err) require.Equal(t, txmgrcommon.TxUnconfirmed, state) - require.Nil(t, txErr) }) t.Run("returns confirmed state", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ Sequence: &nonce, - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -689,20 +689,20 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, state) - require.Nil(t, txErr) }) t.Run("returns confirmed missing receipt state", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ Sequence: &nonce, - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -712,20 +712,20 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, state) - require.Nil(t, txErr) }) t.Run("returns fatal error state with terminally stuck error", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ Sequence: &nonce, - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -736,20 +736,18 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) - require.NoError(t, err) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.Equal(t, txmgrcommon.TxFatalError, state) - require.NotNil(t, txErr) - require.Equal(t, client.TerminallyStuckMsg, txErr.Error()) - require.Equal(t, true, txErr.IsTerminallyStuck()) + require.Error(t, err, client.TerminallyStuckMsg) }) t.Run("returns fatal error state with other error", func(t *testing.T) { - idempotencyKey := uuid.New().String() + idempotencyKey := uuid.New() + idempotencyKeyStr := idempotencyKey.String() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) errorMsg := "something went wrong" tx := &txmgr.Tx{ - IdempotencyKey: &idempotencyKey, + IdempotencyKey: &idempotencyKeyStr, FromAddress: fromAddress, EncodedPayload: []byte{1, 2, 3}, FeeLimit: feeLimit, @@ -758,11 +756,9 @@ func TestTxm_TxStatusByIdempotencyKey(t *testing.T) { } err := txStore.InsertTx(ctx, tx) require.NoError(t, err) - state, txErr, err := txm.TxStatusByIdempotencyKey(ctx, idempotencyKey) - require.NoError(t, err) + state, err := txm.GetTransactionStatus(ctx, idempotencyKey) require.Equal(t, txmgrcommon.TxFatalError, state) - require.NotNil(t, txErr) - require.Equal(t, errorMsg, txErr.Error()) + require.Error(t, err, errorMsg) }) }