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.

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