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.

529 lines
17 KiB

  1. package til
  2. import (
  3. "crypto/ecdsa"
  4. "fmt"
  5. "math/big"
  6. "strconv"
  7. "strings"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. "github.com/iden3/go-iden3-crypto/babyjub"
  14. )
  15. // Context contains the data of the test
  16. type Context struct {
  17. Instructions []instruction
  18. accountsNames []string
  19. Users map[string]*User
  20. lastRegisteredTokenID common.TokenID
  21. l1CreatedAccounts map[string]*Account
  22. // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch
  23. rollupConstMaxL1UserTx int
  24. idx int
  25. currBlock BlockData
  26. currBatch BatchData
  27. currBatchNum int
  28. queues [][]L1Tx
  29. toForgeNum int
  30. openToForge int
  31. }
  32. // NewContext returns a new Context
  33. func NewContext(rollupConstMaxL1UserTx int) *Context {
  34. return &Context{
  35. Users: make(map[string]*User),
  36. l1CreatedAccounts: make(map[string]*Account),
  37. lastRegisteredTokenID: 0,
  38. rollupConstMaxL1UserTx: rollupConstMaxL1UserTx,
  39. idx: common.UserThreshold,
  40. currBatchNum: 0,
  41. // start with 2 queues, one for toForge, and the other for openToForge
  42. queues: make([][]L1Tx, 2),
  43. toForgeNum: 0,
  44. openToForge: 1,
  45. }
  46. }
  47. // Account contains the data related to the account for a specific TokenID of a User
  48. type Account struct {
  49. Idx common.Idx
  50. Nonce common.Nonce
  51. }
  52. // User contains the data related to a testing user
  53. type User struct {
  54. BJJ *babyjub.PrivateKey
  55. Addr ethCommon.Address
  56. Accounts map[common.TokenID]*Account
  57. }
  58. // BlockData contains the information of a Block
  59. type BlockData struct {
  60. // block *common.Block // ethereum block
  61. // L1UserTxs that were accepted in the block
  62. L1UserTxs []common.L1Tx
  63. Batches []BatchData
  64. RegisteredTokens []common.Token
  65. }
  66. // BatchData contains the information of a Batch
  67. type BatchData struct {
  68. L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
  69. L1CoordinatorTxs []common.L1Tx
  70. testL1CoordinatorTxs []L1Tx
  71. L2Txs []common.L2Tx
  72. // testL2Tx are L2Txs without the Idx&EthAddr&BJJ setted, but with the
  73. // string that represents the account
  74. testL2Txs []L2Tx
  75. }
  76. // L1Tx is the data structure used internally for transaction test generation,
  77. // which contains a common.L1Tx data plus some intermediate data for the
  78. // transaction generation.
  79. type L1Tx struct {
  80. lineNum int
  81. fromIdxName string
  82. toIdxName string
  83. L1Tx common.L1Tx
  84. }
  85. // L2Tx is the data structure used internally for transaction test generation,
  86. // which contains a common.L2Tx data plus some intermediate data for the
  87. // transaction generation.
  88. type L2Tx struct {
  89. lineNum int
  90. fromIdxName string
  91. toIdxName string
  92. tokenID common.TokenID
  93. L2Tx common.L2Tx
  94. }
  95. // GenerateBlocks returns an array of BlockData for a given set. It uses the
  96. // accounts (keys & nonces) of the Context.
  97. func (tc *Context) GenerateBlocks(set string) ([]BlockData, error) {
  98. parser := newParser(strings.NewReader(set))
  99. parsedSet, err := parser.parse()
  100. if err != nil {
  101. return nil, err
  102. }
  103. tc.Instructions = parsedSet.instructions
  104. tc.accountsNames = parsedSet.accounts
  105. tc.generateKeys(tc.accountsNames)
  106. var blocks []BlockData
  107. for _, inst := range parsedSet.instructions {
  108. switch inst.typ {
  109. case txTypeCreateAccountDepositCoordinator:
  110. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  111. log.Error(err)
  112. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  113. }
  114. tx := common.L1Tx{
  115. FromEthAddr: tc.Users[inst.from].Addr,
  116. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  117. TokenID: inst.tokenID,
  118. LoadAmount: big.NewInt(int64(inst.loadAmount)),
  119. Type: common.TxTypeCreateAccountDeposit, // as txTypeCreateAccountDepositCoordinator is not valid oustide Til package
  120. }
  121. testTx := L1Tx{
  122. lineNum: inst.lineNum,
  123. fromIdxName: inst.from,
  124. L1Tx: tx,
  125. }
  126. tc.currBatch.testL1CoordinatorTxs = append(tc.currBatch.testL1CoordinatorTxs, testTx)
  127. case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer:
  128. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  129. log.Error(err)
  130. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  131. }
  132. tx := common.L1Tx{
  133. FromEthAddr: tc.Users[inst.from].Addr,
  134. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  135. TokenID: inst.tokenID,
  136. LoadAmount: big.NewInt(int64(inst.loadAmount)),
  137. Type: inst.typ,
  138. }
  139. if inst.typ == common.TxTypeCreateAccountDepositTransfer {
  140. tx.Amount = big.NewInt(int64(inst.amount))
  141. }
  142. testTx := L1Tx{
  143. lineNum: inst.lineNum,
  144. fromIdxName: inst.from,
  145. toIdxName: inst.to,
  146. L1Tx: tx,
  147. }
  148. tc.addToL1Queue(testTx)
  149. case common.TxTypeDeposit, common.TxTypeDepositTransfer:
  150. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  151. log.Error(err)
  152. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  153. }
  154. if err := tc.checkIfAccountExists(inst.from, inst); err != nil {
  155. log.Error(err)
  156. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  157. }
  158. tx := common.L1Tx{
  159. TokenID: inst.tokenID,
  160. LoadAmount: big.NewInt(int64(inst.loadAmount)),
  161. Type: inst.typ,
  162. }
  163. if inst.typ == common.TxTypeDepositTransfer {
  164. tx.Amount = big.NewInt(int64(inst.amount))
  165. }
  166. testTx := L1Tx{
  167. lineNum: inst.lineNum,
  168. fromIdxName: inst.from,
  169. toIdxName: inst.to,
  170. L1Tx: tx,
  171. }
  172. tc.addToL1Queue(testTx)
  173. case common.TxTypeTransfer:
  174. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  175. log.Error(err)
  176. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  177. }
  178. tx := common.L2Tx{
  179. Amount: big.NewInt(int64(inst.amount)),
  180. Fee: common.FeeSelector(inst.fee),
  181. Type: common.TxTypeTransfer,
  182. }
  183. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  184. testTx := L2Tx{
  185. lineNum: inst.lineNum,
  186. fromIdxName: inst.from,
  187. toIdxName: inst.to,
  188. tokenID: inst.tokenID,
  189. L2Tx: tx,
  190. }
  191. tc.currBatch.testL2Txs = append(tc.currBatch.testL2Txs, testTx)
  192. case common.TxTypeExit:
  193. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  194. log.Error(err)
  195. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  196. }
  197. tx := common.L2Tx{
  198. ToIdx: common.Idx(1), // as is an Exit
  199. Amount: big.NewInt(int64(inst.amount)),
  200. Type: common.TxTypeExit,
  201. }
  202. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  203. testTx := L2Tx{
  204. lineNum: inst.lineNum,
  205. fromIdxName: inst.from,
  206. toIdxName: inst.to,
  207. tokenID: inst.tokenID,
  208. L2Tx: tx,
  209. }
  210. tc.currBatch.testL2Txs = append(tc.currBatch.testL2Txs, testTx)
  211. case common.TxTypeForceExit:
  212. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  213. log.Error(err)
  214. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  215. }
  216. tx := common.L1Tx{
  217. ToIdx: common.Idx(1), // as is an Exit
  218. TokenID: inst.tokenID,
  219. Amount: big.NewInt(int64(inst.amount)),
  220. Type: common.TxTypeExit,
  221. }
  222. testTx := L1Tx{
  223. lineNum: inst.lineNum,
  224. fromIdxName: inst.from,
  225. toIdxName: inst.to,
  226. L1Tx: tx,
  227. }
  228. tc.addToL1Queue(testTx)
  229. case typeNewBatch:
  230. if err = tc.calculateIdxForL1Txs(true, tc.currBatch.testL1CoordinatorTxs); err != nil {
  231. return nil, err
  232. }
  233. if err = tc.setIdxs(); err != nil {
  234. log.Error(err)
  235. return nil, err
  236. }
  237. case typeNewBatchL1:
  238. // for each L1UserTx of the queues[ToForgeNum], calculate the Idx
  239. if err = tc.calculateIdxForL1Txs(false, tc.queues[tc.toForgeNum]); err != nil {
  240. return nil, err
  241. }
  242. if err = tc.calculateIdxForL1Txs(true, tc.currBatch.testL1CoordinatorTxs); err != nil {
  243. return nil, err
  244. }
  245. // once Idxs are calculated, update transactions to use the real Idxs
  246. for i := 0; i < len(tc.queues[tc.toForgeNum]); i++ {
  247. testTx := &tc.queues[tc.toForgeNum][i]
  248. if testTx.L1Tx.Type != common.TxTypeCreateAccountDeposit && testTx.L1Tx.Type != common.TxTypeCreateAccountDepositTransfer {
  249. testTx.L1Tx.FromIdx = tc.Users[testTx.fromIdxName].Accounts[testTx.L1Tx.TokenID].Idx
  250. }
  251. testTx.L1Tx.FromEthAddr = tc.Users[testTx.fromIdxName].Addr
  252. testTx.L1Tx.FromBJJ = tc.Users[testTx.fromIdxName].BJJ.Public()
  253. if testTx.toIdxName == "" {
  254. testTx.L1Tx.ToIdx = common.Idx(0)
  255. } else {
  256. testTx.L1Tx.ToIdx = tc.Users[testTx.toIdxName].Accounts[testTx.L1Tx.TokenID].Idx
  257. }
  258. if testTx.L1Tx.Type == common.TxTypeExit {
  259. testTx.L1Tx.ToIdx = common.Idx(1)
  260. }
  261. bn := common.BatchNum(tc.currBatchNum)
  262. testTx.L1Tx.BatchNum = &bn
  263. nTx, err := common.NewL1Tx(&testTx.L1Tx)
  264. if err != nil {
  265. fmt.Println(testTx)
  266. return nil, fmt.Errorf("Line %d: %s", testTx.lineNum, err.Error())
  267. }
  268. testTx.L1Tx = *nTx
  269. tc.currBlock.L1UserTxs = append(tc.currBlock.L1UserTxs, testTx.L1Tx)
  270. }
  271. if err = tc.setIdxs(); err != nil {
  272. log.Error(err)
  273. return nil, err
  274. }
  275. // advance batch
  276. tc.toForgeNum++
  277. if tc.toForgeNum == tc.openToForge {
  278. tc.openToForge++
  279. newQueue := []L1Tx{}
  280. tc.queues = append(tc.queues, newQueue)
  281. }
  282. case typeNewBlock:
  283. blocks = append(blocks, tc.currBlock)
  284. tc.currBlock = BlockData{}
  285. case typeRegisterToken:
  286. newToken := common.Token{
  287. TokenID: inst.tokenID,
  288. EthBlockNum: int64(len(blocks)),
  289. }
  290. if inst.tokenID != tc.lastRegisteredTokenID+1 {
  291. return nil, fmt.Errorf("Line %d: RegisterToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", inst.lineNum, tc.lastRegisteredTokenID+1, inst.tokenID)
  292. }
  293. tc.lastRegisteredTokenID++
  294. tc.currBlock.RegisteredTokens = append(tc.currBlock.RegisteredTokens, newToken)
  295. default:
  296. return nil, fmt.Errorf("Line %d: Unexpected type: %s", inst.lineNum, inst.typ)
  297. }
  298. }
  299. return blocks, nil
  300. }
  301. // calculateIdxsForL1Txs calculates new Idx for new created accounts. If
  302. // 'isCoordinatorTxs==true', adds the tx to tc.currBatch.L1CoordinatorTxs.
  303. func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error {
  304. // for each batch.L1CoordinatorTxs of the queues[ToForgeNum], calculate the Idx
  305. for i := 0; i < len(txs); i++ {
  306. tx := txs[i]
  307. if tx.L1Tx.Type == common.TxTypeCreateAccountDeposit || tx.L1Tx.Type == common.TxTypeCreateAccountDepositTransfer {
  308. if tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] != nil { // if account already exists, return error
  309. return fmt.Errorf("Can not create same account twice (same User & same TokenID) (this is a design property of Til)")
  310. }
  311. tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{
  312. Idx: common.Idx(tc.idx),
  313. Nonce: common.Nonce(0),
  314. }
  315. tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
  316. tc.idx++
  317. }
  318. if isCoordinatorTxs {
  319. tc.currBatch.L1CoordinatorTxs = append(tc.currBatch.L1CoordinatorTxs, tx.L1Tx)
  320. }
  321. }
  322. return nil
  323. }
  324. // setIdxs sets the Idxs to the transactions of the tc.currBatch
  325. func (tc *Context) setIdxs() error {
  326. // once Idxs are calculated, update transactions to use the new Idxs
  327. for i := 0; i < len(tc.currBatch.testL2Txs); i++ {
  328. testTx := &tc.currBatch.testL2Txs[i]
  329. if tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID] == nil {
  330. return fmt.Errorf("Line %d: %s from User %s for TokenID %d while account not created yet", testTx.lineNum, testTx.L2Tx.Type, testTx.fromIdxName, testTx.tokenID)
  331. }
  332. if testTx.L2Tx.Type == common.TxTypeTransfer {
  333. if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(testTx.toIdxName, testTx.tokenID)]; !ok {
  334. return fmt.Errorf("Line %d: Can not create Transfer for a non existing account. Batch %d, ToIdx name: %s, TokenID: %d", testTx.lineNum, tc.currBatchNum, testTx.toIdxName, testTx.tokenID)
  335. }
  336. }
  337. tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce++
  338. testTx.L2Tx.Nonce = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce
  339. // set real Idx
  340. testTx.L2Tx.FromIdx = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Idx
  341. if testTx.L2Tx.Type == common.TxTypeTransfer {
  342. testTx.L2Tx.ToIdx = tc.Users[testTx.toIdxName].Accounts[testTx.tokenID].Idx
  343. }
  344. // in case Type==Exit, ToIdx=1, already set at the
  345. // GenerateBlocks main switch inside TxTypeExit case
  346. nTx, err := common.NewL2Tx(&testTx.L2Tx)
  347. if err != nil {
  348. return fmt.Errorf("Line %d: %s", testTx.lineNum, err.Error())
  349. }
  350. testTx.L2Tx = *nTx
  351. tc.currBatch.L2Txs = append(tc.currBatch.L2Txs, testTx.L2Tx)
  352. }
  353. tc.currBlock.Batches = append(tc.currBlock.Batches, tc.currBatch)
  354. tc.currBatchNum++
  355. tc.currBatch = BatchData{}
  356. return nil
  357. }
  358. // addToL1Queue adds the L1Tx into the queue that is open and has space
  359. func (tc *Context) addToL1Queue(tx L1Tx) {
  360. if len(tc.queues[tc.openToForge]) >= tc.rollupConstMaxL1UserTx {
  361. // if current OpenToForge queue reached its Max, move into a
  362. // new queue
  363. tc.openToForge++
  364. newQueue := []L1Tx{}
  365. tc.queues = append(tc.queues, newQueue)
  366. }
  367. tc.queues[tc.openToForge] = append(tc.queues[tc.openToForge], tx)
  368. }
  369. func (tc *Context) checkIfAccountExists(tf string, inst instruction) error {
  370. if tc.Users[tf].Accounts[inst.tokenID] == nil {
  371. return fmt.Errorf("%s at User: %s, for TokenID: %d, while account not created yet", inst.typ, tf, inst.tokenID)
  372. }
  373. return nil
  374. }
  375. func (tc *Context) checkIfTokenIsRegistered(inst instruction) error {
  376. if inst.tokenID > tc.lastRegisteredTokenID {
  377. return fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.lastRegisteredTokenID)
  378. }
  379. return nil
  380. }
  381. // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It
  382. // uses the accounts (keys & nonces) of the Context.
  383. func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
  384. parser := newParser(strings.NewReader(set))
  385. parsedSet, err := parser.parse()
  386. if err != nil {
  387. return nil, err
  388. }
  389. tc.Instructions = parsedSet.instructions
  390. tc.accountsNames = parsedSet.accounts
  391. tc.generateKeys(tc.accountsNames)
  392. txs := []common.PoolL2Tx{}
  393. for _, inst := range tc.Instructions {
  394. switch inst.typ {
  395. case common.TxTypeTransfer:
  396. if err := tc.checkIfAccountExists(inst.from, inst); err != nil {
  397. log.Error(err)
  398. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  399. }
  400. if err := tc.checkIfAccountExists(inst.to, inst); err != nil {
  401. log.Error(err)
  402. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  403. }
  404. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  405. // if account of receiver does not exist, don't use
  406. // ToIdx, and use only ToEthAddr & ToBJJ
  407. tx := common.PoolL2Tx{
  408. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  409. ToIdx: tc.Users[inst.to].Accounts[inst.tokenID].Idx,
  410. ToEthAddr: tc.Users[inst.to].Addr,
  411. ToBJJ: tc.Users[inst.to].BJJ.Public(),
  412. TokenID: inst.tokenID,
  413. Amount: big.NewInt(int64(inst.amount)),
  414. Fee: common.FeeSelector(inst.fee),
  415. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  416. State: common.PoolL2TxStatePending,
  417. Timestamp: time.Now(),
  418. RqToEthAddr: common.EmptyAddr,
  419. RqToBJJ: nil,
  420. Type: common.TxTypeTransfer,
  421. }
  422. nTx, err := common.NewPoolL2Tx(&tx)
  423. if err != nil {
  424. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  425. }
  426. tx = *nTx
  427. // perform signature and set it to tx.Signature
  428. toSign, err := tx.HashToSign()
  429. if err != nil {
  430. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  431. }
  432. sig := tc.Users[inst.from].BJJ.SignPoseidon(toSign)
  433. tx.Signature = sig.Compress()
  434. txs = append(txs, tx)
  435. case common.TxTypeExit:
  436. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  437. tx := common.PoolL2Tx{
  438. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  439. ToIdx: common.Idx(1), // as is an Exit
  440. TokenID: inst.tokenID,
  441. Amount: big.NewInt(int64(inst.amount)),
  442. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  443. Type: common.TxTypeExit,
  444. }
  445. nTx, err := common.NewPoolL2Tx(&tx)
  446. if err != nil {
  447. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  448. }
  449. tx = *nTx
  450. // perform signature and set it to tx.Signature
  451. toSign, err := tx.HashToSign()
  452. if err != nil {
  453. return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
  454. }
  455. sig := tc.Users[inst.from].BJJ.SignPoseidon(toSign)
  456. tx.Signature = sig.Compress()
  457. txs = append(txs, tx)
  458. default:
  459. return nil, fmt.Errorf("Line %d: instruction type unrecognized: %s", inst.lineNum, inst.typ)
  460. }
  461. }
  462. return txs, nil
  463. }
  464. // generateKeys generates BabyJubJub & Address keys for the given list of
  465. // account names in a deterministic way. This means, that for the same given
  466. // 'accNames' in a certain order, the keys will be always the same.
  467. func (tc *Context) generateKeys(accNames []string) {
  468. for i := 1; i < len(accNames)+1; i++ {
  469. if _, ok := tc.Users[accNames[i-1]]; ok {
  470. // account already created
  471. continue
  472. }
  473. // babyjubjub key
  474. var sk babyjub.PrivateKey
  475. copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
  476. // eth address
  477. var key ecdsa.PrivateKey
  478. key.D = big.NewInt(int64(i)) // only for testing
  479. key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
  480. key.Curve = ethCrypto.S256()
  481. addr := ethCrypto.PubkeyToAddress(key.PublicKey)
  482. u := User{
  483. BJJ: &sk,
  484. Addr: addr,
  485. Accounts: make(map[common.TokenID]*Account),
  486. }
  487. tc.Users[accNames[i-1]] = &u
  488. }
  489. }