arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/api/txspool.go
api/txspool.goRaw
  1package api
  2
  3import (
  4	"errors"
  5	"math/big"
  6	"net/http"
  7
  8	ethCommon "github.com/ethereum/go-ethereum/common"
  9	"github.com/gin-gonic/gin"
 10	"github.com/hermeznetwork/hermez-node/apitypes"
 11	"github.com/hermeznetwork/hermez-node/common"
 12	"github.com/hermeznetwork/hermez-node/db/l2db"
 13	"github.com/hermeznetwork/tracerr"
 14	"github.com/iden3/go-iden3-crypto/babyjub"
 15)
 16
 17func (a *API) postPoolTx(c *gin.Context) {
 18	// Parse body
 19	var receivedTx receivedPoolTx
 20	if err := c.ShouldBindJSON(&receivedTx); err != nil {
 21		retBadReq(err, c)
 22		return
 23	}
 24	// Transform from received to insert format and validate
 25	writeTx := receivedTx.toPoolL2TxWrite()
 26	if err := a.verifyPoolL2TxWrite(writeTx); err != nil {
 27		retBadReq(err, c)
 28		return
 29	}
 30	// Insert to DB
 31	if err := a.l2.AddTx(writeTx); err != nil {
 32		retSQLErr(err, c)
 33		return
 34	}
 35	// Return TxID
 36	c.JSON(http.StatusOK, writeTx.TxID.String())
 37}
 38
 39func (a *API) getPoolTx(c *gin.Context) {
 40	// Get TxID
 41	txID, err := parseParamTxID(c)
 42	if err != nil {
 43		retBadReq(err, c)
 44		return
 45	}
 46	// Fetch tx from l2DB
 47	tx, err := a.l2.GetTxAPI(txID)
 48	if err != nil {
 49		retSQLErr(err, c)
 50		return
 51	}
 52	// Build succesfull response
 53	c.JSON(http.StatusOK, tx)
 54}
 55
 56type receivedPoolTx struct {
 57	TxID        common.TxID             `json:"id" binding:"required"`
 58	Type        common.TxType           `json:"type" binding:"required"`
 59	TokenID     common.TokenID          `json:"tokenId"`
 60	FromIdx     apitypes.StrHezIdx      `json:"fromAccountIndex" binding:"required"`
 61	ToIdx       *apitypes.StrHezIdx     `json:"toAccountIndex"`
 62	ToEthAddr   *apitypes.StrHezEthAddr `json:"toHezEthereumAddress"`
 63	ToBJJ       *apitypes.StrHezBJJ     `json:"toBjj"`
 64	Amount      apitypes.StrBigInt      `json:"amount" binding:"required"`
 65	Fee         common.FeeSelector      `json:"fee"`
 66	Nonce       common.Nonce            `json:"nonce"`
 67	Signature   babyjub.SignatureComp   `json:"signature" binding:"required"`
 68	RqFromIdx   *apitypes.StrHezIdx     `json:"requestFromAccountIndex"`
 69	RqToIdx     *apitypes.StrHezIdx     `json:"requestToAccountIndex"`
 70	RqToEthAddr *apitypes.StrHezEthAddr `json:"requestToHezEthereumAddress"`
 71	RqToBJJ     *apitypes.StrHezBJJ     `json:"requestToBjj"`
 72	RqTokenID   *common.TokenID         `json:"requestTokenId"`
 73	RqAmount    *apitypes.StrBigInt     `json:"requestAmount"`
 74	RqFee       *common.FeeSelector     `json:"requestFee"`
 75	RqNonce     *common.Nonce           `json:"requestNonce"`
 76}
 77
 78func (tx *receivedPoolTx) toPoolL2TxWrite() *l2db.PoolL2TxWrite {
 79	f := new(big.Float).SetInt((*big.Int)(&tx.Amount))
 80	amountF, _ := f.Float64()
 81	return &l2db.PoolL2TxWrite{
 82		TxID:        tx.TxID,
 83		FromIdx:     common.Idx(tx.FromIdx),
 84		ToIdx:       (*common.Idx)(tx.ToIdx),
 85		ToEthAddr:   (*ethCommon.Address)(tx.ToEthAddr),
 86		ToBJJ:       (*babyjub.PublicKey)(tx.ToBJJ),
 87		TokenID:     tx.TokenID,
 88		Amount:      (*big.Int)(&tx.Amount),
 89		AmountFloat: amountF,
 90		Fee:         tx.Fee,
 91		Nonce:       tx.Nonce,
 92		State:       common.PoolL2TxStatePending,
 93		Signature:   tx.Signature,
 94		RqFromIdx:   (*common.Idx)(tx.RqFromIdx),
 95		RqToIdx:     (*common.Idx)(tx.RqToIdx),
 96		RqToEthAddr: (*ethCommon.Address)(tx.RqToEthAddr),
 97		RqToBJJ:     (*babyjub.PublicKey)(tx.RqToBJJ),
 98		RqTokenID:   tx.RqTokenID,
 99		RqAmount:    (*big.Int)(tx.RqAmount),
100		RqFee:       tx.RqFee,
101		RqNonce:     tx.RqNonce,
102		Type:        tx.Type,
103	}
104}
105
106func (a *API) verifyPoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
107	poolTx := common.PoolL2Tx{
108		TxID:    txw.TxID,
109		FromIdx: txw.FromIdx,
110		ToBJJ:   txw.ToBJJ,
111		TokenID: txw.TokenID,
112		Amount:  txw.Amount,
113		Fee:     txw.Fee,
114		Nonce:   txw.Nonce,
115		// State:     txw.State,
116		Signature: txw.Signature,
117		RqToBJJ:   txw.RqToBJJ,
118		RqAmount:  txw.RqAmount,
119		Type:      txw.Type,
120	}
121	// ToIdx
122	if txw.ToIdx != nil {
123		poolTx.ToIdx = *txw.ToIdx
124	}
125	// ToEthAddr
126	if txw.ToEthAddr == nil {
127		poolTx.ToEthAddr = common.EmptyAddr
128	} else {
129		poolTx.ToEthAddr = *txw.ToEthAddr
130	}
131	// RqFromIdx
132	if txw.RqFromIdx != nil {
133		poolTx.RqFromIdx = *txw.RqFromIdx
134	}
135	// RqToIdx
136	if txw.RqToIdx != nil {
137		poolTx.RqToIdx = *txw.RqToIdx
138	}
139	// RqToEthAddr
140	if txw.RqToEthAddr == nil {
141		poolTx.RqToEthAddr = common.EmptyAddr
142	} else {
143		poolTx.RqToEthAddr = *txw.RqToEthAddr
144	}
145	// RqTokenID
146	if txw.RqTokenID != nil {
147		poolTx.RqTokenID = *txw.RqTokenID
148	}
149	// RqFee
150	if txw.RqFee != nil {
151		poolTx.RqFee = *txw.RqFee
152	}
153	// RqNonce
154	if txw.RqNonce != nil {
155		poolTx.RqNonce = *txw.RqNonce
156	}
157	// Check type and id
158	_, err := common.NewPoolL2Tx(&poolTx)
159	if err != nil {
160		return tracerr.Wrap(err)
161	}
162	// Get public key
163	account, err := a.s.GetAccount(poolTx.FromIdx)
164	if err != nil {
165		return tracerr.Wrap(err)
166	}
167	// Validate feeAmount
168	_, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
169	if err != nil {
170		return tracerr.Wrap(err)
171	}
172	// Check signature
173	if !poolTx.VerifySignature(account.PublicKey) {
174		return tracerr.Wrap(errors.New("wrong signature"))
175	}
176	return nil
177}