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