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.

299 lines
9.5 KiB

  1. package coordinator
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "math/big"
  7. "os"
  8. "testing"
  9. ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
  10. ethCommon "github.com/ethereum/go-ethereum/common"
  11. "github.com/ethereum/go-ethereum/crypto"
  12. "github.com/ethereum/go-ethereum/ethclient"
  13. "github.com/hermeznetwork/hermez-node/common"
  14. "github.com/hermeznetwork/hermez-node/db/historydb"
  15. "github.com/hermeznetwork/hermez-node/db/statedb"
  16. "github.com/hermeznetwork/hermez-node/eth"
  17. "github.com/hermeznetwork/hermez-node/prover"
  18. "github.com/hermeznetwork/hermez-node/synchronizer"
  19. "github.com/hermeznetwork/hermez-node/test"
  20. "github.com/hermeznetwork/hermez-node/test/til"
  21. "github.com/iden3/go-merkletree"
  22. "github.com/stretchr/testify/assert"
  23. "github.com/stretchr/testify/require"
  24. )
  25. func TestPipelineShouldL1L2Batch(t *testing.T) {
  26. ethClientSetup := test.NewClientSetupExample()
  27. ethClientSetup.ChainID = big.NewInt(int64(chainID))
  28. var timer timer
  29. ctx := context.Background()
  30. ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
  31. modules := newTestModules(t)
  32. var stats synchronizer.Stats
  33. coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
  34. pipeline, err := coord.newPipeline(ctx)
  35. require.NoError(t, err)
  36. pipeline.vars = coord.vars
  37. // Check that the parameters are the ones we expect and use in this test
  38. require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
  39. require.Equal(t, int64(10), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
  40. l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
  41. l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
  42. startBlock := int64(100)
  43. // Empty batchInfo to pass to shouldL1L2Batch() which sets debug information
  44. batchInfo := BatchInfo{}
  45. //
  46. // No scheduled L1Batch
  47. //
  48. // Last L1Batch was a long time ago
  49. stats.Eth.LastBlock.Num = startBlock
  50. stats.Sync.LastBlock = stats.Eth.LastBlock
  51. stats.Sync.LastL1BatchBlock = 0
  52. pipeline.stats = stats
  53. assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
  54. stats.Sync.LastL1BatchBlock = startBlock
  55. // We are are one block before the timeout range * 0.5
  56. stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
  57. stats.Sync.LastBlock = stats.Eth.LastBlock
  58. pipeline.stats = stats
  59. assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
  60. // We are are at timeout range * 0.5
  61. stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
  62. stats.Sync.LastBlock = stats.Eth.LastBlock
  63. pipeline.stats = stats
  64. assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
  65. //
  66. // Scheduled L1Batch
  67. //
  68. pipeline.lastScheduledL1BatchBlockNum = startBlock
  69. stats.Sync.LastL1BatchBlock = startBlock - 10
  70. // We are are one block before the timeout range * 0.5
  71. stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
  72. stats.Sync.LastBlock = stats.Eth.LastBlock
  73. pipeline.stats = stats
  74. assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
  75. // We are are at timeout range * 0.5
  76. stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
  77. stats.Sync.LastBlock = stats.Eth.LastBlock
  78. pipeline.stats = stats
  79. assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
  80. }
  81. const testTokensLen = 3
  82. const testUsersLen = 4
  83. func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
  84. historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
  85. // Create a set with `testTokensLen` tokens and for each token
  86. // `testUsersLen` accounts.
  87. var set []til.Instruction
  88. // set = append(set, til.Instruction{Typ: "Blockchain"})
  89. for tokenID := 1; tokenID < testTokensLen; tokenID++ {
  90. set = append(set, til.Instruction{
  91. Typ: til.TypeAddToken,
  92. TokenID: common.TokenID(tokenID),
  93. })
  94. }
  95. depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
  96. require.True(t, ok)
  97. for tokenID := 0; tokenID < testTokensLen; tokenID++ {
  98. for user := 0; user < testUsersLen; user++ {
  99. set = append(set, til.Instruction{
  100. Typ: common.TxTypeCreateAccountDeposit,
  101. TokenID: common.TokenID(tokenID),
  102. DepositAmount: depositAmount,
  103. From: fmt.Sprintf("User%d", user),
  104. })
  105. }
  106. }
  107. set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
  108. set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
  109. set = append(set, til.Instruction{Typ: til.TypeNewBlock})
  110. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  111. blocks, err := tc.GenerateBlocksFromInstructions(set)
  112. require.NoError(t, err)
  113. require.NotNil(t, blocks)
  114. ethAddTokens(blocks, ethClient)
  115. err = ethClient.CtlAddBlocks(blocks)
  116. require.NoError(t, err)
  117. ctx := context.Background()
  118. for {
  119. syncBlock, discards, err := sync.Sync2(ctx, nil)
  120. require.NoError(t, err)
  121. require.Nil(t, discards)
  122. if syncBlock == nil {
  123. break
  124. }
  125. }
  126. dbTokens, err := historyDB.GetAllTokens()
  127. require.Nil(t, err)
  128. require.Equal(t, testTokensLen, len(dbTokens))
  129. dbAccounts, err := historyDB.GetAllAccounts()
  130. require.Nil(t, err)
  131. require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
  132. sdbAccounts, err := stateDB.TestGetAccounts()
  133. require.Nil(t, err)
  134. require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
  135. return tc
  136. }
  137. func TestPipelineForgeBatchWithTxs(t *testing.T) {
  138. ethClientSetup := test.NewClientSetupExample()
  139. ethClientSetup.ChainID = big.NewInt(int64(chainID))
  140. var timer timer
  141. ctx := context.Background()
  142. ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
  143. modules := newTestModules(t)
  144. coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
  145. sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
  146. // preload the synchronier (via the test ethClient) some tokens and
  147. // users with positive balances
  148. tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
  149. syncStats := sync.Stats()
  150. batchNum := common.BatchNum(syncStats.Sync.LastBatch)
  151. syncSCVars := sync.SCVars()
  152. pipeline, err := coord.newPipeline(ctx)
  153. require.NoError(t, err)
  154. // Insert some l2txs in the Pool
  155. setPool := `
  156. Type: PoolL2
  157. PoolTransfer(0) User0-User1: 100 (126)
  158. PoolTransfer(0) User1-User2: 200 (126)
  159. PoolTransfer(0) User2-User3: 300 (126)
  160. `
  161. l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
  162. require.NoError(t, err)
  163. for _, tx := range l2txs {
  164. err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
  165. require.NoError(t, err)
  166. }
  167. err = pipeline.reset(batchNum, syncStats, &synchronizer.SCVariables{
  168. Rollup: *syncSCVars.Rollup,
  169. Auction: *syncSCVars.Auction,
  170. WDelayer: *syncSCVars.WDelayer,
  171. })
  172. require.NoError(t, err)
  173. // Sanity check
  174. sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().TestGetAccounts()
  175. require.Nil(t, err)
  176. require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
  177. // Sanity check
  178. sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().TestGetAccounts()
  179. require.Nil(t, err)
  180. require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
  181. // Sanity check
  182. require.Equal(t, modules.stateDB.MT.Root(),
  183. pipeline.batchBuilder.LocalStateDB().MT.Root())
  184. batchNum++
  185. batchInfo, err := pipeline.forgeBatch(batchNum)
  186. require.NoError(t, err)
  187. assert.Equal(t, 3, len(batchInfo.L2Txs))
  188. batchNum++
  189. batchInfo, err = pipeline.forgeBatch(batchNum)
  190. require.NoError(t, err)
  191. assert.Equal(t, 0, len(batchInfo.L2Txs))
  192. }
  193. func TestEthRollupForgeBatch(t *testing.T) {
  194. if os.Getenv("TEST_ROLLUP_FORGE_BATCH") == "" {
  195. return
  196. }
  197. const web3URL = "http://localhost:8545"
  198. const password = "test"
  199. addr := ethCommon.HexToAddress("0xb4124ceb3451635dacedd11767f004d8a28c6ee7")
  200. sk, err := crypto.HexToECDSA(
  201. "a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563")
  202. require.NoError(t, err)
  203. rollupAddr := ethCommon.HexToAddress("0x8EEaea23686c319133a7cC110b840d1591d9AeE0")
  204. pathKeystore, err := ioutil.TempDir("", "tmpKeystore")
  205. require.NoError(t, err)
  206. deleteme = append(deleteme, pathKeystore)
  207. ctx := context.Background()
  208. batchInfo := &BatchInfo{}
  209. proofClient := &prover.MockClient{}
  210. chainID := uint16(0)
  211. ethClient, err := ethclient.Dial(web3URL)
  212. require.NoError(t, err)
  213. ethCfg := eth.EthereumConfig{
  214. CallGasLimit: 300000,
  215. GasPriceDiv: 100,
  216. }
  217. scryptN := ethKeystore.LightScryptN
  218. scryptP := ethKeystore.LightScryptP
  219. keyStore := ethKeystore.NewKeyStore(pathKeystore,
  220. scryptN, scryptP)
  221. account, err := keyStore.ImportECDSA(sk, password)
  222. require.NoError(t, err)
  223. require.Equal(t, account.Address, addr)
  224. err = keyStore.Unlock(account, password)
  225. require.NoError(t, err)
  226. client, err := eth.NewClient(ethClient, &account, keyStore, &eth.ClientConfig{
  227. Ethereum: ethCfg,
  228. Rollup: eth.RollupConfig{
  229. Address: rollupAddr,
  230. },
  231. Auction: eth.AuctionConfig{
  232. Address: ethCommon.Address{},
  233. TokenHEZ: eth.TokenConfig{
  234. Address: ethCommon.Address{},
  235. Name: "HEZ",
  236. },
  237. },
  238. WDelayer: eth.WDelayerConfig{
  239. Address: ethCommon.Address{},
  240. },
  241. })
  242. require.NoError(t, err)
  243. zkInputs := common.NewZKInputs(chainID, 100, 24, 512, 32, big.NewInt(1))
  244. zkInputs.Metadata.NewStateRootRaw = &merkletree.Hash{1}
  245. zkInputs.Metadata.NewExitRootRaw = &merkletree.Hash{2}
  246. batchInfo.ZKInputs = zkInputs
  247. err = proofClient.CalculateProof(ctx, batchInfo.ZKInputs)
  248. require.NoError(t, err)
  249. proof, pubInputs, err := proofClient.GetProof(ctx)
  250. require.NoError(t, err)
  251. batchInfo.Proof = proof
  252. batchInfo.PublicInputs = pubInputs
  253. batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo)
  254. auth, err := client.NewAuth()
  255. require.NoError(t, err)
  256. _, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs, auth)
  257. require.NoError(t, err)
  258. batchInfo.Proof = proof
  259. }