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.

199 lines
7.3 KiB

  1. package common
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math/big"
  6. "time"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  8. "github.com/hermeznetwork/hermez-node/utils"
  9. "github.com/iden3/go-iden3-crypto/babyjub"
  10. "github.com/iden3/go-iden3-crypto/poseidon"
  11. )
  12. // Nonce represents the nonce value in a uint64, which has the method Bytes that returns a byte array of length 5 (40 bits).
  13. type Nonce uint64
  14. // Bytes returns a byte array of length 5 representing the Nonce
  15. func (n Nonce) Bytes() ([5]byte, error) {
  16. if n >= 1099511627776 { // 2**40bits
  17. return [5]byte{}, ErrNonceOverflow
  18. }
  19. var nonceBytes [8]byte
  20. binary.LittleEndian.PutUint64(nonceBytes[:], uint64(n))
  21. var b [5]byte
  22. copy(b[:], nonceBytes[:5])
  23. return b, nil
  24. }
  25. func NonceFromBytes(b [5]byte) (Nonce, error) {
  26. var nonceBytes [8]byte
  27. copy(nonceBytes[:], b[:5])
  28. nonce := binary.LittleEndian.Uint64(nonceBytes[:])
  29. return Nonce(nonce), nil
  30. }
  31. // PoolL2Tx is a struct that represents a L2Tx sent by an account to the coordinator hat is waiting to be forged
  32. type PoolL2Tx struct {
  33. // Stored in DB: mandatory fileds
  34. TxID TxID `meddler:"tx_id"`
  35. FromIdx Idx `meddler:"from_idx"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  36. ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
  37. ToEthAddr ethCommon.Address `meddler:"to_eth_addr"`
  38. ToBJJ *babyjub.PublicKey `meddler:"to_bjj"` // TODO: stop using json, use scanner/valuer
  39. TokenID TokenID `meddler:"token_id"`
  40. Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16
  41. Fee FeeSelector `meddler:"fee"`
  42. Nonce Nonce `meddler:"nonce"` // effective 40 bits used
  43. State PoolL2TxState `meddler:"state"`
  44. Signature *babyjub.Signature `meddler:"signature"` // tx signature
  45. Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool
  46. // Stored in DB: optional fileds, may be uninitialized
  47. BatchNum BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. Presence indicates "forged" state.
  48. RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  49. RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  50. RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr"`
  51. RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"` // TODO: stop using json, use scanner/valuer
  52. RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
  53. RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16
  54. RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
  55. RqNonce uint64 `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
  56. AbsoluteFee float64 `meddler:"absolute_fee,zeroisnull"`
  57. AbsoluteFeeUpdate time.Time `meddler:"absolute_fee_update,utctimez"`
  58. // Extra metadata, may be uninitialized
  59. Type TxType `meddler:"-"` // optional, descrives which kind of tx it's
  60. RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
  61. }
  62. // TxCompressedData spec:
  63. // [ 32 bits ] signatureConstant // 4 bytes: [0:4]
  64. // [ 16 bits ] chainId // 2 bytes: [4:6]
  65. // [ 48 bits ] fromIdx // 6 bytes: [6:12]
  66. // [ 48 bits ] toIdx // 6 bytes: [12:18]
  67. // [ 16 bits ] amountFloat16 // 2 bytes: [18:20]
  68. // [ 32 bits ] tokenID // 4 bytes: [20:24]
  69. // [ 40 bits ] nonce // 5 bytes: [24:29]
  70. // [ 8 bits ] userFee // 1 byte: [29:30]
  71. // [ 1 bits ] toBjjSign // 1 byte: [30:31]
  72. // Total bits compressed data: 241 bits // 31 bytes in *big.Int representation
  73. func (tx *PoolL2Tx) TxCompressedData() (*big.Int, error) {
  74. // sigconstant
  75. sc, ok := new(big.Int).SetString("3322668559", 10)
  76. if !ok {
  77. return nil, fmt.Errorf("error parsing SignatureConstant")
  78. }
  79. amountFloat16, err := utils.NewFloat16(tx.Amount)
  80. if err != nil {
  81. return nil, err
  82. }
  83. var b [31]byte
  84. copy(b[:4], SwapEndianness(sc.Bytes()))
  85. copy(b[4:6], []byte{1, 0, 0, 0}) // LittleEndian representation of uint32(1) for Ethereum
  86. copy(b[6:12], tx.FromIdx.Bytes())
  87. copy(b[12:18], tx.ToIdx.Bytes())
  88. copy(b[18:20], amountFloat16.Bytes())
  89. copy(b[20:24], tx.TokenID.Bytes())
  90. nonceBytes, err := tx.Nonce.Bytes()
  91. if err != nil {
  92. return nil, err
  93. }
  94. copy(b[24:29], nonceBytes[:])
  95. b[29] = byte(tx.Fee)
  96. toBjjSign := byte(0)
  97. if babyjub.PointCoordSign(tx.ToBJJ.X) {
  98. toBjjSign = byte(1)
  99. }
  100. b[30] = toBjjSign
  101. bi := new(big.Int).SetBytes(SwapEndianness(b[:]))
  102. return bi, nil
  103. }
  104. // TxCompressedDataV2 spec:
  105. // [ 48 bits ] fromIdx // 6 bytes: [0:6]
  106. // [ 48 bits ] toIdx // 6 bytes: [6:12]
  107. // [ 16 bits ] amountFloat16 // 2 bytes: [12:14]
  108. // [ 32 bits ] tokenID // 4 bytes: [14:18]
  109. // [ 40 bits ] nonce // 5 bytes: [18:23]
  110. // [ 8 bits ] userFee // 1 byte: [23:24]
  111. // [ 1 bits ] toBjjSign // 1 byte: [24:25]
  112. // Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
  113. func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
  114. amountFloat16, err := utils.NewFloat16(tx.Amount)
  115. if err != nil {
  116. return nil, err
  117. }
  118. var b [25]byte
  119. copy(b[0:6], tx.FromIdx.Bytes())
  120. copy(b[6:12], tx.ToIdx.Bytes())
  121. copy(b[12:14], amountFloat16.Bytes())
  122. copy(b[14:18], tx.TokenID.Bytes())
  123. nonceBytes, err := tx.Nonce.Bytes()
  124. if err != nil {
  125. return nil, err
  126. }
  127. copy(b[18:23], nonceBytes[:])
  128. b[23] = byte(tx.Fee)
  129. toBjjSign := byte(0)
  130. if babyjub.PointCoordSign(tx.ToBJJ.X) {
  131. toBjjSign = byte(1)
  132. }
  133. b[24] = toBjjSign
  134. bi := new(big.Int).SetBytes(SwapEndianness(b[:]))
  135. return bi, nil
  136. }
  137. // HashToSign returns the computed Poseidon hash from the *PoolL2Tx that will be signed by the sender.
  138. func (tx *PoolL2Tx) HashToSign() (*big.Int, error) {
  139. toCompressedData, err := tx.TxCompressedData()
  140. if err != nil {
  141. return nil, err
  142. }
  143. toEthAddr := EthAddrToBigInt(tx.ToEthAddr)
  144. toBjjAy := tx.ToBJJ.Y
  145. rqTxCompressedDataV2, err := tx.TxCompressedDataV2()
  146. if err != nil {
  147. return nil, err
  148. }
  149. return poseidon.Hash([]*big.Int{toCompressedData, toEthAddr, toBjjAy, rqTxCompressedDataV2, EthAddrToBigInt(tx.RqToEthAddr), tx.RqToBJJ.Y})
  150. }
  151. // VerifySignature returns true if the signature verification is correct for the given PublicKey
  152. func (tx *PoolL2Tx) VerifySignature(pk *babyjub.PublicKey) bool {
  153. h, err := tx.HashToSign()
  154. if err != nil {
  155. return false
  156. }
  157. return pk.VerifyPoseidon(h, tx.Signature)
  158. }
  159. func (tx *PoolL2Tx) Tx() *Tx {
  160. return &Tx{
  161. TxID: tx.TxID,
  162. FromIdx: tx.FromIdx,
  163. ToIdx: tx.ToIdx,
  164. TokenID: tx.TokenID,
  165. Amount: tx.Amount,
  166. Nonce: tx.Nonce,
  167. Fee: tx.Fee,
  168. Type: tx.Type,
  169. }
  170. }
  171. // PoolL2TxState is a struct that represents the status of a L2 transaction
  172. type PoolL2TxState string
  173. const (
  174. // PoolL2TxStatePending represents a valid L2Tx that hasn't started the forging process
  175. PoolL2TxStatePending PoolL2TxState = "pend"
  176. // PoolL2TxStateForging represents a valid L2Tx that has started the forging process
  177. PoolL2TxStateForging PoolL2TxState = "fing"
  178. // PoolL2TxStateForged represents a L2Tx that has already been forged
  179. PoolL2TxStateForged PoolL2TxState = "fged"
  180. // PoolL2TxStateInvalid represents a L2Tx that has been invalidated
  181. PoolL2TxStateInvalid PoolL2TxState = "invl"
  182. )