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.

383 lines
12 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package common
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math/big"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. "github.com/ethereum/go-ethereum/crypto"
  8. "github.com/iden3/go-iden3-crypto/babyjub"
  9. )
  10. const (
  11. // L1UserTxBytesLen is the length of the byte array that represents the L1Tx
  12. L1UserTxBytesLen = 72
  13. // L1CoordinatorTxBytesLen is the length of the byte array that represents the L1CoordinatorTx
  14. L1CoordinatorTxBytesLen = 101
  15. )
  16. // L1Tx is a struct that represents a L1 tx
  17. type L1Tx struct {
  18. // Stored in DB: mandatory fileds
  19. // TxID (12 bytes) for L1Tx is:
  20. // bytes: | 1 | 8 | 2 | 1 |
  21. // values: | type | ToForgeL1TxsNum | Position | 0 (padding) |
  22. // where type:
  23. // - L1UserTx: 0
  24. // - L1CoordinatorTx: 1
  25. TxID TxID `meddler:"id"`
  26. ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
  27. Position int `meddler:"position"`
  28. UserOrigin bool `meddler:"user_origin"` // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
  29. FromIdx Idx `meddler:"from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
  30. FromEthAddr ethCommon.Address `meddler:"from_eth_addr,zeroisnull"`
  31. FromBJJ *babyjub.PublicKey `meddler:"from_bjj,zeroisnull"`
  32. ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
  33. TokenID TokenID `meddler:"token_id"`
  34. Amount *big.Int `meddler:"amount,bigint"`
  35. // EffectiveAmount only applies to L1UserTx.
  36. EffectiveAmount *big.Int `meddler:"effective_amount,bigintnull"`
  37. LoadAmount *big.Int `meddler:"load_amount,bigint"`
  38. // EffectiveLoadAmount only applies to L1UserTx.
  39. EffectiveLoadAmount *big.Int `meddler:"effective_load_amount,bigintnull"`
  40. EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
  41. Type TxType `meddler:"type"`
  42. BatchNum *BatchNum `meddler:"batch_num"`
  43. }
  44. // NewL1Tx returns the given L1Tx with the TxId & Type parameters calculated
  45. // from the L1Tx values
  46. func NewL1Tx(l1Tx *L1Tx) (*L1Tx, error) {
  47. // calculate TxType
  48. var txType TxType
  49. if l1Tx.FromIdx == 0 {
  50. if l1Tx.ToIdx == Idx(0) {
  51. txType = TxTypeCreateAccountDeposit
  52. } else if l1Tx.ToIdx >= IdxUserThreshold {
  53. txType = TxTypeCreateAccountDepositTransfer
  54. } else {
  55. return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)
  56. }
  57. } else if l1Tx.FromIdx >= IdxUserThreshold {
  58. if l1Tx.ToIdx == Idx(0) {
  59. txType = TxTypeDeposit
  60. } else if l1Tx.ToIdx == Idx(1) {
  61. txType = TxTypeForceExit
  62. } else if l1Tx.ToIdx >= IdxUserThreshold {
  63. if l1Tx.LoadAmount.Int64() == int64(0) {
  64. txType = TxTypeForceTransfer
  65. } else {
  66. txType = TxTypeDepositTransfer
  67. }
  68. } else {
  69. return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)
  70. }
  71. } else {
  72. return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid FromIdx value: %d", l1Tx.FromIdx)
  73. }
  74. if l1Tx.Type != "" && l1Tx.Type != txType {
  75. return l1Tx, fmt.Errorf("L1Tx.Type: %s, should be: %s", l1Tx.Type, txType)
  76. }
  77. l1Tx.Type = txType
  78. txID, err := l1Tx.CalcTxID()
  79. if err != nil {
  80. return nil, err
  81. }
  82. l1Tx.TxID = *txID
  83. return l1Tx, nil
  84. }
  85. // CalcTxID calculates the TxId of the L1Tx
  86. func (tx *L1Tx) CalcTxID() (*TxID, error) {
  87. var txID TxID
  88. if tx.UserOrigin {
  89. if tx.ToForgeL1TxsNum == nil {
  90. return nil, fmt.Errorf("L1Tx.UserOrigin == true && L1Tx.ToForgeL1TxsNum == nil")
  91. }
  92. txID[0] = TxIDPrefixL1UserTx
  93. var toForgeL1TxsNumBytes [8]byte
  94. binary.BigEndian.PutUint64(toForgeL1TxsNumBytes[:], uint64(*tx.ToForgeL1TxsNum))
  95. copy(txID[1:9], toForgeL1TxsNumBytes[:])
  96. } else {
  97. if tx.BatchNum == nil {
  98. return nil, fmt.Errorf("L1Tx.UserOrigin == false && L1Tx.BatchNum == nil")
  99. }
  100. txID[0] = TxIDPrefixL1CoordTx
  101. var batchNumBytes [8]byte
  102. binary.BigEndian.PutUint64(batchNumBytes[:], uint64(*tx.BatchNum))
  103. copy(txID[1:9], batchNumBytes[:])
  104. }
  105. var positionBytes [2]byte
  106. binary.BigEndian.PutUint16(positionBytes[:], uint16(tx.Position))
  107. copy(txID[9:11], positionBytes[:])
  108. return &txID, nil
  109. }
  110. // Tx returns a *Tx from the L1Tx
  111. func (tx L1Tx) Tx() Tx {
  112. f := new(big.Float).SetInt(tx.EffectiveAmount)
  113. amountFloat, _ := f.Float64()
  114. userOrigin := new(bool)
  115. *userOrigin = tx.UserOrigin
  116. genericTx := Tx{
  117. IsL1: true,
  118. TxID: tx.TxID,
  119. Type: tx.Type,
  120. Position: tx.Position,
  121. FromIdx: tx.FromIdx,
  122. ToIdx: tx.ToIdx,
  123. Amount: tx.EffectiveAmount,
  124. AmountFloat: amountFloat,
  125. TokenID: tx.TokenID,
  126. ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
  127. UserOrigin: userOrigin,
  128. FromEthAddr: tx.FromEthAddr,
  129. FromBJJ: tx.FromBJJ,
  130. LoadAmount: tx.EffectiveLoadAmount,
  131. EthBlockNum: tx.EthBlockNum,
  132. }
  133. if tx.LoadAmount != nil {
  134. lf := new(big.Float).SetInt(tx.LoadAmount)
  135. loadAmountFloat, _ := lf.Float64()
  136. genericTx.LoadAmountFloat = &loadAmountFloat
  137. }
  138. return genericTx
  139. }
  140. // TxCompressedData spec:
  141. // [ 1 bits ] empty (toBJJSign) // 1 byte
  142. // [ 8 bits ] empty (userFee) // 1 byte
  143. // [ 40 bits ] empty (nonce) // 5 bytes
  144. // [ 32 bits ] tokenID // 4 bytes
  145. // [ 16 bits ] amountFloat16 // 2 bytes
  146. // [ 48 bits ] toIdx // 6 bytes
  147. // [ 48 bits ] fromIdx // 6 bytes
  148. // [ 16 bits ] chainId // 2 bytes
  149. // [ 32 bits ] empty (signatureConstant) // 4 bytes
  150. // Total bits compressed data: 241 bits // 31 bytes in *big.Int representation
  151. func (tx L1Tx) TxCompressedData() (*big.Int, error) {
  152. amountFloat16, err := NewFloat16(tx.Amount)
  153. if err != nil {
  154. return nil, err
  155. }
  156. var b [31]byte
  157. // b[0:7] empty: no fee neither nonce
  158. copy(b[7:11], tx.TokenID.Bytes())
  159. copy(b[11:13], amountFloat16.Bytes())
  160. toIdxBytes, err := tx.ToIdx.Bytes()
  161. if err != nil {
  162. return nil, err
  163. }
  164. copy(b[13:19], toIdxBytes[:])
  165. fromIdxBytes, err := tx.FromIdx.Bytes()
  166. if err != nil {
  167. return nil, err
  168. }
  169. copy(b[19:25], fromIdxBytes[:])
  170. copy(b[25:27], []byte{0, 1}) // TODO this will be generated by the ChainID config parameter
  171. // b[27:] empty: no signature
  172. bi := new(big.Int).SetBytes(b[:])
  173. return bi, nil
  174. }
  175. // BytesDataAvailability encodes a L1Tx into []byte for the Data Availability
  176. func (tx *L1Tx) BytesDataAvailability(nLevels uint32) ([]byte, error) {
  177. idxLen := nLevels / 8 //nolint:gomnd
  178. b := make([]byte, ((nLevels*2)+16+8)/8) //nolint:gomnd
  179. fromIdxBytes, err := tx.FromIdx.Bytes()
  180. if err != nil {
  181. return nil, err
  182. }
  183. copy(b[0:idxLen], fromIdxBytes[6-idxLen:])
  184. toIdxBytes, err := tx.ToIdx.Bytes()
  185. if err != nil {
  186. return nil, err
  187. }
  188. copy(b[idxLen:idxLen*2], toIdxBytes[6-idxLen:])
  189. if tx.EffectiveAmount != nil {
  190. amountFloat16, err := NewFloat16(tx.EffectiveAmount)
  191. if err != nil {
  192. return nil, err
  193. }
  194. copy(b[idxLen*2:idxLen*2+2], amountFloat16.Bytes())
  195. }
  196. // fee = 0 (as is L1Tx) b[10:11]
  197. return b[:], nil
  198. }
  199. // BytesGeneric returns the generic representation of a L1Tx. This method is
  200. // used to compute the []byte representation of a L1UserTx, and also to compute
  201. // the L1TxData for the ZKInputs (at the HashGlobalInputs), using this method
  202. // for L1CoordinatorTxs & L1UserTxs (for the ZKInputs case).
  203. func (tx *L1Tx) BytesGeneric() ([]byte, error) {
  204. var b [L1UserTxBytesLen]byte
  205. copy(b[0:20], tx.FromEthAddr.Bytes())
  206. if tx.FromBJJ != nil {
  207. pkCompL := tx.FromBJJ.Compress()
  208. pkCompB := SwapEndianness(pkCompL[:])
  209. copy(b[20:52], pkCompB[:])
  210. }
  211. fromIdxBytes, err := tx.FromIdx.Bytes()
  212. if err != nil {
  213. return nil, err
  214. }
  215. copy(b[52:58], fromIdxBytes[:])
  216. loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
  217. if err != nil {
  218. return nil, err
  219. }
  220. copy(b[58:60], loadAmountFloat16.Bytes())
  221. amountFloat16, err := NewFloat16(tx.Amount)
  222. if err != nil {
  223. return nil, err
  224. }
  225. copy(b[60:62], amountFloat16.Bytes())
  226. copy(b[62:66], tx.TokenID.Bytes())
  227. toIdxBytes, err := tx.ToIdx.Bytes()
  228. if err != nil {
  229. return nil, err
  230. }
  231. copy(b[66:72], toIdxBytes[:])
  232. return b[:], nil
  233. }
  234. // BytesUser encodes a L1UserTx into []byte
  235. func (tx *L1Tx) BytesUser() ([]byte, error) {
  236. if !tx.UserOrigin {
  237. return nil, fmt.Errorf("Can not calculate BytesUser() for a L1CoordinatorTx")
  238. }
  239. return tx.BytesGeneric()
  240. }
  241. // BytesCoordinatorTx encodes a L1CoordinatorTx into []byte
  242. func (tx *L1Tx) BytesCoordinatorTx(compressedSignatureBytes []byte) ([]byte, error) {
  243. if tx.UserOrigin {
  244. return nil, fmt.Errorf("Can not calculate BytesCoordinatorTx() for a L1UserTx")
  245. }
  246. var b [L1CoordinatorTxBytesLen]byte
  247. v := compressedSignatureBytes[64]
  248. s := compressedSignatureBytes[32:64]
  249. r := compressedSignatureBytes[0:32]
  250. b[0] = v
  251. copy(b[1:33], s)
  252. copy(b[33:65], r)
  253. pkCompL := tx.FromBJJ.Compress()
  254. pkCompB := SwapEndianness(pkCompL[:])
  255. copy(b[65:97], pkCompB[:])
  256. copy(b[97:101], tx.TokenID.Bytes())
  257. return b[:], nil
  258. }
  259. // L1UserTxFromBytes decodes a L1Tx from []byte
  260. func L1UserTxFromBytes(b []byte) (*L1Tx, error) {
  261. if len(b) != L1UserTxBytesLen {
  262. return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
  263. }
  264. tx := &L1Tx{
  265. UserOrigin: true,
  266. }
  267. var err error
  268. tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
  269. pkCompB := b[20:52]
  270. pkCompL := SwapEndianness(pkCompB)
  271. var pkComp babyjub.PublicKeyComp
  272. copy(pkComp[:], pkCompL)
  273. tx.FromBJJ, err = pkComp.Decompress()
  274. if err != nil {
  275. return nil, err
  276. }
  277. fromIdx, err := IdxFromBytes(b[52:58])
  278. if err != nil {
  279. return nil, err
  280. }
  281. tx.FromIdx = fromIdx
  282. tx.LoadAmount = Float16FromBytes(b[58:60]).BigInt()
  283. tx.Amount = Float16FromBytes(b[60:62]).BigInt()
  284. tx.TokenID, err = TokenIDFromBytes(b[62:66])
  285. if err != nil {
  286. return nil, err
  287. }
  288. tx.ToIdx, err = IdxFromBytes(b[66:72])
  289. if err != nil {
  290. return nil, err
  291. }
  292. return tx, nil
  293. }
  294. func signHash(data []byte) []byte {
  295. msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
  296. return crypto.Keccak256([]byte(msg))
  297. }
  298. // L1CoordinatorTxFromBytes decodes a L1Tx from []byte
  299. func L1CoordinatorTxFromBytes(b []byte, chainID *big.Int, hermezAddress ethCommon.Address) (*L1Tx, error) {
  300. if len(b) != L1CoordinatorTxBytesLen {
  301. return nil, fmt.Errorf("Can not parse L1CoordinatorTx bytes, expected length %d, current: %d", 101, len(b))
  302. }
  303. bytesMessage := []byte("I authorize this babyjubjub key for hermez rollup account creation")
  304. tx := &L1Tx{
  305. UserOrigin: false,
  306. }
  307. var err error
  308. v := b[0]
  309. s := b[1:33]
  310. r := b[33:65]
  311. pkCompB := b[65:97]
  312. pkCompL := SwapEndianness(pkCompB)
  313. var pkComp babyjub.PublicKeyComp
  314. copy(pkComp[:], pkCompL)
  315. tx.FromBJJ, err = pkComp.Decompress()
  316. if err != nil {
  317. return nil, err
  318. }
  319. tx.TokenID, err = TokenIDFromBytes(b[97:101])
  320. if err != nil {
  321. return nil, err
  322. }
  323. tx.Amount = big.NewInt(0)
  324. tx.LoadAmount = big.NewInt(0)
  325. if int(v) > 0 {
  326. // L1CoordinatorTX ETH
  327. // Ethereum adds 27 to v
  328. v = b[0] - byte(27) //nolint:gomnd
  329. chainIDBytes := ethCommon.LeftPadBytes(chainID.Bytes(), 2)
  330. var data []byte
  331. data = append(data, bytesMessage...)
  332. data = append(data, pkCompB...)
  333. data = append(data, chainIDBytes[:]...)
  334. data = append(data, hermezAddress.Bytes()...)
  335. var signature []byte
  336. signature = append(signature, r[:]...)
  337. signature = append(signature, s[:]...)
  338. signature = append(signature, v)
  339. hash := signHash(data)
  340. pubKeyBytes, err := crypto.Ecrecover(hash, signature)
  341. if err != nil {
  342. return nil, err
  343. }
  344. pubKey, err := crypto.UnmarshalPubkey(pubKeyBytes)
  345. if err != nil {
  346. return nil, err
  347. }
  348. tx.FromEthAddr = crypto.PubkeyToAddress(*pubKey)
  349. } else {
  350. // L1Coordinator Babyjub
  351. tx.FromEthAddr = RollupConstEthAddressInternalOnly
  352. }
  353. return tx, nil
  354. }