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.

681 lines
21 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 = 0
  48. toBlock = 7
  49. // Reset DB
  50. test.WipeDB(historyDB.DB())
  51. // Generate blocks using til
  52. set1 := `
  53. Type: Blockchain
  54. // block 0 is stored as default in the DB
  55. // block 1 does not exist
  56. > block // blockNum=2
  57. > block // blockNum=3
  58. > block // blockNum=4
  59. > block // blockNum=5
  60. > block // blockNum=6
  61. `
  62. tc := til.NewContext(1)
  63. blocks, err := tc.GenerateBlocks(set1)
  64. require.NoError(t, err)
  65. // Save timestamp of a block with UTC and change it without UTC
  66. timestamp := time.Now().Add(time.Second * 13)
  67. blocks[fromBlock].Block.Timestamp = timestamp
  68. // Insert blocks into DB
  69. for i := 0; i < len(blocks); i++ {
  70. err := historyDB.AddBlock(&blocks[i].Block)
  71. assert.NoError(t, err)
  72. }
  73. // Add block 0 to the generated blocks
  74. blocks = append(
  75. []common.BlockData{common.BlockData{Block: test.Block0}}, //nolint:gofmt
  76. blocks...,
  77. )
  78. // Get all blocks from DB
  79. fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
  80. assert.Equal(t, len(blocks), len(fetchedBlocks))
  81. // Compare generated vs getted blocks
  82. assert.NoError(t, err)
  83. for i := range fetchedBlocks {
  84. assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
  85. }
  86. // Compare saved timestamp vs getted
  87. nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
  88. zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
  89. assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
  90. assert.Equal(t, offsetUTC, offsetFetchedBlock)
  91. // Get blocks from the DB one by one
  92. for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
  93. fetchedBlock, err := historyDB.GetBlock(i)
  94. assert.NoError(t, err)
  95. assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
  96. }
  97. // Get last block
  98. lastBlock, err := historyDB.GetLastBlock()
  99. assert.NoError(t, err)
  100. assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
  101. }
  102. func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
  103. assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
  104. assert.Equal(t, expected.Hash, actual.Hash)
  105. assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
  106. }
  107. func TestBatches(t *testing.T) {
  108. // Reset DB
  109. test.WipeDB(historyDB.DB())
  110. // Generate batches using til (and blocks for foreign key)
  111. set := `
  112. Type: Blockchain
  113. AddToken(1) // Will have value in USD
  114. AddToken(2) // Will NOT have value in USD
  115. CreateAccountDeposit(1) A: 2000
  116. CreateAccountDeposit(2) A: 2000
  117. CreateAccountDeposit(1) B: 1000
  118. CreateAccountDeposit(2) B: 1000
  119. > batchL1
  120. > batchL1
  121. Transfer(1) A-B: 100 (5)
  122. Transfer(2) B-A: 100 (199)
  123. > batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
  124. > block
  125. Transfer(1) A-B: 100 (5)
  126. > batch // batchNum=3, L2 only batch, forges transfer (with USD value)
  127. Transfer(2) B-A: 100 (199)
  128. > batch // batchNum=4, L2 only batch, forges transfer (without USD value)
  129. > block
  130. `
  131. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  132. tilCfgExtra := til.ConfigExtra{
  133. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  134. CoordUser: "A",
  135. }
  136. blocks, err := tc.GenerateBlocks(set)
  137. require.Nil(t, err)
  138. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  139. assert.Nil(t, err)
  140. // Insert to DB
  141. batches := []common.Batch{}
  142. tokensValue := make(map[common.TokenID]float64)
  143. lastL1TxsNum := new(int64)
  144. for _, block := range blocks {
  145. // Insert block
  146. assert.NoError(t, historyDB.AddBlock(&block.Block))
  147. // Insert tokens
  148. for i, token := range block.Rollup.AddedTokens {
  149. assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
  150. if i%2 != 0 {
  151. // Set value to the token
  152. value := (float64(i) + 5) * 5.389329
  153. assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
  154. tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
  155. }
  156. }
  157. // Combine all generated batches into single array
  158. for _, batch := range block.Rollup.Batches {
  159. batches = append(batches, batch.Batch)
  160. forgeTxsNum := batch.Batch.ForgeL1TxsNum
  161. if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
  162. *lastL1TxsNum = *forgeTxsNum
  163. }
  164. }
  165. }
  166. // Insert batches
  167. assert.NoError(t, historyDB.AddBatches(batches))
  168. // Set expected total fee
  169. for _, batch := range batches {
  170. total := .0
  171. for tokenID, amount := range batch.CollectedFees {
  172. af := new(big.Float).SetInt(amount)
  173. amountFloat, _ := af.Float64()
  174. total += tokensValue[tokenID] * amountFloat
  175. }
  176. batch.TotalFeesUSD = &total
  177. }
  178. // Get batches from the DB
  179. fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
  180. assert.NoError(t, err)
  181. assert.Equal(t, len(batches), len(fetchedBatches))
  182. for i, fetchedBatch := range fetchedBatches {
  183. assert.Equal(t, batches[i], fetchedBatch)
  184. }
  185. // Test GetLastBatchNum
  186. fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
  187. assert.NoError(t, err)
  188. assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
  189. // Test GetLastL1TxsNum
  190. fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
  191. assert.NoError(t, err)
  192. assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
  193. }
  194. func TestBids(t *testing.T) {
  195. const fromBlock int64 = 1
  196. const toBlock int64 = 5
  197. // Prepare blocks in the DB
  198. blocks := setTestBlocks(fromBlock, toBlock)
  199. // Generate fake coordinators
  200. const nCoords = 5
  201. coords := test.GenCoordinators(nCoords, blocks)
  202. err := historyDB.AddCoordinators(coords)
  203. assert.NoError(t, err)
  204. // Generate fake bids
  205. const nBids = 20
  206. bids := test.GenBids(nBids, blocks, coords)
  207. err = historyDB.AddBids(bids)
  208. assert.NoError(t, err)
  209. // Fetch bids
  210. fetchedBids, err := historyDB.GetAllBids()
  211. assert.NoError(t, err)
  212. // Compare fetched bids vs generated bids
  213. for i, bid := range fetchedBids {
  214. assert.Equal(t, bids[i], bid)
  215. }
  216. }
  217. func TestTokens(t *testing.T) {
  218. const fromBlock int64 = 1
  219. const toBlock int64 = 5
  220. // Prepare blocks in the DB
  221. blocks := setTestBlocks(fromBlock, toBlock)
  222. // Generate fake tokens
  223. const nTokens = 5
  224. tokens, ethToken := test.GenTokens(nTokens, blocks)
  225. err := historyDB.AddTokens(tokens)
  226. assert.NoError(t, err)
  227. tokens = append([]common.Token{ethToken}, tokens...)
  228. limit := uint(10)
  229. // Fetch tokens
  230. fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
  231. assert.NoError(t, err)
  232. // Compare fetched tokens vs generated tokens
  233. // All the tokens should have USDUpdate setted by the DB trigger
  234. for i, token := range fetchedTokens {
  235. assert.Equal(t, tokens[i].TokenID, token.TokenID)
  236. assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
  237. assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
  238. assert.Equal(t, tokens[i].Name, token.Name)
  239. assert.Equal(t, tokens[i].Symbol, token.Symbol)
  240. assert.Nil(t, token.USD)
  241. assert.Nil(t, token.USDUpdate)
  242. }
  243. // Update token value
  244. for i, token := range tokens {
  245. value := 1.01 * float64(i)
  246. assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
  247. }
  248. // Fetch tokens
  249. fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
  250. assert.NoError(t, err)
  251. // Compare fetched tokens vs generated tokens
  252. // All the tokens should have USDUpdate setted by the DB trigger
  253. for i, token := range fetchedTokens {
  254. value := 1.01 * float64(i)
  255. assert.Equal(t, value, *token.USD)
  256. nameZone, offset := token.USDUpdate.Zone()
  257. assert.Equal(t, "UTC", nameZone)
  258. assert.Equal(t, 0, offset)
  259. }
  260. }
  261. func TestAccounts(t *testing.T) {
  262. const fromBlock int64 = 1
  263. const toBlock int64 = 5
  264. // Prepare blocks in the DB
  265. blocks := setTestBlocks(fromBlock, toBlock)
  266. // Generate fake tokens
  267. const nTokens = 5
  268. tokens, ethToken := test.GenTokens(nTokens, blocks)
  269. err := historyDB.AddTokens(tokens)
  270. assert.NoError(t, err)
  271. tokens = append([]common.Token{ethToken}, tokens...)
  272. // Generate fake batches
  273. const nBatches = 10
  274. batches := test.GenBatches(nBatches, blocks)
  275. err = historyDB.AddBatches(batches)
  276. assert.NoError(t, err)
  277. // Generate fake accounts
  278. const nAccounts = 3
  279. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  280. err = historyDB.AddAccounts(accs)
  281. assert.NoError(t, err)
  282. // Fetch accounts
  283. fetchedAccs, err := historyDB.GetAccounts()
  284. assert.NoError(t, err)
  285. // Compare fetched accounts vs generated accounts
  286. for i, acc := range fetchedAccs {
  287. accs[i].Balance = nil
  288. assert.Equal(t, accs[i], acc)
  289. }
  290. }
  291. func TestTxs(t *testing.T) {
  292. // Reset DB
  293. test.WipeDB(historyDB.DB())
  294. // TODO: Generate batches using til (and blocks for foreign key)
  295. set := `
  296. Type: Blockchain
  297. // Things to test:
  298. // One tx of each type
  299. // batches that forge user L1s
  300. // historic USD is not set if USDUpdate is too old (24h)
  301. `
  302. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  303. tilCfgExtra := til.ConfigExtra{
  304. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  305. CoordUser: "A",
  306. }
  307. blocks, err := tc.GenerateBlocks(set)
  308. require.Nil(t, err)
  309. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  310. assert.Nil(t, err)
  311. /*
  312. OLD TEST
  313. const fromBlock int64 = 1
  314. const toBlock int64 = 5
  315. // Prepare blocks in the DB
  316. blocks := setTestBlocks(fromBlock, toBlock)
  317. // Generate fake tokens
  318. const nTokens = 500
  319. tokens, ethToken := test.GenTokens(nTokens, blocks)
  320. err := historyDB.AddTokens(tokens)
  321. assert.NoError(t, err)
  322. tokens = append([]common.Token{ethToken}, tokens...)
  323. // Generate fake batches
  324. const nBatches = 10
  325. batches := test.GenBatches(nBatches, blocks)
  326. err = historyDB.AddBatches(batches)
  327. assert.NoError(t, err)
  328. // Generate fake accounts
  329. const nAccounts = 3
  330. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  331. err = historyDB.AddAccounts(accs)
  332. assert.NoError(t, err)
  333. Uncomment once the transaction generation is fixed
  334. !! test that batches that forge user L1s !!
  335. !! Missing tests to check that !!
  336. // Generate fake L1 txs
  337. const nL1s = 64
  338. _, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
  339. err = historyDB.AddL1Txs(l1txs)
  340. assert.NoError(t, err)
  341. // Generate fake L2 txs
  342. const nL2s = 2048 - nL1s
  343. _, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
  344. err = historyDB.AddL2Txs(l2txs)
  345. assert.NoError(t, err)
  346. // Compare fetched txs vs generated txs.
  347. fetchAndAssertTxs(t, l1txs, l2txs)
  348. // Test trigger: L1 integrity
  349. // from_eth_addr can't be null
  350. l1txs[0].FromEthAddr = ethCommon.Address{}
  351. err = historyDB.AddL1Txs(l1txs)
  352. assert.Error(t, err)
  353. l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
  354. // from_bjj can't be null
  355. l1txs[0].FromBJJ = nil
  356. err = historyDB.AddL1Txs(l1txs)
  357. assert.Error(t, err)
  358. privK := babyjub.NewRandPrivKey()
  359. l1txs[0].FromBJJ = privK.Public()
  360. // load_amount can't be null
  361. l1txs[0].LoadAmount = nil
  362. err = historyDB.AddL1Txs(l1txs)
  363. assert.Error(t, err)
  364. // Test trigger: L2 integrity
  365. // batch_num can't be null
  366. l2txs[0].BatchNum = 0
  367. err = historyDB.AddL2Txs(l2txs)
  368. assert.Error(t, err)
  369. l2txs[0].BatchNum = 1
  370. // nonce can't be null
  371. l2txs[0].Nonce = 0
  372. err = historyDB.AddL2Txs(l2txs)
  373. assert.Error(t, err)
  374. // Test trigger: forge L1 txs
  375. // add next batch to DB
  376. batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
  377. batch := batches[0]
  378. batch.BatchNum = batchNum
  379. batch.ForgeL1TxsNum = toForgeL1TxsNum
  380. assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
  381. // Set batch num in txs that should have been marked as forged in the DB
  382. for i := 0; i < len(l1txs); i++ {
  383. fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
  384. assert.NoError(t, err)
  385. if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
  386. assert.Equal(t, batchNum, *fetchedTx.BatchNum)
  387. } else {
  388. if fetchedTx.BatchNum != nil {
  389. assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
  390. }
  391. }
  392. }
  393. // Test helper functions for Synchronizer
  394. // GetLastTxsPosition
  395. expectedPosition := -1
  396. var choosenToForgeL1TxsNum int64 = -1
  397. for _, tx := range l1txs {
  398. if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
  399. choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
  400. expectedPosition = tx.Position
  401. } else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
  402. expectedPosition = tx.Position
  403. }
  404. }
  405. position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
  406. assert.NoError(t, err)
  407. assert.Equal(t, expectedPosition, position)
  408. // GetL1UserTxs: not needed? tests were broken
  409. // txs, err := historyDB.GetL1UserTxs(2)
  410. // assert.NoError(t, err)
  411. // assert.NotZero(t, len(txs))
  412. // assert.NoError(t, err)
  413. // assert.Equal(t, 22, position)
  414. // // Test Update L1 TX Batch_num
  415. // assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
  416. // txs[0].BatchNum = common.BatchNum(1)
  417. // txs, err = historyDB.GetL1UserTxs(2)
  418. // assert.NoError(t, err)
  419. // assert.NotZero(t, len(txs))
  420. // assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
  421. */
  422. }
  423. /*
  424. func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
  425. for i := 0; i < len(l1txs); i++ {
  426. tx := l1txs[i].Tx()
  427. fmt.Println("ASDF", i, tx.TxID)
  428. fetchedTx, err := historyDB.GetTx(tx.TxID)
  429. require.NoError(t, err)
  430. test.AssertUSD(t, tx.USD, fetchedTx.USD)
  431. test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
  432. assert.Equal(t, tx, fetchedTx)
  433. }
  434. for i := 0; i < len(l2txs); i++ {
  435. tx := l2txs[i].Tx()
  436. fetchedTx, err := historyDB.GetTx(tx.TxID)
  437. tx.TokenID = fetchedTx.TokenID
  438. assert.NoError(t, err)
  439. test.AssertUSD(t, fetchedTx.USD, tx.USD)
  440. test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
  441. assert.Equal(t, tx, fetchedTx)
  442. }
  443. }
  444. */
  445. func TestExitTree(t *testing.T) {
  446. nBatches := 17
  447. blocks := setTestBlocks(1, 10)
  448. batches := test.GenBatches(nBatches, blocks)
  449. err := historyDB.AddBatches(batches)
  450. assert.NoError(t, err)
  451. const nTokens = 50
  452. tokens, ethToken := test.GenTokens(nTokens, blocks)
  453. err = historyDB.AddTokens(tokens)
  454. assert.NoError(t, err)
  455. tokens = append([]common.Token{ethToken}, tokens...)
  456. const nAccounts = 3
  457. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  458. assert.NoError(t, historyDB.AddAccounts(accs))
  459. exitTree := test.GenExitTree(nBatches, batches, accs)
  460. err = historyDB.AddExitTree(exitTree)
  461. assert.NoError(t, err)
  462. }
  463. func TestGetL1UserTxs(t *testing.T) {
  464. test.WipeDB(historyDB.DB())
  465. set := `
  466. Type: Blockchain
  467. AddToken(1)
  468. AddToken(2)
  469. AddToken(3)
  470. CreateAccountDeposit(1) A: 20
  471. CreateAccountDeposit(2) A: 20
  472. CreateAccountDeposit(1) B: 5
  473. CreateAccountDeposit(1) C: 5
  474. CreateAccountDeposit(1) D: 5
  475. > block
  476. `
  477. tc := til.NewContext(128)
  478. blocks, err := tc.GenerateBlocks(set)
  479. require.Nil(t, err)
  480. // Sanity check
  481. require.Equal(t, 1, len(blocks))
  482. require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
  483. // fmt.Printf("DBG Blocks: %+v\n", blocks)
  484. toForgeL1TxsNum := int64(1)
  485. for i := range blocks {
  486. err = historyDB.AddBlockSCData(&blocks[i])
  487. require.Nil(t, err)
  488. }
  489. l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
  490. require.Nil(t, err)
  491. assert.Equal(t, 5, len(l1UserTxs))
  492. assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
  493. // No l1UserTxs for this toForgeL1TxsNum
  494. l1UserTxs, err = historyDB.GetL1UserTxs(2)
  495. require.Nil(t, err)
  496. assert.Equal(t, 0, len(l1UserTxs))
  497. }
  498. func TestSetInitialSCVars(t *testing.T) {
  499. test.WipeDB(historyDB.DB())
  500. _, _, _, err := historyDB.GetSCVars()
  501. assert.Equal(t, sql.ErrNoRows, err)
  502. //nolint:govet
  503. rollup := &common.RollupVariables{
  504. 0,
  505. big.NewInt(10),
  506. 12,
  507. 13,
  508. [5]common.Bucket{},
  509. }
  510. //nolint:govet
  511. auction := &common.AuctionVariables{
  512. 0,
  513. ethCommon.BigToAddress(big.NewInt(2)),
  514. ethCommon.BigToAddress(big.NewInt(3)),
  515. [6]*big.Int{
  516. big.NewInt(1), big.NewInt(2), big.NewInt(3),
  517. big.NewInt(4), big.NewInt(5), big.NewInt(6),
  518. },
  519. 2,
  520. 4320,
  521. [3]uint16{10, 11, 12},
  522. 1000,
  523. 20,
  524. }
  525. //nolint:govet
  526. wDelayer := &common.WDelayerVariables{
  527. 0,
  528. ethCommon.BigToAddress(big.NewInt(2)),
  529. ethCommon.BigToAddress(big.NewInt(3)),
  530. ethCommon.BigToAddress(big.NewInt(4)),
  531. 13,
  532. 14,
  533. false,
  534. }
  535. err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
  536. require.Nil(t, err)
  537. dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
  538. assert.Nil(t, err)
  539. require.Equal(t, rollup, dbRollup)
  540. require.Equal(t, auction, dbAuction)
  541. require.Equal(t, wDelayer, dbWDelayer)
  542. }
  543. func TestUpdateExitTree(t *testing.T) {
  544. test.WipeDB(historyDB.DB())
  545. set := `
  546. Type: Blockchain
  547. AddToken(1)
  548. CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
  549. CreateAccountDeposit(1) D: 500 // Idx=256+3=259
  550. CreateAccountCoordinator(1) A // Idx=256+0=256
  551. CreateAccountCoordinator(1) B // Idx=256+1=257
  552. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
  553. > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
  554. > block // blockNum=2
  555. ForceExit(1) A: 100
  556. ForceExit(1) B: 80
  557. Exit(1) C: 50 (200)
  558. Exit(1) D: 30 (200)
  559. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
  560. > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
  561. > block // blockNum=3
  562. > block // blockNum=4 (empty block)
  563. `
  564. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  565. tilCfgExtra := til.ConfigExtra{
  566. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  567. CoordUser: "A",
  568. }
  569. blocks, err := tc.GenerateBlocks(set)
  570. require.Nil(t, err)
  571. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  572. assert.Nil(t, err)
  573. // Add all blocks except for the last one
  574. for i := range blocks[:len(blocks)-1] {
  575. err = historyDB.AddBlockSCData(&blocks[i])
  576. require.Nil(t, err)
  577. }
  578. // Add withdraws to the last block, and insert block into the DB
  579. block := &blocks[len(blocks)-1]
  580. require.Equal(t, int64(4), block.Block.EthBlockNum)
  581. block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
  582. common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
  583. common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
  584. common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
  585. common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
  586. )
  587. err = historyDB.addBlock(historyDB.db, &block.Block)
  588. require.Nil(t, err)
  589. // update exit trees in DB
  590. instantWithdrawn := []exitID{}
  591. delayedWithdrawRequest := []exitID{}
  592. for _, withdraw := range block.Rollup.Withdrawals {
  593. exitID := exitID{
  594. batchNum: int64(withdraw.NumExitRoot),
  595. idx: int64(withdraw.Idx),
  596. }
  597. if withdraw.InstantWithdraw {
  598. instantWithdrawn = append(instantWithdrawn, exitID)
  599. } else {
  600. delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
  601. }
  602. }
  603. err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
  604. require.Nil(t, err)
  605. // Check that exits in DB match with the expected values
  606. dbExits, err := historyDB.GetAllExits()
  607. require.Nil(t, err)
  608. assert.Equal(t, 4, len(dbExits))
  609. dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
  610. for _, dbExit := range dbExits {
  611. dbExitsByIdx[dbExit.AccountIdx] = dbExit
  612. }
  613. for _, withdraw := range block.Rollup.Withdrawals {
  614. assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
  615. if withdraw.InstantWithdraw {
  616. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
  617. } else {
  618. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
  619. }
  620. }
  621. }
  622. // setTestBlocks WARNING: this will delete the blocks and recreate them
  623. func setTestBlocks(from, to int64) []common.Block {
  624. test.WipeDB(historyDB.DB())
  625. blocks := test.GenBlocks(from, to)
  626. if err := historyDB.AddBlocks(blocks); err != nil {
  627. panic(err)
  628. }
  629. return blocks
  630. }