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.

407 lines
12 KiB

  1. package common
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "time"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/tracerr"
  10. "github.com/iden3/go-iden3-crypto/babyjub"
  11. "github.com/iden3/go-iden3-crypto/poseidon"
  12. )
  13. // EmptyBJJComp contains the 32 byte array of a empty BabyJubJub PublicKey
  14. // Compressed. It is a valid point in the BabyJubJub curve, so does not give
  15. // errors when being decompressed.
  16. var EmptyBJJComp = babyjub.PublicKeyComp([32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
  17. // PoolL2Tx is a struct that represents a L2Tx sent by an account to the
  18. // coordinator that is waiting to be forged
  19. type PoolL2Tx struct {
  20. // Stored in DB: mandatory fileds
  21. // TxID (12 bytes) for L2Tx is:
  22. // bytes: | 1 | 6 | 5 |
  23. // values: | type | FromIdx | Nonce |
  24. TxID TxID `meddler:"tx_id"`
  25. FromIdx Idx `meddler:"from_idx"`
  26. ToIdx Idx `meddler:"to_idx,zeroisnull"`
  27. // AuxToIdx is only used internally at the StateDB to avoid repeated
  28. // computation when processing transactions (from Synchronizer,
  29. // TxSelector, BatchBuilder)
  30. AuxToIdx Idx `meddler:"-"`
  31. ToEthAddr ethCommon.Address `meddler:"to_eth_addr,zeroisnull"`
  32. ToBJJ babyjub.PublicKeyComp `meddler:"to_bjj,zeroisnull"`
  33. TokenID TokenID `meddler:"token_id"`
  34. Amount *big.Int `meddler:"amount,bigint"`
  35. Fee FeeSelector `meddler:"fee"`
  36. Nonce Nonce `meddler:"nonce"` // effective 40 bits used
  37. State PoolL2TxState `meddler:"state"`
  38. // Info contains information about the status & State of the
  39. // transaction. As for example, if the Tx has not been selected in the
  40. // last batch due not enough Balance at the Sender account, this reason
  41. // would appear at this parameter.
  42. Info string `meddler:"info,zeroisnull"`
  43. Signature babyjub.SignatureComp `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. RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"`
  47. RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"`
  48. RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr,zeroisnull"`
  49. RqToBJJ babyjub.PublicKeyComp `meddler:"rq_to_bjj,zeroisnull"`
  50. RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
  51. RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
  52. RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
  53. RqNonce Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
  54. AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"`
  55. AbsoluteFeeUpdate time.Time `meddler:"usd_update,utctimez"`
  56. Type TxType `meddler:"tx_type"`
  57. // Extra metadata, may be uninitialized
  58. RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
  59. }
  60. // NewPoolL2Tx returns the given L2Tx with the TxId & Type parameters calculated
  61. // from the L2Tx values
  62. func NewPoolL2Tx(tx *PoolL2Tx) (*PoolL2Tx, error) {
  63. txTypeOld := tx.Type
  64. if err := tx.SetType(); err != nil {
  65. return nil, tracerr.Wrap(err)
  66. }
  67. // If original Type doesn't match the correct one, return error
  68. if txTypeOld != "" && txTypeOld != tx.Type {
  69. return nil, tracerr.Wrap(fmt.Errorf("L2Tx.Type: %s, should be: %s",
  70. tx.Type, txTypeOld))
  71. }
  72. txIDOld := tx.TxID
  73. if err := tx.SetID(); err != nil {
  74. return nil, tracerr.Wrap(err)
  75. }
  76. // If original TxID doesn't match the correct one, return error
  77. if txIDOld != (TxID{}) && txIDOld != tx.TxID {
  78. return tx, tracerr.Wrap(fmt.Errorf("PoolL2Tx.TxID: %s, should be: %s",
  79. tx.TxID.String(), txIDOld.String()))
  80. }
  81. return tx, nil
  82. }
  83. // SetType sets the type of the transaction
  84. func (tx *PoolL2Tx) SetType() error {
  85. if tx.ToIdx >= IdxUserThreshold {
  86. tx.Type = TxTypeTransfer
  87. } else if tx.ToIdx == 1 {
  88. tx.Type = TxTypeExit
  89. } else if tx.ToIdx == 0 {
  90. if tx.ToBJJ != EmptyBJJComp && tx.ToEthAddr == FFAddr {
  91. tx.Type = TxTypeTransferToBJJ
  92. } else if tx.ToEthAddr != FFAddr && tx.ToEthAddr != EmptyAddr {
  93. tx.Type = TxTypeTransferToEthAddr
  94. }
  95. } else {
  96. return tracerr.Wrap(errors.New("malformed transaction"))
  97. }
  98. return nil
  99. }
  100. // SetID sets the ID of the transaction
  101. func (tx *PoolL2Tx) SetID() error {
  102. txID, err := tx.L2Tx().CalculateTxID()
  103. if err != nil {
  104. return tracerr.Wrap(err)
  105. }
  106. tx.TxID = txID
  107. return nil
  108. }
  109. // TxCompressedData spec:
  110. // [ 1 bits ] toBJJSign // 1 byte
  111. // [ 8 bits ] userFee // 1 byte
  112. // [ 40 bits ] nonce // 5 bytes
  113. // [ 32 bits ] tokenID // 4 bytes
  114. // [ 48 bits ] toIdx // 6 bytes
  115. // [ 48 bits ] fromIdx // 6 bytes
  116. // [ 16 bits ] chainId // 2 bytes
  117. // [ 32 bits ] signatureConstant // 4 bytes
  118. // Total bits compressed data: 225 bits // 29 bytes in *big.Int representation
  119. func (tx *PoolL2Tx) TxCompressedData(chainID uint16) (*big.Int, error) {
  120. var b [29]byte
  121. toBJJSign := byte(0)
  122. pkSign, _ := babyjub.UnpackSignY(tx.ToBJJ)
  123. if pkSign {
  124. toBJJSign = byte(1)
  125. }
  126. b[0] = toBJJSign
  127. b[1] = byte(tx.Fee)
  128. nonceBytes, err := tx.Nonce.Bytes()
  129. if err != nil {
  130. return nil, tracerr.Wrap(err)
  131. }
  132. copy(b[2:7], nonceBytes[:])
  133. copy(b[7:11], tx.TokenID.Bytes())
  134. toIdxBytes, err := tx.ToIdx.Bytes()
  135. if err != nil {
  136. return nil, tracerr.Wrap(err)
  137. }
  138. copy(b[11:17], toIdxBytes[:])
  139. fromIdxBytes, err := tx.FromIdx.Bytes()
  140. if err != nil {
  141. return nil, tracerr.Wrap(err)
  142. }
  143. copy(b[17:23], fromIdxBytes[:])
  144. binary.BigEndian.PutUint16(b[23:25], chainID)
  145. copy(b[25:29], SignatureConstantBytes[:])
  146. bi := new(big.Int).SetBytes(b[:])
  147. return bi, nil
  148. }
  149. // TxCompressedDataEmpty calculates the TxCompressedData of an empty
  150. // transaction
  151. func TxCompressedDataEmpty(chainID uint16) *big.Int {
  152. var b [29]byte
  153. binary.BigEndian.PutUint16(b[23:25], chainID)
  154. copy(b[25:29], SignatureConstantBytes[:])
  155. bi := new(big.Int).SetBytes(b[:])
  156. return bi
  157. }
  158. // TxCompressedDataV2 spec:
  159. // [ 1 bits ] toBJJSign // 1 byte
  160. // [ 8 bits ] userFee // 1 byte
  161. // [ 40 bits ] nonce // 5 bytes
  162. // [ 32 bits ] tokenID // 4 bytes
  163. // [ 40 bits ] amountFloat40 // 5 bytes
  164. // [ 48 bits ] toIdx // 6 bytes
  165. // [ 48 bits ] fromIdx // 6 bytes
  166. // Total bits compressed data: 217 bits // 28 bytes in *big.Int representation
  167. func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
  168. if tx.Amount == nil {
  169. tx.Amount = big.NewInt(0)
  170. }
  171. amountFloat40, err := NewFloat40(tx.Amount)
  172. if err != nil {
  173. return nil, tracerr.Wrap(err)
  174. }
  175. amountFloat40Bytes, err := amountFloat40.Bytes()
  176. if err != nil {
  177. return nil, tracerr.Wrap(err)
  178. }
  179. var b [28]byte
  180. toBJJSign := byte(0)
  181. if tx.ToBJJ != EmptyBJJComp {
  182. sign, _ := babyjub.UnpackSignY(tx.ToBJJ)
  183. if sign {
  184. toBJJSign = byte(1)
  185. }
  186. }
  187. b[0] = toBJJSign
  188. b[1] = byte(tx.Fee)
  189. nonceBytes, err := tx.Nonce.Bytes()
  190. if err != nil {
  191. return nil, tracerr.Wrap(err)
  192. }
  193. copy(b[2:7], nonceBytes[:])
  194. copy(b[7:11], tx.TokenID.Bytes())
  195. copy(b[11:16], amountFloat40Bytes)
  196. toIdxBytes, err := tx.ToIdx.Bytes()
  197. if err != nil {
  198. return nil, tracerr.Wrap(err)
  199. }
  200. copy(b[16:22], toIdxBytes[:])
  201. fromIdxBytes, err := tx.FromIdx.Bytes()
  202. if err != nil {
  203. return nil, tracerr.Wrap(err)
  204. }
  205. copy(b[22:28], fromIdxBytes[:])
  206. bi := new(big.Int).SetBytes(b[:])
  207. return bi, nil
  208. }
  209. // RqTxCompressedDataV2 is like the TxCompressedDataV2 but using the 'Rq'
  210. // parameters. In a future iteration of the hermez-node, the 'Rq' parameters
  211. // can be inside a struct, which contains the 'Rq' transaction grouped inside,
  212. // so then computing the 'RqTxCompressedDataV2' would be just calling
  213. // 'tx.Rq.TxCompressedDataV2()'.
  214. // RqTxCompressedDataV2 spec:
  215. // [ 1 bits ] rqToBJJSign // 1 byte
  216. // [ 8 bits ] rqUserFee // 1 byte
  217. // [ 40 bits ] rqNonce // 5 bytes
  218. // [ 32 bits ] rqTokenID // 4 bytes
  219. // [ 40 bits ] rqAmountFloat40 // 5 bytes
  220. // [ 48 bits ] rqToIdx // 6 bytes
  221. // [ 48 bits ] rqFromIdx // 6 bytes
  222. // Total bits compressed data: 217 bits // 28 bytes in *big.Int representation
  223. func (tx *PoolL2Tx) RqTxCompressedDataV2() (*big.Int, error) {
  224. if tx.RqAmount == nil {
  225. tx.RqAmount = big.NewInt(0)
  226. }
  227. amountFloat40, err := NewFloat40(tx.RqAmount)
  228. if err != nil {
  229. return nil, tracerr.Wrap(err)
  230. }
  231. amountFloat40Bytes, err := amountFloat40.Bytes()
  232. if err != nil {
  233. return nil, tracerr.Wrap(err)
  234. }
  235. var b [28]byte
  236. rqToBJJSign := byte(0)
  237. if tx.RqToBJJ != EmptyBJJComp {
  238. sign, _ := babyjub.UnpackSignY(tx.RqToBJJ)
  239. if sign {
  240. rqToBJJSign = byte(1)
  241. }
  242. }
  243. b[0] = rqToBJJSign
  244. b[1] = byte(tx.RqFee)
  245. nonceBytes, err := tx.RqNonce.Bytes()
  246. if err != nil {
  247. return nil, tracerr.Wrap(err)
  248. }
  249. copy(b[2:7], nonceBytes[:])
  250. copy(b[7:11], tx.RqTokenID.Bytes())
  251. copy(b[11:16], amountFloat40Bytes)
  252. toIdxBytes, err := tx.RqToIdx.Bytes()
  253. if err != nil {
  254. return nil, tracerr.Wrap(err)
  255. }
  256. copy(b[16:22], toIdxBytes[:])
  257. fromIdxBytes, err := tx.RqFromIdx.Bytes()
  258. if err != nil {
  259. return nil, tracerr.Wrap(err)
  260. }
  261. copy(b[22:28], fromIdxBytes[:])
  262. bi := new(big.Int).SetBytes(b[:])
  263. return bi, nil
  264. }
  265. // HashToSign returns the computed Poseidon hash from the *PoolL2Tx that will
  266. // be signed by the sender.
  267. func (tx *PoolL2Tx) HashToSign(chainID uint16) (*big.Int, error) {
  268. toCompressedData, err := tx.TxCompressedData(chainID)
  269. if err != nil {
  270. return nil, tracerr.Wrap(err)
  271. }
  272. // e1: [5 bytes AmountFloat40 | 20 bytes ToEthAddr]
  273. var e1B [25]byte
  274. amountFloat40, err := NewFloat40(tx.Amount)
  275. if err != nil {
  276. return nil, tracerr.Wrap(err)
  277. }
  278. amountFloat40Bytes, err := amountFloat40.Bytes()
  279. if err != nil {
  280. return nil, tracerr.Wrap(err)
  281. }
  282. copy(e1B[0:5], amountFloat40Bytes)
  283. toEthAddr := EthAddrToBigInt(tx.ToEthAddr)
  284. copy(e1B[5:25], toEthAddr.Bytes())
  285. e1 := new(big.Int).SetBytes(e1B[:])
  286. rqToEthAddr := EthAddrToBigInt(tx.RqToEthAddr)
  287. _, toBJJY := babyjub.UnpackSignY(tx.ToBJJ)
  288. rqTxCompressedDataV2, err := tx.RqTxCompressedDataV2()
  289. if err != nil {
  290. return nil, tracerr.Wrap(err)
  291. }
  292. _, rqToBJJY := babyjub.UnpackSignY(tx.RqToBJJ)
  293. return poseidon.Hash([]*big.Int{toCompressedData, e1, toBJJY, rqTxCompressedDataV2, rqToEthAddr, rqToBJJY})
  294. }
  295. // VerifySignature returns true if the signature verification is correct for the given PublicKeyComp
  296. func (tx *PoolL2Tx) VerifySignature(chainID uint16, pkComp babyjub.PublicKeyComp) bool {
  297. h, err := tx.HashToSign(chainID)
  298. if err != nil {
  299. return false
  300. }
  301. s, err := tx.Signature.Decompress()
  302. if err != nil {
  303. return false
  304. }
  305. pk, err := pkComp.Decompress()
  306. if err != nil {
  307. return false
  308. }
  309. return pk.VerifyPoseidon(h, s)
  310. }
  311. // L2Tx returns a *L2Tx from the PoolL2Tx
  312. func (tx PoolL2Tx) L2Tx() L2Tx {
  313. var toIdx Idx
  314. if tx.ToIdx == Idx(0) {
  315. toIdx = tx.AuxToIdx
  316. } else {
  317. toIdx = tx.ToIdx
  318. }
  319. return L2Tx{
  320. TxID: tx.TxID,
  321. FromIdx: tx.FromIdx,
  322. ToIdx: toIdx,
  323. TokenID: tx.TokenID,
  324. Amount: tx.Amount,
  325. Fee: tx.Fee,
  326. Nonce: tx.Nonce,
  327. Type: tx.Type,
  328. }
  329. }
  330. // Tx returns a *Tx from the PoolL2Tx
  331. func (tx PoolL2Tx) Tx() Tx {
  332. return Tx{
  333. TxID: tx.TxID,
  334. FromIdx: tx.FromIdx,
  335. ToIdx: tx.ToIdx,
  336. Amount: tx.Amount,
  337. TokenID: tx.TokenID,
  338. Nonce: &tx.Nonce,
  339. Fee: &tx.Fee,
  340. Type: tx.Type,
  341. }
  342. }
  343. // PoolL2TxsToL2Txs returns an array of []L2Tx from an array of []PoolL2Tx
  344. func PoolL2TxsToL2Txs(txs []PoolL2Tx) ([]L2Tx, error) {
  345. l2Txs := make([]L2Tx, len(txs))
  346. for i, poolTx := range txs {
  347. l2Txs[i] = poolTx.L2Tx()
  348. }
  349. return l2Txs, nil
  350. }
  351. // TxIDsFromPoolL2Txs returns an array of TxID from the []PoolL2Tx
  352. func TxIDsFromPoolL2Txs(txs []PoolL2Tx) []TxID {
  353. txIDs := make([]TxID, len(txs))
  354. for i, tx := range txs {
  355. txIDs[i] = tx.TxID
  356. }
  357. return txIDs
  358. }
  359. // PoolL2TxState is a string that represents the status of a L2 transaction
  360. type PoolL2TxState string
  361. const (
  362. // PoolL2TxStatePending represents a valid L2Tx that hasn't started the
  363. // forging process
  364. PoolL2TxStatePending PoolL2TxState = "pend"
  365. // PoolL2TxStateForging represents a valid L2Tx that has started the
  366. // forging process
  367. PoolL2TxStateForging PoolL2TxState = "fing"
  368. // PoolL2TxStateForged represents a L2Tx that has already been forged
  369. PoolL2TxStateForged PoolL2TxState = "fged"
  370. // PoolL2TxStateInvalid represents a L2Tx that has been invalidated
  371. PoolL2TxStateInvalid PoolL2TxState = "invl"
  372. )