You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
10 KiB

  1. package common
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "time"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  8. "github.com/hermeznetwork/tracerr"
  9. "github.com/iden3/go-iden3-crypto/babyjub"
  10. "github.com/iden3/go-iden3-crypto/poseidon"
  11. )
  12. // PoolL2Tx is a struct that represents a L2Tx sent by an account to the coordinator hat is waiting to be forged
  13. type PoolL2Tx struct {
  14. // Stored in DB: mandatory fileds
  15. // TxID (12 bytes) for L2Tx is:
  16. // bytes: | 1 | 6 | 5 |
  17. // values: | type | FromIdx | Nonce |
  18. TxID TxID `meddler:"tx_id"`
  19. FromIdx Idx `meddler:"from_idx"`
  20. ToIdx Idx `meddler:"to_idx,zeroisnull"`
  21. AuxToIdx Idx `meddler:"-"` // AuxToIdx is only used internally at the StateDB to avoid repeated computation when processing transactions (from Synchronizer, TxSelector, BatchBuilder)
  22. ToEthAddr ethCommon.Address `meddler:"to_eth_addr,zeroisnull"`
  23. ToBJJ *babyjub.PublicKey `meddler:"to_bjj"`
  24. TokenID TokenID `meddler:"token_id"`
  25. Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16
  26. Fee FeeSelector `meddler:"fee"`
  27. Nonce Nonce `meddler:"nonce"` // effective 40 bits used
  28. State PoolL2TxState `meddler:"state"`
  29. Signature babyjub.SignatureComp `meddler:"signature"` // tx signature
  30. Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool
  31. // Stored in DB: optional fileds, may be uninitialized
  32. RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  33. RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  34. RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr,zeroisnull"`
  35. RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"` // TODO: stop using json, use scanner/valuer
  36. RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
  37. RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16
  38. RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
  39. RqNonce Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
  40. AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"`
  41. AbsoluteFeeUpdate time.Time `meddler:"usd_update,utctimez"`
  42. Type TxType `meddler:"tx_type"`
  43. // Extra metadata, may be uninitialized
  44. RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
  45. }
  46. // NewPoolL2Tx returns the given L2Tx with the TxId & Type parameters calculated
  47. // from the L2Tx values
  48. func NewPoolL2Tx(poolL2Tx *PoolL2Tx) (*PoolL2Tx, error) {
  49. // calculate TxType
  50. var txType TxType
  51. if poolL2Tx.ToIdx >= IdxUserThreshold {
  52. txType = TxTypeTransfer
  53. } else if poolL2Tx.ToIdx == 1 {
  54. txType = TxTypeExit
  55. } else if poolL2Tx.ToIdx == 0 {
  56. if poolL2Tx.ToBJJ != nil && poolL2Tx.ToEthAddr == FFAddr {
  57. txType = TxTypeTransferToBJJ
  58. } else if poolL2Tx.ToEthAddr != FFAddr && poolL2Tx.ToEthAddr != EmptyAddr {
  59. txType = TxTypeTransferToEthAddr
  60. }
  61. } else {
  62. return nil, tracerr.Wrap(errors.New("malformed transaction"))
  63. }
  64. // if TxType!=poolL2Tx.TxType return error
  65. if poolL2Tx.Type != "" && poolL2Tx.Type != txType {
  66. return poolL2Tx, tracerr.Wrap(fmt.Errorf("type: %s, should be: %s", poolL2Tx.Type, txType))
  67. }
  68. poolL2Tx.Type = txType
  69. var txid [TxIDLen]byte
  70. txid[0] = TxIDPrefixL2Tx
  71. fromIdxBytes, err := poolL2Tx.FromIdx.Bytes()
  72. if err != nil {
  73. return poolL2Tx, tracerr.Wrap(err)
  74. }
  75. copy(txid[1:7], fromIdxBytes[:])
  76. nonceBytes, err := poolL2Tx.Nonce.Bytes()
  77. if err != nil {
  78. return poolL2Tx, tracerr.Wrap(err)
  79. }
  80. copy(txid[7:12], nonceBytes[:])
  81. txID := TxID(txid)
  82. // if TxID!=poolL2Tx.TxID return error
  83. if poolL2Tx.TxID != (TxID{}) && poolL2Tx.TxID != txID {
  84. return poolL2Tx, tracerr.Wrap(fmt.Errorf("id: %s, should be: %s", poolL2Tx.TxID.String(), txID.String()))
  85. }
  86. poolL2Tx.TxID = txID
  87. return poolL2Tx, nil
  88. }
  89. // TxCompressedData spec:
  90. // [ 1 bits ] toBJJSign // 1 byte
  91. // [ 8 bits ] userFee // 1 byte
  92. // [ 40 bits ] nonce // 5 bytes
  93. // [ 32 bits ] tokenID // 4 bytes
  94. // [ 16 bits ] amountFloat16 // 2 bytes
  95. // [ 48 bits ] toIdx // 6 bytes
  96. // [ 48 bits ] fromIdx // 6 bytes
  97. // [ 16 bits ] chainId // 2 bytes
  98. // [ 32 bits ] signatureConstant // 4 bytes
  99. // Total bits compressed data: 241 bits // 31 bytes in *big.Int representation
  100. func (tx *PoolL2Tx) TxCompressedData() (*big.Int, error) {
  101. amountFloat16, err := NewFloat16(tx.Amount)
  102. if err != nil {
  103. return nil, tracerr.Wrap(err)
  104. }
  105. var b [31]byte
  106. toBJJSign := byte(0)
  107. if tx.ToBJJ != nil && babyjub.PointCoordSign(tx.ToBJJ.X) {
  108. toBJJSign = byte(1)
  109. }
  110. b[0] = toBJJSign
  111. b[1] = byte(tx.Fee)
  112. nonceBytes, err := tx.Nonce.Bytes()
  113. if err != nil {
  114. return nil, tracerr.Wrap(err)
  115. }
  116. copy(b[2:7], nonceBytes[:])
  117. copy(b[7:11], tx.TokenID.Bytes())
  118. copy(b[11:13], amountFloat16.Bytes())
  119. toIdxBytes, err := tx.ToIdx.Bytes()
  120. if err != nil {
  121. return nil, tracerr.Wrap(err)
  122. }
  123. copy(b[13:19], toIdxBytes[:])
  124. fromIdxBytes, err := tx.FromIdx.Bytes()
  125. if err != nil {
  126. return nil, tracerr.Wrap(err)
  127. }
  128. copy(b[19:25], fromIdxBytes[:])
  129. copy(b[25:27], []byte{0, 0}) // TODO this will be generated by the ChainID config parameter
  130. copy(b[27:31], SignatureConstantBytes[:])
  131. bi := new(big.Int).SetBytes(b[:])
  132. return bi, nil
  133. }
  134. // TxCompressedDataV2 spec:
  135. // [ 1 bits ] toBJJSign // 1 byte
  136. // [ 8 bits ] userFee // 1 byte
  137. // [ 40 bits ] nonce // 5 bytes
  138. // [ 32 bits ] tokenID // 4 bytes
  139. // [ 16 bits ] amountFloat16 // 2 bytes
  140. // [ 48 bits ] toIdx // 6 bytes
  141. // [ 48 bits ] fromIdx // 6 bytes
  142. // Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
  143. func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
  144. if tx.Amount == nil {
  145. tx.Amount = big.NewInt(0)
  146. }
  147. amountFloat16, err := NewFloat16(tx.Amount)
  148. if err != nil {
  149. return nil, tracerr.Wrap(err)
  150. }
  151. var b [25]byte
  152. toBJJSign := byte(0)
  153. if tx.ToBJJ != nil && babyjub.PointCoordSign(tx.ToBJJ.X) {
  154. toBJJSign = byte(1)
  155. }
  156. b[0] = toBJJSign
  157. b[1] = byte(tx.Fee)
  158. nonceBytes, err := tx.Nonce.Bytes()
  159. if err != nil {
  160. return nil, tracerr.Wrap(err)
  161. }
  162. copy(b[2:7], nonceBytes[:])
  163. copy(b[7:11], tx.TokenID.Bytes())
  164. copy(b[11:13], amountFloat16.Bytes())
  165. toIdxBytes, err := tx.ToIdx.Bytes()
  166. if err != nil {
  167. return nil, tracerr.Wrap(err)
  168. }
  169. copy(b[13:19], toIdxBytes[:])
  170. fromIdxBytes, err := tx.FromIdx.Bytes()
  171. if err != nil {
  172. return nil, tracerr.Wrap(err)
  173. }
  174. copy(b[19:25], fromIdxBytes[:])
  175. bi := new(big.Int).SetBytes(b[:])
  176. return bi, nil
  177. }
  178. // RqTxCompressedDataV2 is like the TxCompressedDataV2 but using the 'Rq'
  179. // parameters. In a future iteration of the hermez-node, the 'Rq' parameters
  180. // can be inside a struct, which contains the 'Rq' transaction grouped inside,
  181. // so then computing the 'RqTxCompressedDataV2' would be just calling
  182. // 'tx.Rq.TxCompressedDataV2()'.
  183. // RqTxCompressedDataV2 spec:
  184. // [ 1 bits ] rqToBJJSign // 1 byte
  185. // [ 8 bits ] rqUserFee // 1 byte
  186. // [ 40 bits ] rqNonce // 5 bytes
  187. // [ 32 bits ] rqTokenID // 4 bytes
  188. // [ 16 bits ] rqAmountFloat16 // 2 bytes
  189. // [ 48 bits ] rqToIdx // 6 bytes
  190. // [ 48 bits ] rqFromIdx // 6 bytes
  191. // Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
  192. func (tx *PoolL2Tx) RqTxCompressedDataV2() (*big.Int, error) {
  193. if tx.RqAmount == nil {
  194. tx.RqAmount = big.NewInt(0)
  195. }
  196. amountFloat16, err := NewFloat16(tx.RqAmount)
  197. if err != nil {
  198. return nil, tracerr.Wrap(err)
  199. }
  200. var b [25]byte
  201. toBJJSign := byte(0)
  202. if tx.RqToBJJ != nil && babyjub.PointCoordSign(tx.RqToBJJ.X) {
  203. toBJJSign = byte(1)
  204. }
  205. b[0] = toBJJSign
  206. b[1] = byte(tx.RqFee)
  207. nonceBytes, err := tx.RqNonce.Bytes()
  208. if err != nil {
  209. return nil, tracerr.Wrap(err)
  210. }
  211. copy(b[2:7], nonceBytes[:])
  212. copy(b[7:11], tx.RqTokenID.Bytes())
  213. copy(b[11:13], amountFloat16.Bytes())
  214. toIdxBytes, err := tx.RqToIdx.Bytes()
  215. if err != nil {
  216. return nil, tracerr.Wrap(err)
  217. }
  218. copy(b[13:19], toIdxBytes[:])
  219. fromIdxBytes, err := tx.RqFromIdx.Bytes()
  220. if err != nil {
  221. return nil, tracerr.Wrap(err)
  222. }
  223. copy(b[19:25], fromIdxBytes[:])
  224. bi := new(big.Int).SetBytes(b[:])
  225. return bi, nil
  226. }
  227. // HashToSign returns the computed Poseidon hash from the *PoolL2Tx that will be signed by the sender.
  228. func (tx *PoolL2Tx) HashToSign() (*big.Int, error) {
  229. toCompressedData, err := tx.TxCompressedData()
  230. if err != nil {
  231. return nil, tracerr.Wrap(err)
  232. }
  233. toEthAddr := EthAddrToBigInt(tx.ToEthAddr)
  234. rqToEthAddr := EthAddrToBigInt(tx.RqToEthAddr)
  235. toBJJY := big.NewInt(0)
  236. if tx.ToBJJ != nil {
  237. toBJJY = tx.ToBJJ.Y
  238. }
  239. rqTxCompressedDataV2, err := tx.RqTxCompressedDataV2()
  240. if err != nil {
  241. return nil, tracerr.Wrap(err)
  242. }
  243. rqToBJJY := big.NewInt(0)
  244. if tx.RqToBJJ != nil {
  245. rqToBJJY = tx.RqToBJJ.Y
  246. }
  247. return poseidon.Hash([]*big.Int{toCompressedData, toEthAddr, toBJJY, rqTxCompressedDataV2, rqToEthAddr, rqToBJJY})
  248. }
  249. // VerifySignature returns true if the signature verification is correct for the given PublicKey
  250. func (tx *PoolL2Tx) VerifySignature(pk *babyjub.PublicKey) bool {
  251. h, err := tx.HashToSign()
  252. if err != nil {
  253. return false
  254. }
  255. s, err := tx.Signature.Decompress()
  256. if err != nil {
  257. return false
  258. }
  259. return pk.VerifyPoseidon(h, s)
  260. }
  261. // L2Tx returns a *L2Tx from the PoolL2Tx
  262. func (tx PoolL2Tx) L2Tx() L2Tx {
  263. return L2Tx{
  264. TxID: tx.TxID,
  265. FromIdx: tx.FromIdx,
  266. ToIdx: tx.ToIdx,
  267. Amount: tx.Amount,
  268. Fee: tx.Fee,
  269. Nonce: tx.Nonce,
  270. Type: tx.Type,
  271. }
  272. }
  273. // Tx returns a *Tx from the PoolL2Tx
  274. func (tx PoolL2Tx) Tx() Tx {
  275. return Tx{
  276. TxID: tx.TxID,
  277. FromIdx: tx.FromIdx,
  278. ToIdx: tx.ToIdx,
  279. Amount: tx.Amount,
  280. TokenID: tx.TokenID,
  281. Nonce: &tx.Nonce,
  282. Fee: &tx.Fee,
  283. Type: tx.Type,
  284. }
  285. }
  286. // PoolL2TxsToL2Txs returns an array of []L2Tx from an array of []PoolL2Tx
  287. func PoolL2TxsToL2Txs(txs []PoolL2Tx) ([]L2Tx, error) {
  288. var r []L2Tx
  289. for _, poolTx := range txs {
  290. r = append(r, poolTx.L2Tx())
  291. }
  292. return r, nil
  293. }
  294. // PoolL2TxState is a struct that represents the status of a L2 transaction
  295. type PoolL2TxState string
  296. const (
  297. // PoolL2TxStatePending represents a valid L2Tx that hasn't started the forging process
  298. PoolL2TxStatePending PoolL2TxState = "pend"
  299. // PoolL2TxStateForging represents a valid L2Tx that has started the forging process
  300. PoolL2TxStateForging PoolL2TxState = "fing"
  301. // PoolL2TxStateForged represents a L2Tx that has already been forged
  302. PoolL2TxStateForged PoolL2TxState = "fged"
  303. // PoolL2TxStateInvalid represents a L2Tx that has been invalidated
  304. PoolL2TxStateInvalid PoolL2TxState = "invl"
  305. )