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.

374 lines
14 KiB

  1. package zkproof
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "strconv"
  6. "testing"
  7. "time"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  10. "github.com/hermeznetwork/hermez-node/batchbuilder"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. dbUtils "github.com/hermeznetwork/hermez-node/db"
  13. "github.com/hermeznetwork/hermez-node/db/historydb"
  14. "github.com/hermeznetwork/hermez-node/db/l2db"
  15. "github.com/hermeznetwork/hermez-node/db/statedb"
  16. "github.com/hermeznetwork/hermez-node/log"
  17. "github.com/hermeznetwork/hermez-node/test"
  18. "github.com/hermeznetwork/hermez-node/test/til"
  19. "github.com/hermeznetwork/hermez-node/test/txsets"
  20. "github.com/hermeznetwork/hermez-node/txselector"
  21. "github.com/jmoiron/sqlx"
  22. "github.com/stretchr/testify/assert"
  23. "github.com/stretchr/testify/require"
  24. )
  25. func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
  26. var tokens []common.Token
  27. for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
  28. tokens = append(tokens, common.Token{
  29. TokenID: common.TokenID(i + 1),
  30. EthBlockNum: 1,
  31. EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
  32. Name: strconv.Itoa(i),
  33. Symbol: strconv.Itoa(i),
  34. Decimals: 18,
  35. })
  36. }
  37. hdb := historydb.NewHistoryDB(db, db, nil)
  38. assert.NoError(t, hdb.AddBlock(&common.Block{
  39. Num: 1,
  40. }))
  41. assert.NoError(t, hdb.AddTokens(tokens))
  42. }
  43. func addL2Txs(t *testing.T, l2DB *l2db.L2DB, poolL2Txs []common.PoolL2Tx) {
  44. for i := 0; i < len(poolL2Txs); i++ {
  45. err := l2DB.AddTxTest(&poolL2Txs[i])
  46. if err != nil {
  47. log.Error(err)
  48. }
  49. require.NoError(t, err)
  50. }
  51. }
  52. func addAccCreationAuth(t *testing.T, tc *til.Context, l2DB *l2db.L2DB, chainID uint16,
  53. hermezContractAddr ethCommon.Address, username string) []byte {
  54. user := tc.Users[username]
  55. auth := &common.AccountCreationAuth{
  56. EthAddr: user.Addr,
  57. BJJ: user.BJJ.Public().Compress(),
  58. }
  59. err := auth.Sign(func(hash []byte) ([]byte, error) {
  60. return ethCrypto.Sign(hash, user.EthSk)
  61. }, chainID, hermezContractAddr)
  62. assert.NoError(t, err)
  63. err = l2DB.AddAccountCreationAuth(auth)
  64. assert.NoError(t, err)
  65. return auth.Signature
  66. }
  67. func initTxSelector(t *testing.T, chainID uint16, hermezContractAddr ethCommon.Address,
  68. coordUser *til.User) (*txselector.TxSelector, *l2db.L2DB, *statedb.StateDB) {
  69. pass := os.Getenv("POSTGRES_PASS")
  70. db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  71. require.NoError(t, err)
  72. l2DB := l2db.NewL2DB(db, db, 10, 100, 0.0, 24*time.Hour, nil)
  73. dir, err := ioutil.TempDir("", "tmpSyncDB")
  74. require.NoError(t, err)
  75. defer assert.NoError(t, os.RemoveAll(dir))
  76. syncStateDB, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  77. Type: statedb.TypeSynchronizer, NLevels: 0})
  78. require.NoError(t, err)
  79. txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
  80. require.NoError(t, err)
  81. defer assert.NoError(t, os.RemoveAll(dir))
  82. // use Til Coord keys for tests compatibility
  83. coordAccount := &txselector.CoordAccount{
  84. Addr: coordUser.Addr,
  85. BJJ: coordUser.BJJ.Public().Compress(),
  86. AccountCreationAuth: nil,
  87. }
  88. auth := common.AccountCreationAuth{
  89. EthAddr: coordUser.Addr,
  90. BJJ: coordUser.BJJ.Public().Compress(),
  91. }
  92. err = auth.Sign(func(hash []byte) ([]byte, error) {
  93. return ethCrypto.Sign(hash, coordUser.EthSk)
  94. }, chainID, hermezContractAddr)
  95. assert.NoError(t, err)
  96. coordAccount.AccountCreationAuth = auth.Signature
  97. txsel, err := txselector.NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
  98. require.NoError(t, err)
  99. test.WipeDB(l2DB.DB())
  100. return txsel, l2DB, syncStateDB
  101. }
  102. func TestTxSelectorBatchBuilderZKInputsMinimumFlow0(t *testing.T) {
  103. tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx)
  104. // generate test transactions, the L1CoordinatorTxs generated by Til
  105. // will be ignored at this test, as will be the TxSelector who
  106. // generates them when needed
  107. blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
  108. require.NoError(t, err)
  109. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  110. txsel, l2DBTxSel, syncStateDB := initTxSelector(t, ChainID, hermezContractAddr, tc.Users["Coord"])
  111. bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
  112. require.NoError(t, err)
  113. bb, err := batchbuilder.NewBatchBuilder(bbDir, syncStateDB, 0, NLevels)
  114. require.NoError(t, err)
  115. // restart nonces of TilContext, as will be set by generating directly
  116. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  117. tc.RestartNonces()
  118. // add tokens to HistoryDB to avoid breaking FK constrains
  119. addTokens(t, tc, l2DBTxSel.DB())
  120. selectionConfig := &txselector.SelectionConfig{
  121. MaxL1UserTxs: 100, // TODO
  122. TxProcessorConfig: txprocConfig,
  123. }
  124. configBatch := &batchbuilder.ConfigBatch{
  125. // ForgerAddress:
  126. TxProcessorConfig: txprocConfig,
  127. }
  128. // loop over the first 6 batches
  129. expectedRoots := []string{"0", "0",
  130. "13644148972047617726265275926674266298636745191961029124811988256139761111521",
  131. "12433441613247342495680642890662773367605896324555599297255745922589338651261",
  132. "12433441613247342495680642890662773367605896324555599297255745922589338651261",
  133. "4191361650490017591061467288209836928064232431729236465872209988325272262963"}
  134. for i := 0; i < 6; i++ {
  135. log.Debugf("block:0 batch:%d", i+1)
  136. var l1UserTxs []common.L1Tx
  137. if blocks[0].Rollup.Batches[i].Batch.ForgeL1TxsNum != nil {
  138. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[i].Batch.ForgeL1TxsNum])
  139. }
  140. // TxSelector select the transactions for the next Batch
  141. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
  142. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  143. require.NoError(t, err)
  144. // BatchBuilder build Batch
  145. zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  146. require.NoError(t, err)
  147. assert.Equal(t, expectedRoots[i], bb.LocalStateDB().MT.Root().BigInt().String())
  148. sendProofAndCheckResp(t, zki)
  149. }
  150. log.Debug("block:0 batch:7")
  151. // simulate the PoolL2Txs of the batch6
  152. batchPoolL2 := `
  153. Type: PoolL2
  154. PoolTransferToEthAddr(1) A-B: 200 (126)
  155. PoolTransferToEthAddr(0) B-C: 100 (126)`
  156. l2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  157. require.NoError(t, err)
  158. // add AccountCreationAuths that will be used at the next batch
  159. _ = addAccCreationAuth(t, tc, l2DBTxSel, ChainID, hermezContractAddr, "B")
  160. _ = addAccCreationAuth(t, tc, l2DBTxSel, ChainID, hermezContractAddr, "C")
  161. addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
  162. l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
  163. // TxSelector select the transactions for the next Batch
  164. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  165. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  166. require.NoError(t, err)
  167. // BatchBuilder build Batch
  168. zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  169. require.NoError(t, err)
  170. assert.Equal(t,
  171. "7614010373759339299470010949167613050707822522530721724565424494781010548240",
  172. bb.LocalStateDB().MT.Root().BigInt().String())
  173. sendProofAndCheckResp(t, zki)
  174. err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
  175. txsel.LocalAccountsDB().CurrentBatch())
  176. require.NoError(t, err)
  177. err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
  178. require.NoError(t, err)
  179. log.Debug("block:0 batch:8")
  180. // simulate the PoolL2Txs of the batch8
  181. batchPoolL2 = `
  182. Type: PoolL2
  183. PoolTransfer(0) A-B: 100 (126)
  184. PoolTransfer(0) C-A: 50 (126)
  185. PoolTransfer(1) B-C: 100 (126)
  186. PoolExit(0) A: 100 (126)`
  187. l2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  188. require.NoError(t, err)
  189. addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
  190. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
  191. // TxSelector select the transactions for the next Batch
  192. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  193. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  194. require.NoError(t, err)
  195. // BatchBuilder build Batch
  196. zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  197. require.NoError(t, err)
  198. assert.Equal(t,
  199. "21231789250434471575486264439945776732824482207853465397552873521865656677689",
  200. bb.LocalStateDB().MT.Root().BigInt().String())
  201. sendProofAndCheckResp(t, zki)
  202. err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
  203. txsel.LocalAccountsDB().CurrentBatch())
  204. require.NoError(t, err)
  205. err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
  206. require.NoError(t, err)
  207. log.Debug("(batch9) block:1 batch:1")
  208. // simulate the PoolL2Txs of the batch9
  209. batchPoolL2 = `
  210. Type: PoolL2
  211. PoolTransfer(0) D-A: 300 (126)
  212. PoolTransfer(0) B-D: 100 (126)`
  213. l2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
  214. require.NoError(t, err)
  215. addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
  216. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
  217. // TxSelector select the transactions for the next Batch
  218. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  219. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  220. require.NoError(t, err)
  221. // BatchBuilder build Batch
  222. zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  223. require.NoError(t, err)
  224. assert.Equal(t,
  225. "11289313644810782435120113035387729451095637380468777086895109386127538554246",
  226. bb.LocalStateDB().MT.Root().BigInt().String())
  227. sendProofAndCheckResp(t, zki)
  228. err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
  229. txsel.LocalAccountsDB().CurrentBatch())
  230. require.NoError(t, err)
  231. err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
  232. require.NoError(t, err)
  233. log.Debug("(batch10) block:1 batch:2")
  234. l2Txs = []common.PoolL2Tx{}
  235. l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  236. // TxSelector select the transactions for the next Batch
  237. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
  238. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  239. require.NoError(t, err)
  240. // BatchBuilder build Batch
  241. zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  242. require.NoError(t, err)
  243. // same root as previous batch, as the L1CoordinatorTxs created by the
  244. // Til set is not created by the TxSelector in this test
  245. assert.Equal(t,
  246. "11289313644810782435120113035387729451095637380468777086895109386127538554246",
  247. bb.LocalStateDB().MT.Root().BigInt().String())
  248. sendProofAndCheckResp(t, zki)
  249. err = l2DBTxSel.StartForging(common.TxIDsFromPoolL2Txs(l2Txs),
  250. txsel.LocalAccountsDB().CurrentBatch())
  251. require.NoError(t, err)
  252. err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs)
  253. require.NoError(t, err)
  254. }
  255. // TestZKInputsExitWithFee0 checks the case where there is a PoolTxs of type
  256. // Exit with fee 0 for a TokenID that the Coordinator does not have it
  257. // registered yet
  258. func TestZKInputsExitWithFee0(t *testing.T) {
  259. tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx)
  260. var set = `
  261. Type: Blockchain
  262. AddToken(1)
  263. CreateAccountDeposit(1) A: 1000
  264. CreateAccountDeposit(1) B: 1000
  265. CreateAccountDeposit(1) C: 1000
  266. > batchL1
  267. > batchL1
  268. CreateAccountCoordinator(1) Coord
  269. > batch
  270. > block
  271. `
  272. blocks, err := tc.GenerateBlocks(set)
  273. require.NoError(t, err)
  274. hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
  275. txsel, l2DBTxSel, syncStateDB := initTxSelector(t, ChainID, hermezContractAddr, tc.Users["Coord"])
  276. bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
  277. require.NoError(t, err)
  278. bb, err := batchbuilder.NewBatchBuilder(bbDir, syncStateDB, 0, NLevels)
  279. require.NoError(t, err)
  280. // restart nonces of TilContext, as will be set by generating directly
  281. // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
  282. tc.RestartNonces()
  283. // add tokens to HistoryDB to avoid breaking FK constrains
  284. addTokens(t, tc, l2DBTxSel.DB())
  285. selectionConfig := &txselector.SelectionConfig{
  286. MaxL1UserTxs: 100,
  287. TxProcessorConfig: txprocConfig,
  288. }
  289. configBatch := &batchbuilder.ConfigBatch{
  290. TxProcessorConfig: txprocConfig,
  291. }
  292. // batch2
  293. // TxSelector select the transactions for the next Batch
  294. l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
  295. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
  296. txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs)
  297. require.NoError(t, err)
  298. // BatchBuilder build Batch
  299. zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  300. require.NoError(t, err)
  301. assert.Equal(t,
  302. "8737171572459172806192626402462788826264011087579491137542380589998149683116",
  303. bb.LocalStateDB().MT.Root().BigInt().String())
  304. h, err := zki.HashGlobalData()
  305. require.NoError(t, err)
  306. assert.Equal(t,
  307. "18608843755023673022528019960628191162333429206359207449879743919826610006009",
  308. h.String())
  309. sendProofAndCheckResp(t, zki)
  310. // batch3
  311. batchPoolL2 := `
  312. Type: PoolL2
  313. PoolExit(1) A: 100 (0)`
  314. l2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
  315. require.NoError(t, err)
  316. addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB
  317. coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
  318. txsel.GetL1L2TxSelection(selectionConfig, nil)
  319. require.NoError(t, err)
  320. assert.Equal(t, 1, len(coordIdxs))
  321. assert.Equal(t, 0, len(oL1UserTxs))
  322. assert.Equal(t, 1, len(oL1CoordTxs))
  323. assert.Equal(t, 1, len(oL2Txs))
  324. assert.Equal(t, 0, len(discardedL2Txs))
  325. // BatchBuilder build Batch
  326. zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs)
  327. require.NoError(t, err)
  328. assert.Equal(t,
  329. "18306761925365215381387147754881756804475668085493847010988306480531520370130",
  330. bb.LocalStateDB().MT.Root().BigInt().String())
  331. h, err = zki.HashGlobalData()
  332. require.NoError(t, err)
  333. assert.Equal(t,
  334. "6651837443119278772088559395433504719862425648816904171510845286897104469889",
  335. h.String())
  336. assert.Equal(t, common.EthAddrToBigInt(tc.Users["Coord"].Addr), zki.EthAddr3[0])
  337. assert.Equal(t, "0", zki.EthAddr3[1].String())
  338. sendProofAndCheckResp(t, zki)
  339. }