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 }