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.

289 lines
8.9 KiB

  1. package coordinator
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "testing"
  6. "time"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. dbUtils "github.com/hermeznetwork/hermez-node/db"
  9. "github.com/hermeznetwork/hermez-node/db/l2db"
  10. "github.com/hermeznetwork/hermez-node/db/statedb"
  11. "github.com/hermeznetwork/hermez-node/test"
  12. "github.com/hermeznetwork/hermez-node/test/til"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. func newL2DB(t *testing.T) *l2db.L2DB {
  17. pass := os.Getenv("POSTGRES_PASS")
  18. db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  19. require.NoError(t, err)
  20. test.WipeDB(db)
  21. return l2db.NewL2DB(db, db, 10, 100, 0.0, 1000.0, 24*time.Hour, nil)
  22. }
  23. func newStateDB(t *testing.T) *statedb.LocalStateDB {
  24. syncDBPath, err := ioutil.TempDir("", "tmpSyncDB")
  25. require.NoError(t, err)
  26. deleteme = append(deleteme, syncDBPath)
  27. syncStateDB, err := statedb.NewStateDB(statedb.Config{Path: syncDBPath, Keep: 128,
  28. Type: statedb.TypeSynchronizer, NLevels: 48})
  29. assert.NoError(t, err)
  30. stateDBPath, err := ioutil.TempDir("", "tmpStateDB")
  31. require.NoError(t, err)
  32. deleteme = append(deleteme, stateDBPath)
  33. stateDB, err := statedb.NewLocalStateDB(statedb.Config{Path: stateDBPath, Keep: 128,
  34. Type: statedb.TypeTxSelector, NLevels: 0}, syncStateDB)
  35. require.NoError(t, err)
  36. return stateDB
  37. }
  38. func TestCanPurgeCanInvalidate(t *testing.T) {
  39. cfg := PurgerCfg{
  40. PurgeBatchDelay: 2,
  41. PurgeBlockDelay: 6,
  42. InvalidateBatchDelay: 4,
  43. InvalidateBlockDelay: 8,
  44. }
  45. p := Purger{
  46. cfg: cfg,
  47. }
  48. startBlockNum := int64(1000)
  49. startBatchNum := int64(10)
  50. blockNum := startBlockNum
  51. batchNum := startBatchNum
  52. assert.True(t, p.CanPurge(blockNum, batchNum))
  53. p.lastPurgeBlock = startBlockNum
  54. p.lastPurgeBatch = startBatchNum
  55. assert.False(t, p.CanPurge(blockNum, batchNum))
  56. blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
  57. batchNum = startBatchNum + cfg.PurgeBatchDelay - 1
  58. assert.False(t, p.CanPurge(blockNum, batchNum))
  59. blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
  60. batchNum = startBatchNum + cfg.PurgeBatchDelay
  61. assert.True(t, p.CanPurge(blockNum, batchNum))
  62. blockNum = startBlockNum + cfg.PurgeBlockDelay
  63. batchNum = startBatchNum + cfg.PurgeBatchDelay - 1
  64. assert.True(t, p.CanPurge(blockNum, batchNum))
  65. assert.True(t, p.CanInvalidate(blockNum, batchNum))
  66. p.lastInvalidateBlock = startBlockNum
  67. p.lastInvalidateBatch = startBatchNum
  68. assert.False(t, p.CanInvalidate(blockNum, batchNum))
  69. blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
  70. batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
  71. assert.False(t, p.CanInvalidate(blockNum, batchNum))
  72. blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
  73. batchNum = startBatchNum + cfg.InvalidateBatchDelay
  74. assert.True(t, p.CanInvalidate(blockNum, batchNum))
  75. blockNum = startBlockNum + cfg.InvalidateBlockDelay
  76. batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
  77. assert.True(t, p.CanInvalidate(blockNum, batchNum))
  78. }
  79. func TestPurgeMaybeInvalidateMaybe(t *testing.T) {
  80. cfg := PurgerCfg{
  81. PurgeBatchDelay: 2,
  82. PurgeBlockDelay: 6,
  83. InvalidateBatchDelay: 4,
  84. InvalidateBlockDelay: 8,
  85. }
  86. p := Purger{
  87. cfg: cfg,
  88. }
  89. l2DB := newL2DB(t)
  90. stateDB := newStateDB(t)
  91. startBlockNum := int64(1000)
  92. startBatchNum := int64(10)
  93. p.lastPurgeBlock = startBlockNum
  94. p.lastPurgeBatch = startBatchNum
  95. blockNum := startBlockNum + cfg.PurgeBlockDelay - 1
  96. batchNum := startBatchNum + cfg.PurgeBatchDelay - 1
  97. ok, err := p.PurgeMaybe(l2DB, blockNum, batchNum)
  98. require.NoError(t, err)
  99. assert.False(t, ok)
  100. // At this point the purger will purge. The second time it doesn't
  101. // because it the first time it has updates the last time it did.
  102. blockNum = startBlockNum + cfg.PurgeBlockDelay - 1
  103. batchNum = startBatchNum + cfg.PurgeBatchDelay
  104. ok, err = p.PurgeMaybe(l2DB, blockNum, batchNum)
  105. require.NoError(t, err)
  106. assert.True(t, ok)
  107. ok, err = p.PurgeMaybe(l2DB, blockNum, batchNum)
  108. require.NoError(t, err)
  109. assert.False(t, ok)
  110. p.lastInvalidateBlock = startBlockNum
  111. p.lastInvalidateBatch = startBatchNum
  112. blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
  113. batchNum = startBatchNum + cfg.InvalidateBatchDelay - 1
  114. ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
  115. require.NoError(t, err)
  116. assert.False(t, ok)
  117. // At this point the purger will invaidate. The second time it doesn't
  118. // because it the first time it has updates the last time it did.
  119. blockNum = startBlockNum + cfg.InvalidateBlockDelay - 1
  120. batchNum = startBatchNum + cfg.InvalidateBatchDelay
  121. ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
  122. require.NoError(t, err)
  123. assert.True(t, ok)
  124. ok, err = p.InvalidateMaybe(l2DB, stateDB, blockNum, batchNum)
  125. require.NoError(t, err)
  126. assert.False(t, ok)
  127. }
  128. func TestIdxsNonce(t *testing.T) {
  129. inputIdxsNonce := []common.IdxNonce{
  130. {Idx: 256, Nonce: 1},
  131. {Idx: 256, Nonce: 2},
  132. {Idx: 257, Nonce: 3},
  133. {Idx: 258, Nonce: 5},
  134. {Idx: 258, Nonce: 2},
  135. }
  136. expectedIdxsNonce := map[common.Idx]common.Nonce{
  137. common.Idx(256): common.Nonce(2),
  138. common.Idx(257): common.Nonce(3),
  139. common.Idx(258): common.Nonce(5),
  140. }
  141. l2txs := make([]common.L2Tx, len(inputIdxsNonce))
  142. for i, idxNonce := range inputIdxsNonce {
  143. l2txs[i].FromIdx = idxNonce.Idx
  144. l2txs[i].Nonce = idxNonce.Nonce
  145. }
  146. idxsNonce := idxsNonceFromL2Txs(l2txs)
  147. assert.Equal(t, len(expectedIdxsNonce), len(idxsNonce))
  148. for _, idxNonce := range idxsNonce {
  149. nonce := expectedIdxsNonce[idxNonce.Idx]
  150. assert.Equal(t, nonce, idxNonce.Nonce)
  151. }
  152. pooll2txs := make([]common.PoolL2Tx, len(inputIdxsNonce))
  153. for i, idxNonce := range inputIdxsNonce {
  154. pooll2txs[i].FromIdx = idxNonce.Idx
  155. pooll2txs[i].Nonce = idxNonce.Nonce
  156. }
  157. idxsNonce = idxsNonceFromPoolL2Txs(pooll2txs)
  158. assert.Equal(t, len(expectedIdxsNonce), len(idxsNonce))
  159. for _, idxNonce := range idxsNonce {
  160. nonce := expectedIdxsNonce[idxNonce.Idx]
  161. assert.Equal(t, nonce, idxNonce.Nonce)
  162. }
  163. }
  164. func TestPoolMarkInvalidOldNonces(t *testing.T) {
  165. l2DB := newL2DB(t)
  166. stateDB := newStateDB(t)
  167. set0 := `
  168. Type: Blockchain
  169. CreateAccountDeposit(0) A: 1000 // Idx=256
  170. CreateAccountDeposit(0) B: 1000 // Idx=257
  171. CreateAccountDeposit(0) C: 1000 // Idx=258
  172. CreateAccountDeposit(0) D: 1000 // Idx=259
  173. > batchL1
  174. > batchL1
  175. > block
  176. `
  177. tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  178. blocks, err := tc.GenerateBlocks(set0)
  179. require.NoError(t, err)
  180. tilCfgExtra := til.ConfigExtra{
  181. CoordUser: "A",
  182. }
  183. // Call FillBlocksExtra to fill `Batch.CreatedAccounts`
  184. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  185. require.NoError(t, err)
  186. require.Equal(t, 4, len(blocks[0].Rollup.Batches[1].CreatedAccounts)) // sanity check
  187. for _, acc := range blocks[0].Rollup.Batches[1].CreatedAccounts {
  188. _, err := stateDB.CreateAccount(acc.Idx, &acc) //nolint:gosec
  189. require.NoError(t, err)
  190. }
  191. setPool0 := `
  192. Type: PoolL2
  193. PoolTransfer(0) A-B: 10 (1)
  194. PoolTransfer(0) A-C: 10 (1)
  195. PoolTransfer(0) A-D: 10 (1)
  196. PoolTransfer(0) B-A: 10 (1)
  197. PoolTransfer(0) B-C: 10 (1)
  198. PoolTransfer(0) C-A: 10 (1)
  199. `
  200. // We expect the following nonces
  201. nonces0 := map[string]int64{"A": 3, "B": 2, "C": 1, "D": 0}
  202. l2txs0, err := tc.GeneratePoolL2Txs(setPool0)
  203. assert.Nil(t, err)
  204. assert.Equal(t, 6, len(l2txs0))
  205. for _, tx := range l2txs0 {
  206. require.NoError(t, l2DB.AddTxTest(&tx)) //nolint:gosec
  207. }
  208. // Update the accounts in the StateDB, making the txs in the setPool0
  209. // invalid
  210. for name, user := range tc.Users {
  211. for _, _acc := range user.Accounts {
  212. require.Equal(t, common.Nonce(nonces0[name]), _acc.Nonce) // sanity check
  213. acc, err := stateDB.GetAccount(_acc.Idx)
  214. require.NoError(t, err)
  215. require.Equal(t, common.Nonce(0), acc.Nonce) // sanity check
  216. acc.Nonce = _acc.Nonce
  217. _, err = stateDB.UpdateAccount(acc.Idx, acc)
  218. require.NoError(t, err)
  219. }
  220. }
  221. setPool1 := `
  222. Type: PoolL2
  223. PoolTransfer(0) A-B: 10 (1)
  224. PoolTransfer(0) A-C: 10 (1)
  225. PoolTransfer(0) A-D: 10 (1)
  226. PoolTransfer(0) B-A: 10 (1)
  227. PoolTransfer(0) B-C: 10 (1)
  228. PoolTransfer(0) C-A: 10 (1)
  229. `
  230. // We expect the following nonces
  231. nonces1 := map[string]int64{"A": 6, "B": 4, "C": 2, "D": 0}
  232. l2txs1, err := tc.GeneratePoolL2Txs(setPool1)
  233. require.NoError(t, err)
  234. assert.Equal(t, 6, len(l2txs1))
  235. for _, tx := range l2txs1 {
  236. require.NoError(t, l2DB.AddTxTest(&tx)) //nolint:gosec
  237. }
  238. for name, user := range tc.Users {
  239. for _, _acc := range user.Accounts {
  240. require.Equal(t, common.Nonce(nonces1[name]), _acc.Nonce) // sanity check
  241. acc, err := stateDB.GetAccount(_acc.Idx)
  242. require.NoError(t, err)
  243. require.Equal(t, common.Nonce(nonces0[name]), acc.Nonce) // sanity check
  244. }
  245. }
  246. // Now we should have 12 txs in the pool, all marked as pending. Since
  247. // we updated the stateDB with the nonces after setPool0, the first 6
  248. // txs will be marked as invalid
  249. pendingTxs, err := l2DB.GetPendingTxs()
  250. require.NoError(t, err)
  251. assert.Equal(t, 12, len(pendingTxs))
  252. batchNum := common.BatchNum(1)
  253. err = poolMarkInvalidOldNonces(l2DB, stateDB, batchNum)
  254. require.NoError(t, err)
  255. pendingTxs, err = l2DB.GetPendingTxs()
  256. require.NoError(t, err)
  257. assert.Equal(t, 6, len(pendingTxs))
  258. }