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.

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