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.

609 lines
19 KiB

Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
  1. package historydb
  2. import (
  3. "database/sql"
  4. "math"
  5. "math/big"
  6. "os"
  7. "testing"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. dbUtils "github.com/hermeznetwork/hermez-node/db"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. "github.com/hermeznetwork/hermez-node/test"
  14. "github.com/hermeznetwork/hermez-node/test/til"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. var historyDB *HistoryDB
  19. // In order to run the test you need to run a Posgres DB with
  20. // a database named "history" that is accessible by
  21. // user: "hermez"
  22. // pass: set it using the env var POSTGRES_PASS
  23. // This can be achieved by running: POSTGRES_PASS=your_strong_pass && sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD=$POSTGRES_PASS -d postgres && sleep 2s && sudo docker exec -it hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
  24. // After running the test you can stop the container by running: sudo docker kill hermez-db-test
  25. // If you already did that for the L2DB you don't have to do it again
  26. func TestMain(m *testing.M) {
  27. // init DB
  28. pass := os.Getenv("POSTGRES_PASS")
  29. db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
  30. if err != nil {
  31. panic(err)
  32. }
  33. historyDB = NewHistoryDB(db)
  34. if err != nil {
  35. panic(err)
  36. }
  37. // Run tests
  38. result := m.Run()
  39. // Close DB
  40. if err := db.Close(); err != nil {
  41. log.Error("Error closing the history DB:", err)
  42. }
  43. os.Exit(result)
  44. }
  45. func TestBlocks(t *testing.T) {
  46. var fromBlock, toBlock int64
  47. fromBlock = 1
  48. toBlock = 5
  49. // Delete peviously created rows (clean previous test execs)
  50. test.WipeDB(historyDB.DB())
  51. // Generate fake blocks
  52. blocks := test.GenBlocks(fromBlock, toBlock)
  53. // Save timestamp of a block with UTC and change it without UTC
  54. timestamp := time.Now().Add(time.Second * 13)
  55. blocks[fromBlock].Timestamp = timestamp
  56. // Insert blocks into DB
  57. for i := 0; i < len(blocks); i++ {
  58. err := historyDB.AddBlock(&blocks[i])
  59. assert.NoError(t, err)
  60. }
  61. // Get all blocks from DB
  62. fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
  63. assert.Equal(t, len(blocks), len(fetchedBlocks))
  64. // Compare generated vs getted blocks
  65. assert.NoError(t, err)
  66. for i := range fetchedBlocks {
  67. assertEqualBlock(t, &blocks[i], &fetchedBlocks[i])
  68. }
  69. // Compare saved timestamp vs getted
  70. nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
  71. zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
  72. assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
  73. assert.Equal(t, offsetUTC, offsetFetchedBlock)
  74. // Get blocks from the DB one by one
  75. for i := fromBlock; i < toBlock; i++ {
  76. fetchedBlock, err := historyDB.GetBlock(i)
  77. assert.NoError(t, err)
  78. assertEqualBlock(t, &blocks[i-1], fetchedBlock)
  79. }
  80. // Get last block
  81. lastBlock, err := historyDB.GetLastBlock()
  82. assert.NoError(t, err)
  83. assertEqualBlock(t, &blocks[len(blocks)-1], lastBlock)
  84. }
  85. func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
  86. assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
  87. assert.Equal(t, expected.Hash, actual.Hash)
  88. assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
  89. }
  90. func TestBatches(t *testing.T) {
  91. const fromBlock int64 = 1
  92. const toBlock int64 = 3
  93. // Prepare blocks in the DB
  94. blocks := setTestBlocks(fromBlock, toBlock)
  95. // Generate fake batches
  96. const nBatches = 9
  97. batches := test.GenBatches(nBatches, blocks)
  98. // Test GetLastL1TxsNum with no batches
  99. fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
  100. assert.NoError(t, err)
  101. assert.Nil(t, fetchedLastL1TxsNum)
  102. // Add batches to the DB
  103. err = historyDB.AddBatches(batches)
  104. assert.NoError(t, err)
  105. // Get batches from the DB
  106. fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(nBatches))
  107. assert.NoError(t, err)
  108. for i, fetchedBatch := range fetchedBatches {
  109. assert.Equal(t, batches[i], fetchedBatch)
  110. }
  111. // Test GetLastBatchNum
  112. fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
  113. assert.NoError(t, err)
  114. assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
  115. // Test GetLastL1TxsNum
  116. fetchedLastL1TxsNum, err = historyDB.GetLastL1TxsNum()
  117. assert.NoError(t, err)
  118. assert.Equal(t, *batches[nBatches-1].ForgeL1TxsNum, *fetchedLastL1TxsNum)
  119. // Test total fee
  120. // Generate fake tokens
  121. const nTokens = 5
  122. tokens, ethToken := test.GenTokens(nTokens, blocks)
  123. err = historyDB.AddTokens(tokens)
  124. assert.NoError(t, err)
  125. tokens = append([]common.Token{ethToken}, tokens...)
  126. feeBatch := batches[0]
  127. feeBatch.BatchNum = 9999
  128. feeBatch.CollectedFees = make(map[common.TokenID]*big.Int)
  129. var total float64
  130. for i, token := range tokens {
  131. value := 3.019237 * float64(i)
  132. assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
  133. bigAmount := big.NewInt(345000000)
  134. feeBatch.CollectedFees[token.TokenID] = bigAmount
  135. f := new(big.Float).SetInt(bigAmount)
  136. amount, _ := f.Float64()
  137. total += value * (amount / math.Pow(10, float64(token.Decimals)))
  138. }
  139. err = historyDB.AddBatch(&feeBatch)
  140. assert.NoError(t, err)
  141. fetchedBatches, err = historyDB.GetBatches(feeBatch.BatchNum-1, feeBatch.BatchNum+1)
  142. assert.NoError(t, err)
  143. for _, fetchedBatch := range fetchedBatches {
  144. if fetchedBatch.BatchNum == feeBatch.BatchNum {
  145. assert.Equal(t, total, *fetchedBatch.TotalFeesUSD)
  146. }
  147. }
  148. }
  149. func TestBids(t *testing.T) {
  150. const fromBlock int64 = 1
  151. const toBlock int64 = 5
  152. // Prepare blocks in the DB
  153. blocks := setTestBlocks(fromBlock, toBlock)
  154. // Generate fake coordinators
  155. const nCoords = 5
  156. coords := test.GenCoordinators(nCoords, blocks)
  157. err := historyDB.AddCoordinators(coords)
  158. assert.NoError(t, err)
  159. // Generate fake bids
  160. const nBids = 20
  161. bids := test.GenBids(nBids, blocks, coords)
  162. err = historyDB.AddBids(bids)
  163. assert.NoError(t, err)
  164. // Fetch bids
  165. fetchedBids, err := historyDB.GetAllBids()
  166. assert.NoError(t, err)
  167. // Compare fetched bids vs generated bids
  168. for i, bid := range fetchedBids {
  169. assert.Equal(t, bids[i], bid)
  170. }
  171. }
  172. func TestTokens(t *testing.T) {
  173. const fromBlock int64 = 1
  174. const toBlock int64 = 5
  175. // Prepare blocks in the DB
  176. blocks := setTestBlocks(fromBlock, toBlock)
  177. // Generate fake tokens
  178. const nTokens = 5
  179. tokens, ethToken := test.GenTokens(nTokens, blocks)
  180. err := historyDB.AddTokens(tokens)
  181. assert.NoError(t, err)
  182. tokens = append([]common.Token{ethToken}, tokens...)
  183. limit := uint(10)
  184. // Fetch tokens
  185. fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
  186. assert.NoError(t, err)
  187. // Compare fetched tokens vs generated tokens
  188. // All the tokens should have USDUpdate setted by the DB trigger
  189. for i, token := range fetchedTokens {
  190. assert.Equal(t, tokens[i].TokenID, token.TokenID)
  191. assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
  192. assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
  193. assert.Equal(t, tokens[i].Name, token.Name)
  194. assert.Equal(t, tokens[i].Symbol, token.Symbol)
  195. assert.Nil(t, token.USD)
  196. assert.Nil(t, token.USDUpdate)
  197. }
  198. // Update token value
  199. for i, token := range tokens {
  200. value := 1.01 * float64(i)
  201. assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
  202. }
  203. // Fetch tokens
  204. fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
  205. assert.NoError(t, err)
  206. // Compare fetched tokens vs generated tokens
  207. // All the tokens should have USDUpdate setted by the DB trigger
  208. for i, token := range fetchedTokens {
  209. value := 1.01 * float64(i)
  210. assert.Equal(t, value, *token.USD)
  211. nameZone, offset := token.USDUpdate.Zone()
  212. assert.Equal(t, "UTC", nameZone)
  213. assert.Equal(t, 0, offset)
  214. }
  215. }
  216. func TestAccounts(t *testing.T) {
  217. const fromBlock int64 = 1
  218. const toBlock int64 = 5
  219. // Prepare blocks in the DB
  220. blocks := setTestBlocks(fromBlock, toBlock)
  221. // Generate fake tokens
  222. const nTokens = 5
  223. tokens, ethToken := test.GenTokens(nTokens, blocks)
  224. err := historyDB.AddTokens(tokens)
  225. assert.NoError(t, err)
  226. tokens = append([]common.Token{ethToken}, tokens...)
  227. // Generate fake batches
  228. const nBatches = 10
  229. batches := test.GenBatches(nBatches, blocks)
  230. err = historyDB.AddBatches(batches)
  231. assert.NoError(t, err)
  232. // Generate fake accounts
  233. const nAccounts = 3
  234. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  235. err = historyDB.AddAccounts(accs)
  236. assert.NoError(t, err)
  237. // Fetch accounts
  238. fetchedAccs, err := historyDB.GetAccounts()
  239. assert.NoError(t, err)
  240. // Compare fetched accounts vs generated accounts
  241. for i, acc := range fetchedAccs {
  242. accs[i].Balance = nil
  243. assert.Equal(t, accs[i], acc)
  244. }
  245. }
  246. func TestTxs(t *testing.T) {
  247. const fromBlock int64 = 1
  248. const toBlock int64 = 5
  249. // Prepare blocks in the DB
  250. blocks := setTestBlocks(fromBlock, toBlock)
  251. // Generate fake tokens
  252. const nTokens = 500
  253. tokens, ethToken := test.GenTokens(nTokens, blocks)
  254. err := historyDB.AddTokens(tokens)
  255. assert.NoError(t, err)
  256. tokens = append([]common.Token{ethToken}, tokens...)
  257. // Generate fake batches
  258. const nBatches = 10
  259. batches := test.GenBatches(nBatches, blocks)
  260. err = historyDB.AddBatches(batches)
  261. assert.NoError(t, err)
  262. // Generate fake accounts
  263. const nAccounts = 3
  264. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  265. err = historyDB.AddAccounts(accs)
  266. assert.NoError(t, err)
  267. /*
  268. Uncomment once the transaction generation is fixed
  269. !! test that batches that forge user L1s !!
  270. !! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
  271. // Generate fake L1 txs
  272. const nL1s = 64
  273. _, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
  274. err = historyDB.AddL1Txs(l1txs)
  275. assert.NoError(t, err)
  276. // Generate fake L2 txs
  277. const nL2s = 2048 - nL1s
  278. _, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
  279. err = historyDB.AddL2Txs(l2txs)
  280. assert.NoError(t, err)
  281. // Compare fetched txs vs generated txs.
  282. fetchAndAssertTxs(t, l1txs, l2txs)
  283. // Test trigger: L1 integrity
  284. // from_eth_addr can't be null
  285. l1txs[0].FromEthAddr = ethCommon.Address{}
  286. err = historyDB.AddL1Txs(l1txs)
  287. assert.Error(t, err)
  288. l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
  289. // from_bjj can't be null
  290. l1txs[0].FromBJJ = nil
  291. err = historyDB.AddL1Txs(l1txs)
  292. assert.Error(t, err)
  293. privK := babyjub.NewRandPrivKey()
  294. l1txs[0].FromBJJ = privK.Public()
  295. // load_amount can't be null
  296. l1txs[0].LoadAmount = nil
  297. err = historyDB.AddL1Txs(l1txs)
  298. assert.Error(t, err)
  299. // Test trigger: L2 integrity
  300. // batch_num can't be null
  301. l2txs[0].BatchNum = 0
  302. err = historyDB.AddL2Txs(l2txs)
  303. assert.Error(t, err)
  304. l2txs[0].BatchNum = 1
  305. // nonce can't be null
  306. l2txs[0].Nonce = 0
  307. err = historyDB.AddL2Txs(l2txs)
  308. assert.Error(t, err)
  309. // Test trigger: forge L1 txs
  310. // add next batch to DB
  311. batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
  312. batch := batches[0]
  313. batch.BatchNum = batchNum
  314. batch.ForgeL1TxsNum = toForgeL1TxsNum
  315. assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
  316. // Set batch num in txs that should have been marked as forged in the DB
  317. for i := 0; i < len(l1txs); i++ {
  318. fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
  319. assert.NoError(t, err)
  320. if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
  321. assert.Equal(t, batchNum, *fetchedTx.BatchNum)
  322. } else {
  323. if fetchedTx.BatchNum != nil {
  324. assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
  325. }
  326. }
  327. }
  328. // Test helper functions for Synchronizer
  329. // GetLastTxsPosition
  330. expectedPosition := -1
  331. var choosenToForgeL1TxsNum int64 = -1
  332. for _, tx := range l1txs {
  333. if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
  334. choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
  335. expectedPosition = tx.Position
  336. } else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
  337. expectedPosition = tx.Position
  338. }
  339. }
  340. position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
  341. assert.NoError(t, err)
  342. assert.Equal(t, expectedPosition, position)
  343. // GetL1UserTxs: not needed? tests were broken
  344. // txs, err := historyDB.GetL1UserTxs(2)
  345. // assert.NoError(t, err)
  346. // assert.NotZero(t, len(txs))
  347. // assert.NoError(t, err)
  348. // assert.Equal(t, 22, position)
  349. // // Test Update L1 TX Batch_num
  350. // assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
  351. // txs[0].BatchNum = common.BatchNum(1)
  352. // txs, err = historyDB.GetL1UserTxs(2)
  353. // assert.NoError(t, err)
  354. // assert.NotZero(t, len(txs))
  355. // assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
  356. */
  357. }
  358. /*
  359. func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
  360. for i := 0; i < len(l1txs); i++ {
  361. tx := l1txs[i].Tx()
  362. fmt.Println("ASDF", i, tx.TxID)
  363. fetchedTx, err := historyDB.GetTx(tx.TxID)
  364. require.NoError(t, err)
  365. test.AssertUSD(t, tx.USD, fetchedTx.USD)
  366. test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
  367. assert.Equal(t, tx, fetchedTx)
  368. }
  369. for i := 0; i < len(l2txs); i++ {
  370. tx := l2txs[i].Tx()
  371. fetchedTx, err := historyDB.GetTx(tx.TxID)
  372. tx.TokenID = fetchedTx.TokenID
  373. assert.NoError(t, err)
  374. test.AssertUSD(t, fetchedTx.USD, tx.USD)
  375. test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
  376. assert.Equal(t, tx, fetchedTx)
  377. }
  378. }
  379. */
  380. func TestExitTree(t *testing.T) {
  381. nBatches := 17
  382. blocks := setTestBlocks(1, 10)
  383. batches := test.GenBatches(nBatches, blocks)
  384. err := historyDB.AddBatches(batches)
  385. assert.NoError(t, err)
  386. const nTokens = 50
  387. tokens, ethToken := test.GenTokens(nTokens, blocks)
  388. err = historyDB.AddTokens(tokens)
  389. assert.NoError(t, err)
  390. tokens = append([]common.Token{ethToken}, tokens...)
  391. const nAccounts = 3
  392. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  393. assert.NoError(t, historyDB.AddAccounts(accs))
  394. exitTree := test.GenExitTree(nBatches, batches, accs)
  395. err = historyDB.AddExitTree(exitTree)
  396. assert.NoError(t, err)
  397. }
  398. func TestGetL1UserTxs(t *testing.T) {
  399. test.WipeDB(historyDB.DB())
  400. set := `
  401. Type: Blockchain
  402. AddToken(1)
  403. AddToken(2)
  404. AddToken(3)
  405. CreateAccountDeposit(1) A: 20
  406. CreateAccountDeposit(2) A: 20
  407. CreateAccountDeposit(1) B: 5
  408. CreateAccountDeposit(1) C: 5
  409. CreateAccountDeposit(1) D: 5
  410. > block
  411. `
  412. tc := til.NewContext(128)
  413. blocks, err := tc.GenerateBlocks(set)
  414. require.Nil(t, err)
  415. // Sanity check
  416. require.Equal(t, 1, len(blocks))
  417. require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
  418. // fmt.Printf("DBG Blocks: %+v\n", blocks)
  419. toForgeL1TxsNum := int64(1)
  420. for i := range blocks {
  421. err = historyDB.AddBlockSCData(&blocks[i])
  422. require.Nil(t, err)
  423. }
  424. l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
  425. require.Nil(t, err)
  426. assert.Equal(t, 5, len(l1UserTxs))
  427. assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
  428. // No l1UserTxs for this toForgeL1TxsNum
  429. l1UserTxs, err = historyDB.GetL1UserTxs(2)
  430. require.Nil(t, err)
  431. assert.Equal(t, 0, len(l1UserTxs))
  432. }
  433. func TestSetInitialSCVars(t *testing.T) {
  434. test.WipeDB(historyDB.DB())
  435. _, _, _, err := historyDB.GetSCVars()
  436. assert.Equal(t, sql.ErrNoRows, err)
  437. //nolint:govet
  438. rollup := &common.RollupVariables{
  439. 0,
  440. big.NewInt(10),
  441. 12,
  442. 13,
  443. }
  444. //nolint:govet
  445. auction := &common.AuctionVariables{
  446. 0,
  447. ethCommon.BigToAddress(big.NewInt(2)),
  448. ethCommon.BigToAddress(big.NewInt(3)),
  449. [6]*big.Int{
  450. big.NewInt(1), big.NewInt(2), big.NewInt(3),
  451. big.NewInt(4), big.NewInt(5), big.NewInt(6),
  452. },
  453. 2,
  454. 4320,
  455. [3]uint16{10, 11, 12},
  456. 1000,
  457. 20,
  458. }
  459. //nolint:govet
  460. wDelayer := &common.WDelayerVariables{
  461. 0,
  462. ethCommon.BigToAddress(big.NewInt(2)),
  463. ethCommon.BigToAddress(big.NewInt(3)),
  464. ethCommon.BigToAddress(big.NewInt(4)),
  465. 13,
  466. 14,
  467. false,
  468. }
  469. err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
  470. require.Nil(t, err)
  471. dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
  472. assert.Nil(t, err)
  473. require.Equal(t, rollup, dbRollup)
  474. require.Equal(t, auction, dbAuction)
  475. require.Equal(t, wDelayer, dbWDelayer)
  476. }
  477. func TestUpdateExitTree(t *testing.T) {
  478. test.WipeDB(historyDB.DB())
  479. set := `
  480. Type: Blockchain
  481. AddToken(1)
  482. CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
  483. CreateAccountDeposit(1) D: 500 // Idx=256+3=259
  484. CreateAccountCoordinator(1) A // Idx=256+0=256
  485. CreateAccountCoordinator(1) B // Idx=256+1=257
  486. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
  487. > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
  488. > block // blockNum=2
  489. ForceExit(1) A: 100
  490. ForceExit(1) B: 80
  491. Exit(1) C: 50 (200)
  492. Exit(1) D: 30 (200)
  493. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
  494. > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
  495. > block // blockNum=3
  496. > block // blockNum=4 (empty block)
  497. `
  498. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  499. tilCfgExtra := til.ConfigExtra{
  500. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  501. CoordUser: "A",
  502. }
  503. blocks, err := tc.GenerateBlocks(set)
  504. require.Nil(t, err)
  505. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  506. assert.Nil(t, err)
  507. // Add all blocks except for the last one
  508. for i := range blocks[:len(blocks)-1] {
  509. err = historyDB.AddBlockSCData(&blocks[i])
  510. require.Nil(t, err)
  511. }
  512. // Add withdraws to the last block, and insert block into the DB
  513. block := &blocks[len(blocks)-1]
  514. require.Equal(t, int64(4), block.Block.EthBlockNum)
  515. block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
  516. common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
  517. common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
  518. common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
  519. common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
  520. )
  521. err = historyDB.addBlock(historyDB.db, &block.Block)
  522. require.Nil(t, err)
  523. // update exit trees in DB
  524. instantWithdrawn := []exitID{}
  525. delayedWithdrawRequest := []exitID{}
  526. for _, withdraw := range block.Rollup.Withdrawals {
  527. exitID := exitID{
  528. batchNum: int64(withdraw.NumExitRoot),
  529. idx: int64(withdraw.Idx),
  530. }
  531. if withdraw.InstantWithdraw {
  532. instantWithdrawn = append(instantWithdrawn, exitID)
  533. } else {
  534. delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
  535. }
  536. }
  537. err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
  538. require.Nil(t, err)
  539. // Check that exits in DB match with the expected values
  540. dbExits, err := historyDB.GetAllExits()
  541. require.Nil(t, err)
  542. assert.Equal(t, 4, len(dbExits))
  543. dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
  544. for _, dbExit := range dbExits {
  545. dbExitsByIdx[dbExit.AccountIdx] = dbExit
  546. }
  547. for _, withdraw := range block.Rollup.Withdrawals {
  548. assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
  549. if withdraw.InstantWithdraw {
  550. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
  551. } else {
  552. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
  553. }
  554. }
  555. }
  556. // setTestBlocks WARNING: this will delete the blocks and recreate them
  557. func setTestBlocks(from, to int64) []common.Block {
  558. test.WipeDB(historyDB.DB())
  559. blocks := test.GenBlocks(from, to)
  560. if err := historyDB.AddBlocks(blocks); err != nil {
  561. panic(err)
  562. }
  563. return blocks
  564. }