github.com/ethersphere/bee/v2@v2.2.0/pkg/api/transaction.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
     6  
     7  import (
     8  	"errors"
     9  	"math/big"
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/common/hexutil"
    15  	"github.com/ethersphere/bee/v2/pkg/bigint"
    16  	"github.com/ethersphere/bee/v2/pkg/jsonhttp"
    17  	"github.com/ethersphere/bee/v2/pkg/sctx"
    18  	"github.com/ethersphere/bee/v2/pkg/transaction"
    19  	"github.com/gorilla/mux"
    20  )
    21  
    22  const (
    23  	errCantGetTransaction    = "cannot get transaction"
    24  	errUnknownTransaction    = "unknown transaction"
    25  	errAlreadyImported       = "already imported"
    26  	errCantResendTransaction = "can't resend transaction"
    27  )
    28  
    29  type transactionInfo struct {
    30  	TransactionHash common.Hash     `json:"transactionHash"`
    31  	To              *common.Address `json:"to"`
    32  	Nonce           uint64          `json:"nonce"`
    33  	GasPrice        *bigint.BigInt  `json:"gasPrice"`
    34  	GasLimit        uint64          `json:"gasLimit"`
    35  	GasTipBoost     int             `json:"gasTipBoost"`
    36  	GasTipCap       *bigint.BigInt  `json:"gasTipCap"`
    37  	GasFeeCap       *bigint.BigInt  `json:"gasFeeCap"`
    38  	Data            string          `json:"data"`
    39  	Created         time.Time       `json:"created"`
    40  	Description     string          `json:"description"`
    41  	Value           *bigint.BigInt  `json:"value"`
    42  }
    43  
    44  type transactionPendingList struct {
    45  	PendingTransactions []transactionInfo `json:"pendingTransactions"`
    46  }
    47  
    48  func (s *Service) transactionListHandler(w http.ResponseWriter, _ *http.Request) {
    49  	logger := s.logger.WithName("get_transactions").Build()
    50  
    51  	txHashes, err := s.transaction.PendingTransactions()
    52  	if err != nil {
    53  		logger.Debug("get pending transactions failed", "error", err)
    54  		logger.Error(nil, "get pending transactions failed")
    55  		jsonhttp.InternalServerError(w, errCantGetTransaction)
    56  		return
    57  	}
    58  
    59  	transactionInfos := make([]transactionInfo, 0, len(txHashes))
    60  	for _, txHash := range txHashes {
    61  		storedTransaction, err := s.transaction.StoredTransaction(txHash)
    62  		if err != nil {
    63  			logger.Debug("get stored transaction failed", "tx_hash", txHash, "error", err)
    64  			logger.Error(nil, "get stored transaction failed", "tx_hash", txHash)
    65  			jsonhttp.InternalServerError(w, errCantGetTransaction)
    66  			return
    67  		}
    68  
    69  		transactionInfos = append(transactionInfos, transactionInfo{
    70  			TransactionHash: txHash,
    71  			To:              storedTransaction.To,
    72  			Nonce:           storedTransaction.Nonce,
    73  			GasPrice:        bigint.Wrap(storedTransaction.GasPrice),
    74  			GasLimit:        storedTransaction.GasLimit,
    75  			GasFeeCap:       bigint.Wrap(storedTransaction.GasFeeCap),
    76  			GasTipCap:       bigint.Wrap(storedTransaction.GasTipCap),
    77  			GasTipBoost:     storedTransaction.GasTipBoost,
    78  			Data:            hexutil.Encode(storedTransaction.Data),
    79  			Created:         time.Unix(storedTransaction.Created, 0),
    80  			Description:     storedTransaction.Description,
    81  			Value:           bigint.Wrap(storedTransaction.Value),
    82  		})
    83  
    84  	}
    85  
    86  	jsonhttp.OK(w, transactionPendingList{
    87  		PendingTransactions: transactionInfos,
    88  	})
    89  }
    90  
    91  func (s *Service) transactionDetailHandler(w http.ResponseWriter, r *http.Request) {
    92  	logger := s.logger.WithName("get_transaction").Build()
    93  
    94  	paths := struct {
    95  		Hash common.Hash `map:"hash"`
    96  	}{}
    97  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
    98  		response("invalid path params", logger, w)
    99  		return
   100  	}
   101  
   102  	storedTransaction, err := s.transaction.StoredTransaction(paths.Hash)
   103  	if err != nil {
   104  		logger.Debug("get stored transaction failed", "tx_hash", paths.Hash, "error", err)
   105  		logger.Error(nil, "get stored transaction failed", "tx_hash", paths.Hash)
   106  		if errors.Is(err, transaction.ErrUnknownTransaction) {
   107  			jsonhttp.NotFound(w, errUnknownTransaction)
   108  		} else {
   109  			jsonhttp.InternalServerError(w, errCantGetTransaction)
   110  		}
   111  		return
   112  	}
   113  
   114  	jsonhttp.OK(w, transactionInfo{
   115  		TransactionHash: paths.Hash,
   116  		To:              storedTransaction.To,
   117  		Nonce:           storedTransaction.Nonce,
   118  		GasPrice:        bigint.Wrap(storedTransaction.GasPrice),
   119  		GasLimit:        storedTransaction.GasLimit,
   120  		GasFeeCap:       bigint.Wrap(storedTransaction.GasFeeCap),
   121  		GasTipCap:       bigint.Wrap(storedTransaction.GasTipCap),
   122  		GasTipBoost:     storedTransaction.GasTipBoost,
   123  		Data:            hexutil.Encode(storedTransaction.Data),
   124  		Created:         time.Unix(storedTransaction.Created, 0),
   125  		Description:     storedTransaction.Description,
   126  		Value:           bigint.Wrap(storedTransaction.Value),
   127  	})
   128  }
   129  
   130  type transactionHashResponse struct {
   131  	TransactionHash common.Hash `json:"transactionHash"`
   132  }
   133  
   134  func (s *Service) transactionResendHandler(w http.ResponseWriter, r *http.Request) {
   135  	logger := s.logger.WithName("post_transaction").Build()
   136  
   137  	paths := struct {
   138  		Hash common.Hash `map:"hash"`
   139  	}{}
   140  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
   141  		response("invalid path params", logger, w)
   142  		return
   143  	}
   144  
   145  	err := s.transaction.ResendTransaction(r.Context(), paths.Hash)
   146  	if err != nil {
   147  		logger.Debug("resend transaction failed", "tx_hash", paths.Hash, "error", err)
   148  		logger.Error(nil, "resend transaction failed", "tx_hash", paths.Hash)
   149  		if errors.Is(err, transaction.ErrUnknownTransaction) {
   150  			jsonhttp.NotFound(w, errUnknownTransaction)
   151  		} else if errors.Is(err, transaction.ErrAlreadyImported) {
   152  			jsonhttp.BadRequest(w, errAlreadyImported)
   153  		} else {
   154  			jsonhttp.InternalServerError(w, errCantResendTransaction)
   155  		}
   156  		return
   157  	}
   158  
   159  	jsonhttp.OK(w, transactionHashResponse{
   160  		TransactionHash: paths.Hash,
   161  	})
   162  }
   163  
   164  func (s *Service) transactionCancelHandler(w http.ResponseWriter, r *http.Request) {
   165  	logger := s.logger.WithName("delete_transaction").Build()
   166  
   167  	paths := struct {
   168  		Hash common.Hash `map:"hash"`
   169  	}{}
   170  	if response := s.mapStructure(mux.Vars(r), &paths); response != nil {
   171  		response("invalid path params", logger, w)
   172  		return
   173  	}
   174  
   175  	headers := struct {
   176  		GasPrice *big.Int `map:"Gas-Price"`
   177  	}{}
   178  	if response := s.mapStructure(r.Header, &headers); response != nil {
   179  		response("invalid header params", logger, w)
   180  		return
   181  	}
   182  	ctx := sctx.SetGasPrice(r.Context(), headers.GasPrice)
   183  
   184  	txHash, err := s.transaction.CancelTransaction(ctx, paths.Hash)
   185  	if err != nil {
   186  		logger.Debug("cancel transaction failed", "tx_hash", paths.Hash, "error", err, "canceled_tx_hash", txHash)
   187  		logger.Error(nil, "cancel transaction failed", "tx_hash", paths.Hash)
   188  		if errors.Is(err, transaction.ErrUnknownTransaction) {
   189  			jsonhttp.NotFound(w, errUnknownTransaction)
   190  		} else if errors.Is(err, transaction.ErrAlreadyImported) {
   191  			jsonhttp.BadRequest(w, errAlreadyImported)
   192  		} else {
   193  			jsonhttp.InternalServerError(w, errCantResendTransaction)
   194  		}
   195  		return
   196  	}
   197  
   198  	jsonhttp.OK(w, transactionHashResponse{
   199  		TransactionHash: txHash,
   200  	})
   201  }