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.

173 lines
6.5 KiB

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