github.com/ethersphere/bee/v2@v2.2.0/pkg/api/transaction_test.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package api_test
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"math/big"
    11  	"net/http"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/ethereum/go-ethereum/common"
    16  	"github.com/ethereum/go-ethereum/common/hexutil"
    17  	"github.com/ethersphere/bee/v2/pkg/api"
    18  	"github.com/ethersphere/bee/v2/pkg/bigint"
    19  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    20  	"github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest"
    21  	"github.com/ethersphere/bee/v2/pkg/transaction"
    22  	"github.com/ethersphere/bee/v2/pkg/transaction/mock"
    23  )
    24  
    25  func TestTransactionStoredTransaction(t *testing.T) {
    26  	t.Parallel()
    27  
    28  	txHashStr := "0xabcd"
    29  	txHash := common.HexToHash(txHashStr)
    30  	dataStr := "abdd"
    31  	data := common.Hex2Bytes(dataStr)
    32  	created := int64(1616451040)
    33  	recipient := common.HexToAddress("fffe")
    34  	gasPrice := big.NewInt(12)
    35  	gasLimit := uint64(200)
    36  	value := big.NewInt(50)
    37  	nonce := uint64(12)
    38  	description := "test"
    39  	gasTipBoost := 10
    40  	gasTipCap := new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(gasTipBoost)+100), gasPrice), big.NewInt(100))
    41  	t.Run("found", func(t *testing.T) {
    42  		t.Parallel()
    43  
    44  		testServer, _, _, _ := newTestServer(t, testServerOptions{
    45  			TransactionOpts: []mock.Option{
    46  				mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
    47  					return &transaction.StoredTransaction{
    48  						To:          &recipient,
    49  						Created:     created,
    50  						Data:        data,
    51  						GasPrice:    gasPrice,
    52  						GasLimit:    gasLimit,
    53  						GasFeeCap:   gasPrice,
    54  						GasTipBoost: gasTipBoost,
    55  						GasTipCap:   gasTipCap,
    56  						Value:       value,
    57  						Nonce:       nonce,
    58  						Description: description,
    59  					}, nil
    60  				}),
    61  			},
    62  		})
    63  
    64  		jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions/"+txHashStr, http.StatusOK,
    65  			jsonhttptest.WithExpectedJSONResponse(api.TransactionInfo{
    66  				TransactionHash: txHash,
    67  				Created:         time.Unix(created, 0),
    68  				Data:            "0x" + dataStr,
    69  				To:              &recipient,
    70  				GasPrice:        bigint.Wrap(gasPrice),
    71  				GasLimit:        gasLimit,
    72  				GasFeeCap:       bigint.Wrap(gasPrice),
    73  				GasTipCap:       bigint.Wrap(gasTipCap),
    74  				GasTipBoost:     gasTipBoost,
    75  				Value:           bigint.Wrap(value),
    76  				Nonce:           nonce,
    77  				Description:     description,
    78  			}),
    79  		)
    80  	})
    81  
    82  	t.Run("not found", func(t *testing.T) {
    83  		t.Parallel()
    84  
    85  		testServer, _, _, _ := newTestServer(t, testServerOptions{
    86  			TransactionOpts: []mock.Option{
    87  				mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
    88  					return nil, transaction.ErrUnknownTransaction
    89  				}),
    90  			},
    91  		})
    92  
    93  		jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions/"+txHashStr, http.StatusNotFound,
    94  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
    95  				Message: api.ErrUnknownTransaction,
    96  				Code:    http.StatusNotFound,
    97  			}))
    98  	})
    99  
   100  	t.Run("other errors", func(t *testing.T) {
   101  		t.Parallel()
   102  
   103  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   104  			TransactionOpts: []mock.Option{
   105  				mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
   106  					return nil, errors.New("err")
   107  				}),
   108  			},
   109  		})
   110  
   111  		jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions/"+txHashStr, http.StatusInternalServerError,
   112  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   113  				Message: api.ErrCantGetTransaction,
   114  				Code:    http.StatusInternalServerError,
   115  			}))
   116  	})
   117  }
   118  
   119  func TestTransactionList(t *testing.T) {
   120  	t.Parallel()
   121  
   122  	recipient := common.HexToAddress("dfff")
   123  	txHash1 := common.HexToHash("abcd")
   124  	txHash2 := common.HexToHash("efff")
   125  	storedTransactions := map[common.Hash]*transaction.StoredTransaction{
   126  		txHash1: {
   127  			To:          &recipient,
   128  			Data:        []byte{1, 2, 3, 4},
   129  			GasPrice:    big.NewInt(12),
   130  			GasLimit:    5345,
   131  			GasTipBoost: 10,
   132  			GasTipCap:   new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(10)+100), big.NewInt(12)), big.NewInt(100)),
   133  			GasFeeCap:   big.NewInt(12),
   134  			Value:       big.NewInt(4),
   135  			Nonce:       3,
   136  			Created:     1,
   137  			Description: "test",
   138  		},
   139  		txHash2: {
   140  			To:          &recipient,
   141  			Created:     2,
   142  			Data:        []byte{3, 2, 3, 4},
   143  			GasPrice:    big.NewInt(42),
   144  			GasTipBoost: 10,
   145  			GasTipCap:   new(big.Int).Div(new(big.Int).Mul(big.NewInt(int64(10)+100), big.NewInt(42)), big.NewInt(100)),
   146  			GasFeeCap:   big.NewInt(42),
   147  			GasLimit:    53451,
   148  			Value:       big.NewInt(41),
   149  			Nonce:       32,
   150  			Description: "test2",
   151  		},
   152  	}
   153  
   154  	testServer, _, _, _ := newTestServer(t, testServerOptions{
   155  		TransactionOpts: []mock.Option{
   156  			mock.WithPendingTransactionsFunc(func() ([]common.Hash, error) {
   157  				return []common.Hash{txHash1, txHash2}, nil
   158  			}),
   159  			mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
   160  				return storedTransactions[txHash], nil
   161  			}),
   162  		},
   163  	})
   164  
   165  	jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions", http.StatusOK,
   166  		jsonhttptest.WithExpectedJSONResponse(api.TransactionPendingList{
   167  			PendingTransactions: []api.TransactionInfo{
   168  				{
   169  					TransactionHash: txHash1,
   170  					To:              storedTransactions[txHash1].To,
   171  					Nonce:           storedTransactions[txHash1].Nonce,
   172  					GasPrice:        bigint.Wrap(storedTransactions[txHash1].GasPrice),
   173  					GasLimit:        storedTransactions[txHash1].GasLimit,
   174  					GasTipCap:       bigint.Wrap(storedTransactions[txHash1].GasTipCap),
   175  					GasTipBoost:     storedTransactions[txHash1].GasTipBoost,
   176  					GasFeeCap:       bigint.Wrap(storedTransactions[txHash1].GasPrice),
   177  					Data:            hexutil.Encode(storedTransactions[txHash1].Data),
   178  					Created:         time.Unix(storedTransactions[txHash1].Created, 0),
   179  					Description:     storedTransactions[txHash1].Description,
   180  					Value:           bigint.Wrap(storedTransactions[txHash1].Value),
   181  				},
   182  				{
   183  					TransactionHash: txHash2,
   184  					To:              storedTransactions[txHash2].To,
   185  					Nonce:           storedTransactions[txHash2].Nonce,
   186  					GasPrice:        bigint.Wrap(storedTransactions[txHash2].GasPrice),
   187  					GasLimit:        storedTransactions[txHash2].GasLimit,
   188  					GasTipCap:       bigint.Wrap(storedTransactions[txHash2].GasTipCap),
   189  					GasTipBoost:     storedTransactions[txHash2].GasTipBoost,
   190  					GasFeeCap:       bigint.Wrap(storedTransactions[txHash2].GasPrice),
   191  					Data:            hexutil.Encode(storedTransactions[txHash2].Data),
   192  					Created:         time.Unix(storedTransactions[txHash2].Created, 0),
   193  					Description:     storedTransactions[txHash2].Description,
   194  					Value:           bigint.Wrap(storedTransactions[txHash2].Value),
   195  				},
   196  			},
   197  		}),
   198  	)
   199  }
   200  
   201  func TestTransactionListError(t *testing.T) {
   202  	t.Parallel()
   203  
   204  	txHash1 := common.HexToHash("abcd")
   205  	t.Run("pending transactions error", func(t *testing.T) {
   206  		t.Parallel()
   207  
   208  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   209  			TransactionOpts: []mock.Option{
   210  				mock.WithPendingTransactionsFunc(func() ([]common.Hash, error) {
   211  					return nil, errors.New("err")
   212  				}),
   213  				mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
   214  					return nil, nil
   215  				}),
   216  			},
   217  		})
   218  
   219  		jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions", http.StatusInternalServerError,
   220  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   221  				Code:    http.StatusInternalServerError,
   222  				Message: api.ErrCantGetTransaction,
   223  			}),
   224  		)
   225  	})
   226  
   227  	t.Run("pending transactions error", func(t *testing.T) {
   228  		t.Parallel()
   229  
   230  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   231  			TransactionOpts: []mock.Option{
   232  				mock.WithPendingTransactionsFunc(func() ([]common.Hash, error) {
   233  					return []common.Hash{txHash1}, nil
   234  				}),
   235  				mock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) {
   236  					return nil, errors.New("error")
   237  				}),
   238  			},
   239  		})
   240  
   241  		jsonhttptest.Request(t, testServer, http.MethodGet, "/transactions", http.StatusInternalServerError,
   242  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   243  				Code:    http.StatusInternalServerError,
   244  				Message: api.ErrCantGetTransaction,
   245  			}),
   246  		)
   247  	})
   248  }
   249  
   250  func TestTransactionResend(t *testing.T) {
   251  	t.Parallel()
   252  
   253  	txHash := common.HexToHash("abcd")
   254  	t.Run("ok", func(t *testing.T) {
   255  		t.Parallel()
   256  
   257  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   258  			TransactionOpts: []mock.Option{
   259  				mock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error {
   260  					return nil
   261  				}),
   262  			},
   263  		})
   264  
   265  		jsonhttptest.Request(t, testServer, http.MethodPost, "/transactions/"+txHash.String(), http.StatusOK,
   266  			jsonhttptest.WithExpectedJSONResponse(api.TransactionHashResponse{
   267  				TransactionHash: txHash,
   268  			}),
   269  		)
   270  	})
   271  
   272  	t.Run("unknown transaction", func(t *testing.T) {
   273  		t.Parallel()
   274  
   275  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   276  			TransactionOpts: []mock.Option{
   277  				mock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error {
   278  					return transaction.ErrUnknownTransaction
   279  				}),
   280  			},
   281  		})
   282  
   283  		jsonhttptest.Request(t, testServer, http.MethodPost, "/transactions/"+txHash.String(), http.StatusNotFound,
   284  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   285  				Code:    http.StatusNotFound,
   286  				Message: api.ErrUnknownTransaction,
   287  			}),
   288  		)
   289  	})
   290  
   291  	t.Run("already imported", func(t *testing.T) {
   292  		t.Parallel()
   293  
   294  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   295  			TransactionOpts: []mock.Option{
   296  				mock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error {
   297  					return transaction.ErrAlreadyImported
   298  				}),
   299  			},
   300  		})
   301  
   302  		jsonhttptest.Request(t, testServer, http.MethodPost, "/transactions/"+txHash.String(), http.StatusBadRequest,
   303  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   304  				Code:    http.StatusBadRequest,
   305  				Message: api.ErrAlreadyImported,
   306  			}),
   307  		)
   308  	})
   309  
   310  	t.Run("other error", func(t *testing.T) {
   311  		t.Parallel()
   312  
   313  		testServer, _, _, _ := newTestServer(t, testServerOptions{
   314  			TransactionOpts: []mock.Option{
   315  				mock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error {
   316  					return errors.New("err")
   317  				}),
   318  			},
   319  		})
   320  
   321  		jsonhttptest.Request(t, testServer, http.MethodPost, "/transactions/"+txHash.String(), http.StatusInternalServerError,
   322  			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
   323  				Code:    http.StatusInternalServerError,
   324  				Message: api.ErrCantResendTransaction,
   325  			}),
   326  		)
   327  	})
   328  }