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.

867 lines
27 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
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
4 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
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.GetAllAccounts()
  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. set := `
  295. Type: Blockchain
  296. AddToken(1)
  297. AddToken(2)
  298. CreateAccountDeposit(1) A: 10
  299. CreateAccountDeposit(1) B: 10
  300. > batchL1
  301. > batchL1
  302. > block
  303. CreateAccountDepositTransfer(1) C-A: 20, 10
  304. CreateAccountCoordinator(1) User0
  305. > batchL1
  306. > batchL1
  307. > block
  308. Deposit(1) B: 10
  309. Deposit(1) C: 10
  310. Transfer(1) C-A : 10 (1)
  311. Transfer(1) B-C : 10 (1)
  312. Transfer(1) A-B : 10 (1)
  313. Exit(1) A: 10 (1)
  314. > batch
  315. > block
  316. DepositTransfer(1) A-B: 10, 10
  317. > batchL1
  318. > block
  319. ForceTransfer(1) A-B: 10
  320. ForceExit(1) A: 5
  321. > batchL1
  322. > batchL1
  323. > block
  324. CreateAccountDeposit(2) D: 10
  325. > batchL1
  326. > block
  327. CreateAccountDeposit(2) E: 10
  328. > batchL1
  329. > batchL1
  330. > block
  331. `
  332. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  333. tilCfgExtra := til.ConfigExtra{
  334. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  335. CoordUser: "A",
  336. }
  337. blocks, err := tc.GenerateBlocks(set)
  338. require.Nil(t, err)
  339. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  340. assert.Nil(t, err)
  341. // Sanity check
  342. require.Equal(t, 7, len(blocks))
  343. require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
  344. require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
  345. require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
  346. require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
  347. require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
  348. require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
  349. require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
  350. var null *common.BatchNum = nil
  351. var txID common.TxID
  352. // Insert blocks into DB
  353. for i := range blocks {
  354. if i == len(blocks)-1 {
  355. blocks[i].Block.Timestamp = time.Now()
  356. dbL1Txs, err := historyDB.GetAllL1UserTxs()
  357. assert.NoError(t, err)
  358. // Check batch_num is nil before forging
  359. assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
  360. // Save this TxId
  361. txID = dbL1Txs[len(dbL1Txs)-1].TxID
  362. }
  363. err = historyDB.AddBlockSCData(&blocks[i])
  364. assert.NoError(t, err)
  365. }
  366. // Check blocks
  367. dbBlocks, err := historyDB.GetAllBlocks()
  368. assert.NoError(t, err)
  369. assert.Equal(t, len(blocks)+1, len(dbBlocks))
  370. // Check batches
  371. batches, err := historyDB.GetAllBatches()
  372. assert.NoError(t, err)
  373. assert.Equal(t, 11, len(batches))
  374. // Check L1 Transactions
  375. dbL1Txs, err := historyDB.GetAllL1UserTxs()
  376. assert.NoError(t, err)
  377. assert.Equal(t, 10, len(dbL1Txs))
  378. // Tx Type
  379. assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
  380. assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
  381. assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
  382. assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
  383. assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
  384. assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
  385. assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
  386. assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
  387. assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
  388. assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
  389. // Tx ID
  390. assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
  391. assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
  392. assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
  393. assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
  394. assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
  395. assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
  396. assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
  397. assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
  398. assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
  399. assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
  400. // Tx From IDx
  401. assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
  402. assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
  403. assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
  404. assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
  405. assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
  406. assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
  407. assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
  408. assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
  409. assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
  410. assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
  411. assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
  412. assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
  413. assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
  414. // Tx to IDx
  415. assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
  416. assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
  417. assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
  418. // Token ID
  419. assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
  420. assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
  421. assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
  422. assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
  423. assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
  424. assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
  425. assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
  426. assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
  427. assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
  428. assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
  429. // Batch Number
  430. var bn common.BatchNum = common.BatchNum(2)
  431. assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
  432. assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
  433. bn = common.BatchNum(4)
  434. assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
  435. bn = common.BatchNum(7)
  436. assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
  437. assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
  438. assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
  439. bn = common.BatchNum(8)
  440. assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
  441. assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
  442. bn = common.BatchNum(10)
  443. assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
  444. bn = common.BatchNum(11)
  445. assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
  446. // eth_block_num
  447. assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
  448. assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
  449. assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
  450. assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
  451. assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
  452. assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
  453. assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
  454. assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
  455. assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
  456. assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
  457. // User Origin
  458. assert.Equal(t, true, dbL1Txs[0].UserOrigin)
  459. assert.Equal(t, true, dbL1Txs[1].UserOrigin)
  460. assert.Equal(t, true, dbL1Txs[2].UserOrigin)
  461. assert.Equal(t, true, dbL1Txs[3].UserOrigin)
  462. assert.Equal(t, true, dbL1Txs[4].UserOrigin)
  463. assert.Equal(t, true, dbL1Txs[5].UserOrigin)
  464. assert.Equal(t, true, dbL1Txs[6].UserOrigin)
  465. assert.Equal(t, true, dbL1Txs[7].UserOrigin)
  466. assert.Equal(t, true, dbL1Txs[8].UserOrigin)
  467. assert.Equal(t, true, dbL1Txs[9].UserOrigin)
  468. // Load Amount
  469. assert.Equal(t, big.NewInt(10), dbL1Txs[0].LoadAmount)
  470. assert.Equal(t, big.NewInt(10), dbL1Txs[1].LoadAmount)
  471. assert.Equal(t, big.NewInt(20), dbL1Txs[2].LoadAmount)
  472. assert.Equal(t, big.NewInt(10), dbL1Txs[3].LoadAmount)
  473. assert.Equal(t, big.NewInt(10), dbL1Txs[4].LoadAmount)
  474. assert.Equal(t, big.NewInt(10), dbL1Txs[5].LoadAmount)
  475. assert.Equal(t, big.NewInt(0), dbL1Txs[6].LoadAmount)
  476. assert.Equal(t, big.NewInt(0), dbL1Txs[7].LoadAmount)
  477. assert.Equal(t, big.NewInt(10), dbL1Txs[8].LoadAmount)
  478. assert.Equal(t, big.NewInt(10), dbL1Txs[9].LoadAmount)
  479. // Check saved txID's batch_num is not nil
  480. assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
  481. assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
  482. // Check Coordinator TXs
  483. coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
  484. assert.NoError(t, err)
  485. assert.Equal(t, 1, len(coordTxs))
  486. assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
  487. assert.Equal(t, false, coordTxs[0].UserOrigin)
  488. // Check L2 TXs
  489. dbL2Txs, err := historyDB.GetAllL2Txs()
  490. assert.NoError(t, err)
  491. assert.Equal(t, 4, len(dbL2Txs))
  492. // Tx Type
  493. assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
  494. assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
  495. assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
  496. assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
  497. // Tx ID
  498. assert.Equal(t, "0x020000000001030000000001", dbL2Txs[0].TxID.String())
  499. assert.Equal(t, "0x020000000001010000000001", dbL2Txs[1].TxID.String())
  500. assert.Equal(t, "0x020000000001000000000001", dbL2Txs[2].TxID.String())
  501. assert.Equal(t, "0x020000000001000000000002", dbL2Txs[3].TxID.String())
  502. // Tx From and To IDx
  503. assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
  504. assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
  505. assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
  506. // Batch Number
  507. assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
  508. assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
  509. assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
  510. assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
  511. // eth_block_num
  512. assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
  513. assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
  514. assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
  515. // Amount
  516. assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
  517. assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
  518. assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
  519. assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
  520. }
  521. func TestExitTree(t *testing.T) {
  522. nBatches := 17
  523. blocks := setTestBlocks(1, 10)
  524. batches := test.GenBatches(nBatches, blocks)
  525. err := historyDB.AddBatches(batches)
  526. assert.NoError(t, err)
  527. const nTokens = 50
  528. tokens, ethToken := test.GenTokens(nTokens, blocks)
  529. err = historyDB.AddTokens(tokens)
  530. assert.NoError(t, err)
  531. tokens = append([]common.Token{ethToken}, tokens...)
  532. const nAccounts = 3
  533. accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
  534. assert.NoError(t, historyDB.AddAccounts(accs))
  535. exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
  536. err = historyDB.AddExitTree(exitTree)
  537. assert.NoError(t, err)
  538. }
  539. func TestGetL1UserTxs(t *testing.T) {
  540. test.WipeDB(historyDB.DB())
  541. set := `
  542. Type: Blockchain
  543. AddToken(1)
  544. AddToken(2)
  545. AddToken(3)
  546. CreateAccountDeposit(1) A: 20
  547. CreateAccountDeposit(2) A: 20
  548. CreateAccountDeposit(1) B: 5
  549. CreateAccountDeposit(1) C: 5
  550. CreateAccountDeposit(1) D: 5
  551. > block
  552. `
  553. tc := til.NewContext(128)
  554. blocks, err := tc.GenerateBlocks(set)
  555. require.Nil(t, err)
  556. // Sanity check
  557. require.Equal(t, 1, len(blocks))
  558. require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
  559. toForgeL1TxsNum := int64(1)
  560. for i := range blocks {
  561. err = historyDB.AddBlockSCData(&blocks[i])
  562. require.Nil(t, err)
  563. }
  564. l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
  565. require.Nil(t, err)
  566. assert.Equal(t, 5, len(l1UserTxs))
  567. assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
  568. // No l1UserTxs for this toForgeL1TxsNum
  569. l1UserTxs, err = historyDB.GetL1UserTxs(2)
  570. require.Nil(t, err)
  571. assert.Equal(t, 0, len(l1UserTxs))
  572. }
  573. func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
  574. //nolint:govet
  575. rollup := &common.RollupVariables{
  576. 0,
  577. big.NewInt(10),
  578. 12,
  579. 13,
  580. [5]common.Bucket{},
  581. }
  582. //nolint:govet
  583. auction := &common.AuctionVariables{
  584. 0,
  585. ethCommon.BigToAddress(big.NewInt(2)),
  586. ethCommon.BigToAddress(big.NewInt(3)),
  587. [6]*big.Int{
  588. big.NewInt(1), big.NewInt(2), big.NewInt(3),
  589. big.NewInt(4), big.NewInt(5), big.NewInt(6),
  590. },
  591. 0,
  592. 2,
  593. 4320,
  594. [3]uint16{10, 11, 12},
  595. 1000,
  596. 20,
  597. }
  598. //nolint:govet
  599. wDelayer := &common.WDelayerVariables{
  600. 0,
  601. ethCommon.BigToAddress(big.NewInt(2)),
  602. ethCommon.BigToAddress(big.NewInt(3)),
  603. ethCommon.BigToAddress(big.NewInt(4)),
  604. 13,
  605. 14,
  606. false,
  607. }
  608. return rollup, auction, wDelayer
  609. }
  610. func TestSetInitialSCVars(t *testing.T) {
  611. test.WipeDB(historyDB.DB())
  612. _, _, _, err := historyDB.GetSCVars()
  613. assert.Equal(t, sql.ErrNoRows, err)
  614. rollup, auction, wDelayer := exampleInitSCVars()
  615. err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
  616. require.Nil(t, err)
  617. dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
  618. assert.Nil(t, err)
  619. require.Equal(t, rollup, dbRollup)
  620. require.Equal(t, auction, dbAuction)
  621. require.Equal(t, wDelayer, dbWDelayer)
  622. }
  623. func TestUpdateExitTree(t *testing.T) {
  624. test.WipeDB(historyDB.DB())
  625. set := `
  626. Type: Blockchain
  627. AddToken(1)
  628. CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
  629. CreateAccountDeposit(1) D: 500 // Idx=256+3=259
  630. CreateAccountCoordinator(1) A // Idx=256+0=256
  631. CreateAccountCoordinator(1) B // Idx=256+1=257
  632. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
  633. > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
  634. > block // blockNum=2
  635. ForceExit(1) A: 100
  636. ForceExit(1) B: 80
  637. Exit(1) C: 50 (172)
  638. Exit(1) D: 30 (172)
  639. > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
  640. > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
  641. > block // blockNum=3
  642. > block // blockNum=4 (empty block)
  643. > block // blockNum=5 (empty block)
  644. `
  645. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  646. tilCfgExtra := til.ConfigExtra{
  647. BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
  648. CoordUser: "A",
  649. }
  650. blocks, err := tc.GenerateBlocks(set)
  651. require.Nil(t, err)
  652. err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
  653. assert.Nil(t, err)
  654. // Add all blocks except for the last two
  655. for i := range blocks[:len(blocks)-2] {
  656. err = historyDB.AddBlockSCData(&blocks[i])
  657. require.Nil(t, err)
  658. }
  659. // Add withdraws to the second-to-last block, and insert block into the DB
  660. block := &blocks[len(blocks)-2]
  661. require.Equal(t, int64(4), block.Block.EthBlockNum)
  662. tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
  663. // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
  664. // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
  665. // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
  666. // )
  667. block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
  668. common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
  669. common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
  670. Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
  671. common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
  672. common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
  673. Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
  674. )
  675. err = historyDB.addBlock(historyDB.db, &block.Block)
  676. require.Nil(t, err)
  677. err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
  678. block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
  679. require.Nil(t, err)
  680. // Check that exits in DB match with the expected values
  681. dbExits, err := historyDB.GetAllExits()
  682. require.Nil(t, err)
  683. assert.Equal(t, 4, len(dbExits))
  684. dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
  685. for _, dbExit := range dbExits {
  686. dbExitsByIdx[dbExit.AccountIdx] = dbExit
  687. }
  688. for _, withdraw := range block.Rollup.Withdrawals {
  689. assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
  690. if withdraw.InstantWithdraw {
  691. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
  692. } else {
  693. assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
  694. }
  695. }
  696. // Add delayed withdraw to the last block, and insert block into the DB
  697. block = &blocks[len(blocks)-1]
  698. require.Equal(t, int64(5), block.Block.EthBlockNum)
  699. block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
  700. common.WDelayerTransfer{
  701. Owner: tc.UsersByIdx[257].Addr,
  702. Token: tokenAddr,
  703. Amount: big.NewInt(80),
  704. })
  705. err = historyDB.addBlock(historyDB.db, &block.Block)
  706. require.Nil(t, err)
  707. err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
  708. block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
  709. require.Nil(t, err)
  710. // Check that delayed withdrawn has been set
  711. dbExits, err = historyDB.GetAllExits()
  712. require.Nil(t, err)
  713. for _, dbExit := range dbExits {
  714. dbExitsByIdx[dbExit.AccountIdx] = dbExit
  715. }
  716. require.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[257].DelayedWithdrawn)
  717. }
  718. func TestGetBestBidCoordinator(t *testing.T) {
  719. test.WipeDB(historyDB.DB())
  720. rollup, auction, wDelayer := exampleInitSCVars()
  721. err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
  722. require.Nil(t, err)
  723. tc := til.NewContext(common.RollupConstMaxL1UserTx)
  724. blocks, err := tc.GenerateBlocks(`
  725. Type: Blockchain
  726. > block // blockNum=2
  727. `)
  728. require.Nil(t, err)
  729. err = historyDB.AddBlockSCData(&blocks[0])
  730. require.Nil(t, err)
  731. coords := []common.Coordinator{
  732. {
  733. Bidder: ethCommon.BigToAddress(big.NewInt(1)),
  734. Forger: ethCommon.BigToAddress(big.NewInt(2)),
  735. EthBlockNum: 2,
  736. URL: "foo",
  737. },
  738. {
  739. Bidder: ethCommon.BigToAddress(big.NewInt(3)),
  740. Forger: ethCommon.BigToAddress(big.NewInt(4)),
  741. EthBlockNum: 2,
  742. URL: "bar",
  743. },
  744. }
  745. err = historyDB.addCoordinators(historyDB.db, coords)
  746. require.Nil(t, err)
  747. err = historyDB.addBids(historyDB.db, []common.Bid{
  748. {
  749. SlotNum: 10,
  750. BidValue: big.NewInt(10),
  751. EthBlockNum: 2,
  752. Bidder: coords[0].Bidder,
  753. },
  754. {
  755. SlotNum: 10,
  756. BidValue: big.NewInt(20),
  757. EthBlockNum: 2,
  758. Bidder: coords[1].Bidder,
  759. },
  760. })
  761. require.Nil(t, err)
  762. forger10, err := historyDB.GetBestBidCoordinator(10)
  763. require.Nil(t, err)
  764. require.Equal(t, coords[1].Forger, forger10.Forger)
  765. require.Equal(t, coords[1].Bidder, forger10.Bidder)
  766. require.Equal(t, coords[1].URL, forger10.URL)
  767. _, err = historyDB.GetBestBidCoordinator(11)
  768. require.Equal(t, sql.ErrNoRows, err)
  769. }
  770. // setTestBlocks WARNING: this will delete the blocks and recreate them
  771. func setTestBlocks(from, to int64) []common.Block {
  772. test.WipeDB(historyDB.DB())
  773. blocks := test.GenBlocks(from, to)
  774. if err := historyDB.AddBlocks(blocks); err != nil {
  775. panic(err)
  776. }
  777. return blocks
  778. }