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.

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