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	writeTx.ClientIP = c.ClientIP()
 31	// Insert to DB
 32	if err := a.l2.AddTxAPI(writeTx); err != nil {
 33		retSQLErr(err, c)
 34		return
 35	}
 36	// Return TxID
 37	c.JSON(http.StatusOK, writeTx.TxID.String())
 38}
 39
 40func (a *API) getPoolTx(c *gin.Context) {
 41	// Get TxID
 42	txID, err := parseParamTxID(c)
 43	if err != nil {
 44		retBadReq(err, c)
 45		return
 46	}
 47	// Fetch tx from l2DB
 48	tx, err := a.l2.GetTxAPI(txID)
 49	if err != nil {
 50		retSQLErr(err, c)
 51		return
 52	}
 53	// Build succesfull response
 54	c.JSON(http.StatusOK, tx)
 55}
 56
 57type receivedPoolTx struct {
 58	TxID        common.TxID             `json:"id" binding:"required"`
 59	Type        common.TxType           `json:"type" binding:"required"`
 60	TokenID     common.TokenID          `json:"tokenId"`
 61	FromIdx     apitypes.StrHezIdx      `json:"fromAccountIndex" binding:"required"`
 62	ToIdx       *apitypes.StrHezIdx     `json:"toAccountIndex"`
 63	ToEthAddr   *apitypes.StrHezEthAddr `json:"toHezEthereumAddress"`
 64	ToBJJ       *apitypes.StrHezBJJ     `json:"toBjj"`
 65	Amount      apitypes.StrBigInt      `json:"amount" binding:"required"`
 66	Fee         common.FeeSelector      `json:"fee"`
 67	Nonce       common.Nonce            `json:"nonce"`
 68	Signature   babyjub.SignatureComp   `json:"signature" binding:"required"`
 69	RqFromIdx   *apitypes.StrHezIdx     `json:"requestFromAccountIndex"`
 70	RqToIdx     *apitypes.StrHezIdx     `json:"requestToAccountIndex"`
 71	RqToEthAddr *apitypes.StrHezEthAddr `json:"requestToHezEthereumAddress"`
 72	RqToBJJ     *apitypes.StrHezBJJ     `json:"requestToBjj"`
 73	RqTokenID   *common.TokenID         `json:"requestTokenId"`
 74	RqAmount    *apitypes.StrBigInt     `json:"requestAmount"`
 75	RqFee       *common.FeeSelector     `json:"requestFee"`
 76	RqNonce     *common.Nonce           `json:"requestNonce"`
 77}
 78
 79func (tx *receivedPoolTx) toPoolL2TxWrite() *l2db.PoolL2TxWrite {
 80	f := new(big.Float).SetInt((*big.Int)(&tx.Amount))
 81	amountF, _ := f.Float64()
 82	return &l2db.PoolL2TxWrite{
 83		TxID:        tx.TxID,
 84		FromIdx:     common.Idx(tx.FromIdx),
 85		ToIdx:       (*common.Idx)(tx.ToIdx),
 86		ToEthAddr:   (*ethCommon.Address)(tx.ToEthAddr),
 87		ToBJJ:       (*babyjub.PublicKeyComp)(tx.ToBJJ),
 88		TokenID:     tx.TokenID,
 89		Amount:      (*big.Int)(&tx.Amount),
 90		AmountFloat: amountF,
 91		Fee:         tx.Fee,
 92		Nonce:       tx.Nonce,
 93		State:       common.PoolL2TxStatePending,
 94		Signature:   tx.Signature,
 95		RqFromIdx:   (*common.Idx)(tx.RqFromIdx),
 96		RqToIdx:     (*common.Idx)(tx.RqToIdx),
 97		RqToEthAddr: (*ethCommon.Address)(tx.RqToEthAddr),
 98		RqToBJJ:     (*babyjub.PublicKeyComp)(tx.RqToBJJ),
 99		RqTokenID:   tx.RqTokenID,
100		RqAmount:    (*big.Int)(tx.RqAmount),
101		RqFee:       tx.RqFee,
102		RqNonce:     tx.RqNonce,
103		Type:        tx.Type,
104	}
105}
106
107func (a *API) verifyPoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
108	poolTx := common.PoolL2Tx{
109		TxID:    txw.TxID,
110		FromIdx: txw.FromIdx,
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		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	// ToBJJ
131	if txw.ToBJJ == nil {
132		poolTx.ToBJJ = common.EmptyBJJComp
133	} else {
134		poolTx.ToBJJ = *txw.ToBJJ
135	}
136	// RqFromIdx
137	if txw.RqFromIdx != nil {
138		poolTx.RqFromIdx = *txw.RqFromIdx
139	}
140	// RqToIdx
141	if txw.RqToIdx != nil {
142		poolTx.RqToIdx = *txw.RqToIdx
143	}
144	// RqToEthAddr
145	if txw.RqToEthAddr == nil {
146		poolTx.RqToEthAddr = common.EmptyAddr
147	} else {
148		poolTx.RqToEthAddr = *txw.RqToEthAddr
149	}
150	// RqToBJJ
151	if txw.RqToBJJ == nil {
152		poolTx.RqToBJJ = common.EmptyBJJComp
153	} else {
154		poolTx.RqToBJJ = *txw.RqToBJJ
155	}
156	// RqTokenID
157	if txw.RqTokenID != nil {
158		poolTx.RqTokenID = *txw.RqTokenID
159	}
160	// RqFee
161	if txw.RqFee != nil {
162		poolTx.RqFee = *txw.RqFee
163	}
164	// RqNonce
165	if txw.RqNonce != nil {
166		poolTx.RqNonce = *txw.RqNonce
167	}
168	// Check type and id
169	_, err := common.NewPoolL2Tx(&poolTx)
170	if err != nil {
171		return tracerr.Wrap(err)
172	}
173	// Get public key
174	account, err := a.s.LastGetAccount(poolTx.FromIdx)
175	if err != nil {
176		return tracerr.Wrap(err)
177	}
178	// Validate feeAmount
179	_, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
180	if err != nil {
181		return tracerr.Wrap(err)
182	}
183	// Check signature
184	if !poolTx.VerifySignature(a.chainID, account.BJJ) {
185		return tracerr.Wrap(errors.New("wrong signature"))
186	}
187	return nil
188}