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.PublicKeyComp)(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.PublicKeyComp)(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		TokenID: txw.TokenID,
111		Amount:  txw.Amount,
112		Fee:     txw.Fee,
113		Nonce:   txw.Nonce,
114		// State:     txw.State,
115		Signature: txw.Signature,
116		RqAmount:  txw.RqAmount,
117		Type:      txw.Type,
118	}
119	// ToIdx
120	if txw.ToIdx != nil {
121		poolTx.ToIdx = *txw.ToIdx
122	}
123	// ToEthAddr
124	if txw.ToEthAddr == nil {
125		poolTx.ToEthAddr = common.EmptyAddr
126	} else {
127		poolTx.ToEthAddr = *txw.ToEthAddr
128	}
129	// ToBJJ
130	if txw.ToBJJ == nil {
131		poolTx.ToBJJ = common.EmptyBJJComp
132	} else {
133		poolTx.ToBJJ = *txw.ToBJJ
134	}
135	// RqFromIdx
136	if txw.RqFromIdx != nil {
137		poolTx.RqFromIdx = *txw.RqFromIdx
138	}
139	// RqToIdx
140	if txw.RqToIdx != nil {
141		poolTx.RqToIdx = *txw.RqToIdx
142	}
143	// RqToEthAddr
144	if txw.RqToEthAddr == nil {
145		poolTx.RqToEthAddr = common.EmptyAddr
146	} else {
147		poolTx.RqToEthAddr = *txw.RqToEthAddr
148	}
149	// RqToBJJ
150	if txw.RqToBJJ == nil {
151		poolTx.RqToBJJ = common.EmptyBJJComp
152	} else {
153		poolTx.RqToBJJ = *txw.RqToBJJ
154	}
155	// RqTokenID
156	if txw.RqTokenID != nil {
157		poolTx.RqTokenID = *txw.RqTokenID
158	}
159	// RqFee
160	if txw.RqFee != nil {
161		poolTx.RqFee = *txw.RqFee
162	}
163	// RqNonce
164	if txw.RqNonce != nil {
165		poolTx.RqNonce = *txw.RqNonce
166	}
167	// Check type and id
168	_, err := common.NewPoolL2Tx(&poolTx)
169	if err != nil {
170		return tracerr.Wrap(err)
171	}
172	// Get public key
173	account, err := a.s.GetAccount(poolTx.FromIdx)
174	if err != nil {
175		return tracerr.Wrap(err)
176	}
177	// Validate feeAmount
178	_, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
179	if err != nil {
180		return tracerr.Wrap(err)
181	}
182	// Check signature
183	if !poolTx.VerifySignature(a.chainID, account.BJJ) {
184		return tracerr.Wrap(errors.New("wrong signature"))
185	}
186	return nil
187}