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.

1127 lines
37 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 coordinator to work better under real net - cli / node - Update handler of SIGINT so that after 3 SIGINTs, the process terminates unconditionally - coordinator - Store stats without pointer - In all functions that send a variable via channel, check for context done to avoid deadlock (due to no process reading from the channel, which has no queue) when the node is stopped. - Abstract `canForge` so that it can be used outside of the `Coordinator` - In `canForge` check the blockNumber in current and next slot. - Update tests due to smart contract changes in slot handling, and minimum bid defaults - TxManager - Add consts, vars and stats to allow evaluating `canForge` - Add `canForge` method (not used yet) - Store batch and nonces status (last success and last pending) - Track nonces internally instead of relying on the ethereum node (this is required to work with ganache when there are pending txs) - Handle the (common) case of the receipt not being found after the tx is sent. - Don't start the main loop until we get an initial messae fo the stats and vars (so that in the loop the stats and vars are set to synchronizer values) - When a tx fails, check and discard all the failed transactions before sending the message to stop the pipeline. This will avoid sending consecutive messages of stop the pipeline when multiple txs are detected to be failed consecutively. Also, future txs of the same pipeline after a discarded txs are discarded, and their nonces reused. - Robust handling of nonces: - If geth returns nonce is too low, increase it - If geth returns nonce too hight, decrease it - If geth returns underpriced, increase gas price - If geth returns replace underpriced, increase gas price - Add support for resending transactions after a timeout - Store `BatchInfos` in a queue - Pipeline - When an error is found, stop forging batches and send a message to the coordinator to stop the pipeline with information of the failed batch number so that in a restart, non-failed batches are not repated. - When doing a reset of the stateDB, if possible reset from the local checkpoint instead of resetting from the synchronizer. This allows resetting from a batch that is valid but not yet sent / synced. - Every time a pipeline is started, assign it a number from a counter. This allows the TxManager to ignore batches from stopped pipelines, via a message sent by the coordinator. - Avoid forging when we haven't reached the rollup genesis block number. - Add config parameter `StartSlotBlocksDelay`: StartSlotBlocksDelay is the number of blocks of delay to wait before starting the pipeline when we reach a slot in which we can forge. - When detecting a reorg, only reset the pipeline if the batch from which the pipeline started changed and wasn't sent by us. - Add config parameter `ScheduleBatchBlocksAheadCheck`: ScheduleBatchBlocksAheadCheck is the number of blocks ahead in which the forger address is checked to be allowed to forge (apart from checking the next block), used to decide when to stop scheduling new batches (by stopping the pipeline). For example, if we are at block 10 and ScheduleBatchBlocksAheadCheck is 5, eventhough at block 11 we canForge, the pipeline will be stopped if we can't forge at block 15. This value should be the expected number of blocks it takes between scheduling a batch and having it mined. - Add config parameter `SendBatchBlocksMarginCheck`: SendBatchBlocksMarginCheck is the number of margin blocks ahead in which the coordinator is also checked to be allowed to forge, apart from the next block; used to decide when to stop sending batches to the smart contract. For example, if we are at block 10 and SendBatchBlocksMarginCheck is 5, eventhough at block 11 we canForge, the batch will be discarded if we can't forge at block 15. - Add config parameter `TxResendTimeout`: TxResendTimeout is the timeout after which a non-mined ethereum transaction will be resent (reusing the nonce) with a newly calculated gas price - Add config parameter `MaxGasPrice`: MaxGasPrice is the maximum gas price allowed for ethereum transactions - Add config parameter `NoReuseNonce`: NoReuseNonce disables reusing nonces of pending transactions for new replacement transactions. This is useful for testing with Ganache. - Extend BatchInfo with more useful information for debugging - eth / ethereum client - Add necessary methods to create the auth object for transactions manually so that we can set the nonce, gas price, gas limit, etc manually - Update `RollupForgeBatch` to take an auth object as input (so that the coordinator can set parameters manually) - synchronizer - In stats, add `NextSlot` - In stats, store full last batch instead of just last batch number - Instead of calculating a nextSlot from scratch every time, update the current struct (only updating the forger info if we are Synced) - Afer every processed batch, check that the calculated StateDB MTRoot matches the StateRoot found in the forgeBatch event.
3 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.
3 years ago
Update coordinator to work better under real net - cli / node - Update handler of SIGINT so that after 3 SIGINTs, the process terminates unconditionally - coordinator - Store stats without pointer - In all functions that send a variable via channel, check for context done to avoid deadlock (due to no process reading from the channel, which has no queue) when the node is stopped. - Abstract `canForge` so that it can be used outside of the `Coordinator` - In `canForge` check the blockNumber in current and next slot. - Update tests due to smart contract changes in slot handling, and minimum bid defaults - TxManager - Add consts, vars and stats to allow evaluating `canForge` - Add `canForge` method (not used yet) - Store batch and nonces status (last success and last pending) - Track nonces internally instead of relying on the ethereum node (this is required to work with ganache when there are pending txs) - Handle the (common) case of the receipt not being found after the tx is sent. - Don't start the main loop until we get an initial messae fo the stats and vars (so that in the loop the stats and vars are set to synchronizer values) - When a tx fails, check and discard all the failed transactions before sending the message to stop the pipeline. This will avoid sending consecutive messages of stop the pipeline when multiple txs are detected to be failed consecutively. Also, future txs of the same pipeline after a discarded txs are discarded, and their nonces reused. - Robust handling of nonces: - If geth returns nonce is too low, increase it - If geth returns nonce too hight, decrease it - If geth returns underpriced, increase gas price - If geth returns replace underpriced, increase gas price - Add support for resending transactions after a timeout - Store `BatchInfos` in a queue - Pipeline - When an error is found, stop forging batches and send a message to the coordinator to stop the pipeline with information of the failed batch number so that in a restart, non-failed batches are not repated. - When doing a reset of the stateDB, if possible reset from the local checkpoint instead of resetting from the synchronizer. This allows resetting from a batch that is valid but not yet sent / synced. - Every time a pipeline is started, assign it a number from a counter. This allows the TxManager to ignore batches from stopped pipelines, via a message sent by the coordinator. - Avoid forging when we haven't reached the rollup genesis block number. - Add config parameter `StartSlotBlocksDelay`: StartSlotBlocksDelay is the number of blocks of delay to wait before starting the pipeline when we reach a slot in which we can forge. - When detecting a reorg, only reset the pipeline if the batch from which the pipeline started changed and wasn't sent by us. - Add config parameter `ScheduleBatchBlocksAheadCheck`: ScheduleBatchBlocksAheadCheck is the number of blocks ahead in which the forger address is checked to be allowed to forge (apart from checking the next block), used to decide when to stop scheduling new batches (by stopping the pipeline). For example, if we are at block 10 and ScheduleBatchBlocksAheadCheck is 5, eventhough at block 11 we canForge, the pipeline will be stopped if we can't forge at block 15. This value should be the expected number of blocks it takes between scheduling a batch and having it mined. - Add config parameter `SendBatchBlocksMarginCheck`: SendBatchBlocksMarginCheck is the number of margin blocks ahead in which the coordinator is also checked to be allowed to forge, apart from the next block; used to decide when to stop sending batches to the smart contract. For example, if we are at block 10 and SendBatchBlocksMarginCheck is 5, eventhough at block 11 we canForge, the batch will be discarded if we can't forge at block 15. - Add config parameter `TxResendTimeout`: TxResendTimeout is the timeout after which a non-mined ethereum transaction will be resent (reusing the nonce) with a newly calculated gas price - Add config parameter `MaxGasPrice`: MaxGasPrice is the maximum gas price allowed for ethereum transactions - Add config parameter `NoReuseNonce`: NoReuseNonce disables reusing nonces of pending transactions for new replacement transactions. This is useful for testing with Ganache. - Extend BatchInfo with more useful information for debugging - eth / ethereum client - Add necessary methods to create the auth object for transactions manually so that we can set the nonce, gas price, gas limit, etc manually - Update `RollupForgeBatch` to take an auth object as input (so that the coordinator can set parameters manually) - synchronizer - In stats, add `NextSlot` - In stats, store full last batch instead of just last batch number - Instead of calculating a nextSlot from scratch every time, update the current struct (only updating the forger info if we are Synced) - Afer every processed batch, check that the calculated StateDB MTRoot matches the StateRoot found in the forgeBatch event.
3 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
3 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
3 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.
3 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.
3 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.
3 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.
3 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.
3 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.
3 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 coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
3 years ago
  1. package historydb
  2. import (
  3. "math"
  4. "math/big"
  5. "strings"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/db"
  9. "github.com/hermeznetwork/tracerr"
  10. "github.com/jmoiron/sqlx"
  11. //nolint:errcheck // driver for postgres DB
  12. _ "github.com/lib/pq"
  13. "github.com/russross/meddler"
  14. )
  15. const (
  16. // OrderAsc indicates ascending order when using pagination
  17. OrderAsc = "ASC"
  18. // OrderDesc indicates descending order when using pagination
  19. OrderDesc = "DESC"
  20. )
  21. // TODO(Edu): Document here how HistoryDB is kept consistent
  22. // HistoryDB persist the historic of the rollup
  23. type HistoryDB struct {
  24. db *sqlx.DB
  25. apiConnCon *db.APIConnectionController
  26. }
  27. // NewHistoryDB initialize the DB
  28. func NewHistoryDB(db *sqlx.DB, apiConnCon *db.APIConnectionController) *HistoryDB {
  29. return &HistoryDB{db: db, apiConnCon: apiConnCon}
  30. }
  31. // DB returns a pointer to the L2DB.db. This method should be used only for
  32. // internal testing purposes.
  33. func (hdb *HistoryDB) DB() *sqlx.DB {
  34. return hdb.db
  35. }
  36. // AddBlock insert a block into the DB
  37. func (hdb *HistoryDB) AddBlock(block *common.Block) error { return hdb.addBlock(hdb.db, block) }
  38. func (hdb *HistoryDB) addBlock(d meddler.DB, block *common.Block) error {
  39. return tracerr.Wrap(meddler.Insert(d, "block", block))
  40. }
  41. // AddBlocks inserts blocks into the DB
  42. func (hdb *HistoryDB) AddBlocks(blocks []common.Block) error {
  43. return tracerr.Wrap(hdb.addBlocks(hdb.db, blocks))
  44. }
  45. func (hdb *HistoryDB) addBlocks(d meddler.DB, blocks []common.Block) error {
  46. return tracerr.Wrap(db.BulkInsert(
  47. d,
  48. `INSERT INTO block (
  49. eth_block_num,
  50. timestamp,
  51. hash
  52. ) VALUES %s;`,
  53. blocks[:],
  54. ))
  55. }
  56. // GetBlock retrieve a block from the DB, given a block number
  57. func (hdb *HistoryDB) GetBlock(blockNum int64) (*common.Block, error) {
  58. block := &common.Block{}
  59. err := meddler.QueryRow(
  60. hdb.db, block,
  61. "SELECT * FROM block WHERE eth_block_num = $1;", blockNum,
  62. )
  63. return block, tracerr.Wrap(err)
  64. }
  65. // GetAllBlocks retrieve all blocks from the DB
  66. func (hdb *HistoryDB) GetAllBlocks() ([]common.Block, error) {
  67. var blocks []*common.Block
  68. err := meddler.QueryAll(
  69. hdb.db, &blocks,
  70. "SELECT * FROM block ORDER BY eth_block_num;",
  71. )
  72. return db.SlicePtrsToSlice(blocks).([]common.Block), tracerr.Wrap(err)
  73. }
  74. // getBlocks retrieve blocks from the DB, given a range of block numbers defined by from and to
  75. func (hdb *HistoryDB) getBlocks(from, to int64) ([]common.Block, error) {
  76. var blocks []*common.Block
  77. err := meddler.QueryAll(
  78. hdb.db, &blocks,
  79. "SELECT * FROM block WHERE $1 <= eth_block_num AND eth_block_num < $2 ORDER BY eth_block_num;",
  80. from, to,
  81. )
  82. return db.SlicePtrsToSlice(blocks).([]common.Block), tracerr.Wrap(err)
  83. }
  84. // GetLastBlock retrieve the block with the highest block number from the DB
  85. func (hdb *HistoryDB) GetLastBlock() (*common.Block, error) {
  86. block := &common.Block{}
  87. err := meddler.QueryRow(
  88. hdb.db, block, "SELECT * FROM block ORDER BY eth_block_num DESC LIMIT 1;",
  89. )
  90. return block, tracerr.Wrap(err)
  91. }
  92. // AddBatch insert a Batch into the DB
  93. func (hdb *HistoryDB) AddBatch(batch *common.Batch) error { return hdb.addBatch(hdb.db, batch) }
  94. func (hdb *HistoryDB) addBatch(d meddler.DB, batch *common.Batch) error {
  95. // Calculate total collected fees in USD
  96. // Get IDs of collected tokens for fees
  97. tokenIDs := []common.TokenID{}
  98. for id := range batch.CollectedFees {
  99. tokenIDs = append(tokenIDs, id)
  100. }
  101. // Get USD value of the tokens
  102. type tokenPrice struct {
  103. ID common.TokenID `meddler:"token_id"`
  104. USD *float64 `meddler:"usd"`
  105. Decimals int `meddler:"decimals"`
  106. }
  107. var tokenPrices []*tokenPrice
  108. if len(tokenIDs) > 0 {
  109. query, args, err := sqlx.In(
  110. "SELECT token_id, usd, decimals FROM token WHERE token_id IN (?);",
  111. tokenIDs,
  112. )
  113. if err != nil {
  114. return tracerr.Wrap(err)
  115. }
  116. query = hdb.db.Rebind(query)
  117. if err := meddler.QueryAll(
  118. hdb.db, &tokenPrices, query, args...,
  119. ); err != nil {
  120. return tracerr.Wrap(err)
  121. }
  122. }
  123. // Calculate total collected
  124. var total float64
  125. for _, tokenPrice := range tokenPrices {
  126. if tokenPrice.USD == nil {
  127. continue
  128. }
  129. f := new(big.Float).SetInt(batch.CollectedFees[tokenPrice.ID])
  130. amount, _ := f.Float64()
  131. total += *tokenPrice.USD * (amount / math.Pow(10, float64(tokenPrice.Decimals))) //nolint decimals have to be ^10
  132. }
  133. batch.TotalFeesUSD = &total
  134. // Insert to DB
  135. return tracerr.Wrap(meddler.Insert(d, "batch", batch))
  136. }
  137. // AddBatches insert Bids into the DB
  138. func (hdb *HistoryDB) AddBatches(batches []common.Batch) error {
  139. return tracerr.Wrap(hdb.addBatches(hdb.db, batches))
  140. }
  141. func (hdb *HistoryDB) addBatches(d meddler.DB, batches []common.Batch) error {
  142. for i := 0; i < len(batches); i++ {
  143. if err := hdb.addBatch(d, &batches[i]); err != nil {
  144. return tracerr.Wrap(err)
  145. }
  146. }
  147. return nil
  148. }
  149. // GetBatch returns the batch with the given batchNum
  150. func (hdb *HistoryDB) GetBatch(batchNum common.BatchNum) (*common.Batch, error) {
  151. var batch common.Batch
  152. err := meddler.QueryRow(
  153. hdb.db, &batch, `SELECT batch.batch_num, batch.eth_block_num, batch.forger_addr,
  154. batch.fees_collected, batch.fee_idxs_coordinator, batch.state_root,
  155. batch.num_accounts, batch.last_idx, batch.exit_root, batch.forge_l1_txs_num,
  156. batch.slot_num, batch.total_fees_usd FROM batch WHERE batch_num = $1;`,
  157. batchNum,
  158. )
  159. return &batch, err
  160. }
  161. // GetAllBatches retrieve all batches from the DB
  162. func (hdb *HistoryDB) GetAllBatches() ([]common.Batch, error) {
  163. var batches []*common.Batch
  164. err := meddler.QueryAll(
  165. hdb.db, &batches,
  166. `SELECT batch.batch_num, batch.eth_block_num, batch.forger_addr, batch.fees_collected,
  167. batch.fee_idxs_coordinator, batch.state_root, batch.num_accounts, batch.last_idx, batch.exit_root,
  168. batch.forge_l1_txs_num, batch.slot_num, batch.total_fees_usd FROM batch
  169. ORDER BY item_id;`,
  170. )
  171. return db.SlicePtrsToSlice(batches).([]common.Batch), tracerr.Wrap(err)
  172. }
  173. // GetBatches retrieve batches from the DB, given a range of batch numbers defined by from and to
  174. func (hdb *HistoryDB) GetBatches(from, to common.BatchNum) ([]common.Batch, error) {
  175. var batches []*common.Batch
  176. err := meddler.QueryAll(
  177. hdb.db, &batches,
  178. `SELECT batch_num, eth_block_num, forger_addr, fees_collected, fee_idxs_coordinator,
  179. state_root, num_accounts, last_idx, exit_root, forge_l1_txs_num, slot_num, total_fees_usd
  180. FROM batch WHERE $1 <= batch_num AND batch_num < $2 ORDER BY batch_num;`,
  181. from, to,
  182. )
  183. return db.SlicePtrsToSlice(batches).([]common.Batch), tracerr.Wrap(err)
  184. }
  185. // GetFirstBatchBlockNumBySlot returns the ethereum block number of the first
  186. // batch within a slot
  187. func (hdb *HistoryDB) GetFirstBatchBlockNumBySlot(slotNum int64) (int64, error) {
  188. row := hdb.db.QueryRow(
  189. `SELECT eth_block_num FROM batch
  190. WHERE slot_num = $1 ORDER BY batch_num ASC LIMIT 1;`, slotNum,
  191. )
  192. var blockNum int64
  193. return blockNum, tracerr.Wrap(row.Scan(&blockNum))
  194. }
  195. // GetLastBatchNum returns the BatchNum of the latest forged batch
  196. func (hdb *HistoryDB) GetLastBatchNum() (common.BatchNum, error) {
  197. row := hdb.db.QueryRow("SELECT batch_num FROM batch ORDER BY batch_num DESC LIMIT 1;")
  198. var batchNum common.BatchNum
  199. return batchNum, tracerr.Wrap(row.Scan(&batchNum))
  200. }
  201. // GetLastBatch returns the last forged batch
  202. func (hdb *HistoryDB) GetLastBatch() (*common.Batch, error) {
  203. var batch common.Batch
  204. err := meddler.QueryRow(
  205. hdb.db, &batch, `SELECT batch.batch_num, batch.eth_block_num, batch.forger_addr,
  206. batch.fees_collected, batch.fee_idxs_coordinator, batch.state_root,
  207. batch.num_accounts, batch.last_idx, batch.exit_root, batch.forge_l1_txs_num,
  208. batch.slot_num, batch.total_fees_usd FROM batch ORDER BY batch_num DESC LIMIT 1;`,
  209. )
  210. return &batch, err
  211. }
  212. // GetLastL1BatchBlockNum returns the blockNum of the latest forged l1Batch
  213. func (hdb *HistoryDB) GetLastL1BatchBlockNum() (int64, error) {
  214. row := hdb.db.QueryRow(`SELECT eth_block_num FROM batch
  215. WHERE forge_l1_txs_num IS NOT NULL
  216. ORDER BY batch_num DESC LIMIT 1;`)
  217. var blockNum int64
  218. return blockNum, tracerr.Wrap(row.Scan(&blockNum))
  219. }
  220. // GetLastL1TxsNum returns the greatest ForgeL1TxsNum in the DB from forged
  221. // batches. If there's no batch in the DB (nil, nil) is returned.
  222. func (hdb *HistoryDB) GetLastL1TxsNum() (*int64, error) {
  223. row := hdb.db.QueryRow("SELECT MAX(forge_l1_txs_num) FROM batch;")
  224. lastL1TxsNum := new(int64)
  225. return lastL1TxsNum, tracerr.Wrap(row.Scan(&lastL1TxsNum))
  226. }
  227. // Reorg deletes all the information that was added into the DB after the
  228. // lastValidBlock. If lastValidBlock is negative, all block information is
  229. // deleted.
  230. func (hdb *HistoryDB) Reorg(lastValidBlock int64) error {
  231. var err error
  232. if lastValidBlock < 0 {
  233. _, err = hdb.db.Exec("DELETE FROM block;")
  234. } else {
  235. _, err = hdb.db.Exec("DELETE FROM block WHERE eth_block_num > $1;", lastValidBlock)
  236. }
  237. return tracerr.Wrap(err)
  238. }
  239. // AddBids insert Bids into the DB
  240. func (hdb *HistoryDB) AddBids(bids []common.Bid) error { return hdb.addBids(hdb.db, bids) }
  241. func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error {
  242. if len(bids) == 0 {
  243. return nil
  244. }
  245. // TODO: check the coordinator info
  246. return tracerr.Wrap(db.BulkInsert(
  247. d,
  248. "INSERT INTO bid (slot_num, bid_value, eth_block_num, bidder_addr) VALUES %s;",
  249. bids[:],
  250. ))
  251. }
  252. // GetAllBids retrieve all bids from the DB
  253. func (hdb *HistoryDB) GetAllBids() ([]common.Bid, error) {
  254. var bids []*common.Bid
  255. err := meddler.QueryAll(
  256. hdb.db, &bids,
  257. `SELECT bid.slot_num, bid.bid_value, bid.eth_block_num, bid.bidder_addr FROM bid
  258. ORDER BY item_id;`,
  259. )
  260. return db.SlicePtrsToSlice(bids).([]common.Bid), tracerr.Wrap(err)
  261. }
  262. // GetBestBidCoordinator returns the forger address of the highest bidder in a slot by slotNum
  263. func (hdb *HistoryDB) GetBestBidCoordinator(slotNum int64) (*common.BidCoordinator, error) {
  264. bidCoord := &common.BidCoordinator{}
  265. err := meddler.QueryRow(
  266. hdb.db, bidCoord,
  267. `SELECT (
  268. SELECT default_slot_set_bid
  269. FROM auction_vars
  270. WHERE default_slot_set_bid_slot_num <= $1
  271. ORDER BY eth_block_num DESC LIMIT 1
  272. ),
  273. bid.slot_num, bid.bid_value, bid.bidder_addr,
  274. coordinator.forger_addr, coordinator.url
  275. FROM bid
  276. INNER JOIN (
  277. SELECT bidder_addr, MAX(item_id) AS item_id FROM coordinator
  278. GROUP BY bidder_addr
  279. ) c ON bid.bidder_addr = c.bidder_addr
  280. INNER JOIN coordinator ON c.item_id = coordinator.item_id
  281. WHERE bid.slot_num = $1 ORDER BY bid.item_id DESC LIMIT 1;`,
  282. slotNum)
  283. return bidCoord, tracerr.Wrap(err)
  284. }
  285. // AddCoordinators insert Coordinators into the DB
  286. func (hdb *HistoryDB) AddCoordinators(coordinators []common.Coordinator) error {
  287. return tracerr.Wrap(hdb.addCoordinators(hdb.db, coordinators))
  288. }
  289. func (hdb *HistoryDB) addCoordinators(d meddler.DB, coordinators []common.Coordinator) error {
  290. if len(coordinators) == 0 {
  291. return nil
  292. }
  293. return tracerr.Wrap(db.BulkInsert(
  294. d,
  295. "INSERT INTO coordinator (bidder_addr, forger_addr, eth_block_num, url) VALUES %s;",
  296. coordinators[:],
  297. ))
  298. }
  299. // AddExitTree insert Exit tree into the DB
  300. func (hdb *HistoryDB) AddExitTree(exitTree []common.ExitInfo) error {
  301. return tracerr.Wrap(hdb.addExitTree(hdb.db, exitTree))
  302. }
  303. func (hdb *HistoryDB) addExitTree(d meddler.DB, exitTree []common.ExitInfo) error {
  304. if len(exitTree) == 0 {
  305. return nil
  306. }
  307. return tracerr.Wrap(db.BulkInsert(
  308. d,
  309. "INSERT INTO exit_tree (batch_num, account_idx, merkle_proof, balance, "+
  310. "instant_withdrawn, delayed_withdraw_request, delayed_withdrawn) VALUES %s;",
  311. exitTree[:],
  312. ))
  313. }
  314. func (hdb *HistoryDB) updateExitTree(d sqlx.Ext, blockNum int64,
  315. rollupWithdrawals []common.WithdrawInfo, wDelayerWithdrawals []common.WDelayerTransfer) error {
  316. if len(rollupWithdrawals) == 0 && len(wDelayerWithdrawals) == 0 {
  317. return nil
  318. }
  319. type withdrawal struct {
  320. BatchNum int64 `db:"batch_num"`
  321. AccountIdx int64 `db:"account_idx"`
  322. InstantWithdrawn *int64 `db:"instant_withdrawn"`
  323. DelayedWithdrawRequest *int64 `db:"delayed_withdraw_request"`
  324. DelayedWithdrawn *int64 `db:"delayed_withdrawn"`
  325. Owner *ethCommon.Address `db:"owner"`
  326. Token *ethCommon.Address `db:"token"`
  327. }
  328. withdrawals := make([]withdrawal, len(rollupWithdrawals)+len(wDelayerWithdrawals))
  329. for i := range rollupWithdrawals {
  330. info := &rollupWithdrawals[i]
  331. withdrawals[i] = withdrawal{
  332. BatchNum: int64(info.NumExitRoot),
  333. AccountIdx: int64(info.Idx),
  334. }
  335. if info.InstantWithdraw {
  336. withdrawals[i].InstantWithdrawn = &blockNum
  337. } else {
  338. withdrawals[i].DelayedWithdrawRequest = &blockNum
  339. withdrawals[i].Owner = &info.Owner
  340. withdrawals[i].Token = &info.Token
  341. }
  342. }
  343. for i := range wDelayerWithdrawals {
  344. info := &wDelayerWithdrawals[i]
  345. withdrawals[len(rollupWithdrawals)+i] = withdrawal{
  346. DelayedWithdrawn: &blockNum,
  347. Owner: &info.Owner,
  348. Token: &info.Token,
  349. }
  350. }
  351. // In VALUES we set an initial row of NULLs to set the types of each
  352. // variable passed as argument
  353. const query string = `
  354. UPDATE exit_tree e SET
  355. instant_withdrawn = d.instant_withdrawn,
  356. delayed_withdraw_request = CASE
  357. WHEN e.delayed_withdraw_request IS NOT NULL THEN e.delayed_withdraw_request
  358. ELSE d.delayed_withdraw_request
  359. END,
  360. delayed_withdrawn = d.delayed_withdrawn,
  361. owner = d.owner,
  362. token = d.token
  363. FROM (VALUES
  364. (NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BIGINT, NULL::::BYTEA, NULL::::BYTEA),
  365. (:batch_num,
  366. :account_idx,
  367. :instant_withdrawn,
  368. :delayed_withdraw_request,
  369. :delayed_withdrawn,
  370. :owner,
  371. :token)
  372. ) as d (batch_num, account_idx, instant_withdrawn, delayed_withdraw_request, delayed_withdrawn, owner, token)
  373. WHERE
  374. (d.batch_num IS NOT NULL AND e.batch_num = d.batch_num AND e.account_idx = d.account_idx) OR
  375. (d.delayed_withdrawn IS NOT NULL AND e.delayed_withdrawn IS NULL AND e.owner = d.owner AND e.token = d.token);
  376. `
  377. if len(withdrawals) > 0 {
  378. if _, err := sqlx.NamedExec(d, query, withdrawals); err != nil {
  379. return tracerr.Wrap(err)
  380. }
  381. }
  382. return nil
  383. }
  384. // AddToken insert a token into the DB
  385. func (hdb *HistoryDB) AddToken(token *common.Token) error {
  386. return tracerr.Wrap(meddler.Insert(hdb.db, "token", token))
  387. }
  388. // AddTokens insert tokens into the DB
  389. func (hdb *HistoryDB) AddTokens(tokens []common.Token) error { return hdb.addTokens(hdb.db, tokens) }
  390. func (hdb *HistoryDB) addTokens(d meddler.DB, tokens []common.Token) error {
  391. if len(tokens) == 0 {
  392. return nil
  393. }
  394. // Sanitize name and symbol
  395. for i, token := range tokens {
  396. token.Name = strings.ToValidUTF8(token.Name, " ")
  397. token.Symbol = strings.ToValidUTF8(token.Symbol, " ")
  398. tokens[i] = token
  399. }
  400. return tracerr.Wrap(db.BulkInsert(
  401. d,
  402. `INSERT INTO token (
  403. token_id,
  404. eth_block_num,
  405. eth_addr,
  406. name,
  407. symbol,
  408. decimals
  409. ) VALUES %s;`,
  410. tokens[:],
  411. ))
  412. }
  413. // UpdateTokenValue updates the USD value of a token
  414. func (hdb *HistoryDB) UpdateTokenValue(tokenSymbol string, value float64) error {
  415. // Sanitize symbol
  416. tokenSymbol = strings.ToValidUTF8(tokenSymbol, " ")
  417. _, err := hdb.db.Exec(
  418. "UPDATE token SET usd = $1 WHERE symbol = $2;",
  419. value, tokenSymbol,
  420. )
  421. return tracerr.Wrap(err)
  422. }
  423. // GetToken returns a token from the DB given a TokenID
  424. func (hdb *HistoryDB) GetToken(tokenID common.TokenID) (*TokenWithUSD, error) {
  425. token := &TokenWithUSD{}
  426. err := meddler.QueryRow(
  427. hdb.db, token, `SELECT * FROM token WHERE token_id = $1;`, tokenID,
  428. )
  429. return token, tracerr.Wrap(err)
  430. }
  431. // GetAllTokens returns all tokens from the DB
  432. func (hdb *HistoryDB) GetAllTokens() ([]TokenWithUSD, error) {
  433. var tokens []*TokenWithUSD
  434. err := meddler.QueryAll(
  435. hdb.db, &tokens,
  436. "SELECT * FROM token ORDER BY token_id;",
  437. )
  438. return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), tracerr.Wrap(err)
  439. }
  440. // GetTokenSymbols returns all the token symbols from the DB
  441. func (hdb *HistoryDB) GetTokenSymbols() ([]string, error) {
  442. var tokenSymbols []string
  443. rows, err := hdb.db.Query("SELECT symbol FROM token;")
  444. if err != nil {
  445. return nil, tracerr.Wrap(err)
  446. }
  447. defer db.RowsClose(rows)
  448. sym := new(string)
  449. for rows.Next() {
  450. err = rows.Scan(sym)
  451. if err != nil {
  452. return nil, tracerr.Wrap(err)
  453. }
  454. tokenSymbols = append(tokenSymbols, *sym)
  455. }
  456. return tokenSymbols, nil
  457. }
  458. // AddAccounts insert accounts into the DB
  459. func (hdb *HistoryDB) AddAccounts(accounts []common.Account) error {
  460. return tracerr.Wrap(hdb.addAccounts(hdb.db, accounts))
  461. }
  462. func (hdb *HistoryDB) addAccounts(d meddler.DB, accounts []common.Account) error {
  463. if len(accounts) == 0 {
  464. return nil
  465. }
  466. return tracerr.Wrap(db.BulkInsert(
  467. d,
  468. `INSERT INTO account (
  469. idx,
  470. token_id,
  471. batch_num,
  472. bjj,
  473. eth_addr
  474. ) VALUES %s;`,
  475. accounts[:],
  476. ))
  477. }
  478. // GetAllAccounts returns a list of accounts from the DB
  479. func (hdb *HistoryDB) GetAllAccounts() ([]common.Account, error) {
  480. var accs []*common.Account
  481. err := meddler.QueryAll(
  482. hdb.db, &accs,
  483. "SELECT idx, token_id, batch_num, bjj, eth_addr FROM account ORDER BY idx;",
  484. )
  485. return db.SlicePtrsToSlice(accs).([]common.Account), tracerr.Wrap(err)
  486. }
  487. // AddL1Txs inserts L1 txs to the DB. USD and DepositAmountUSD will be set automatically before storing the tx.
  488. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  489. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  490. // EffectiveAmount and EffectiveDepositAmount are seted with default values by the DB.
  491. func (hdb *HistoryDB) AddL1Txs(l1txs []common.L1Tx) error {
  492. return tracerr.Wrap(hdb.addL1Txs(hdb.db, l1txs))
  493. }
  494. // addL1Txs inserts L1 txs to the DB. USD and DepositAmountUSD will be set automatically before storing the tx.
  495. // If the tx is originated by a coordinator, BatchNum must be provided. If it's originated by a user,
  496. // BatchNum should be null, and the value will be setted by a trigger when a batch forges the tx.
  497. // EffectiveAmount and EffectiveDepositAmount are seted with default values by the DB.
  498. func (hdb *HistoryDB) addL1Txs(d meddler.DB, l1txs []common.L1Tx) error {
  499. if len(l1txs) == 0 {
  500. return nil
  501. }
  502. txs := []txWrite{}
  503. for i := 0; i < len(l1txs); i++ {
  504. af := new(big.Float).SetInt(l1txs[i].Amount)
  505. amountFloat, _ := af.Float64()
  506. laf := new(big.Float).SetInt(l1txs[i].DepositAmount)
  507. depositAmountFloat, _ := laf.Float64()
  508. var effectiveFromIdx *common.Idx
  509. if l1txs[i].UserOrigin {
  510. if l1txs[i].Type != common.TxTypeCreateAccountDeposit &&
  511. l1txs[i].Type != common.TxTypeCreateAccountDepositTransfer {
  512. effectiveFromIdx = &l1txs[i].FromIdx
  513. }
  514. } else {
  515. effectiveFromIdx = &l1txs[i].EffectiveFromIdx
  516. }
  517. txs = append(txs, txWrite{
  518. // Generic
  519. IsL1: true,
  520. TxID: l1txs[i].TxID,
  521. Type: l1txs[i].Type,
  522. Position: l1txs[i].Position,
  523. FromIdx: &l1txs[i].FromIdx,
  524. EffectiveFromIdx: effectiveFromIdx,
  525. ToIdx: l1txs[i].ToIdx,
  526. Amount: l1txs[i].Amount,
  527. AmountFloat: amountFloat,
  528. TokenID: l1txs[i].TokenID,
  529. BatchNum: l1txs[i].BatchNum,
  530. EthBlockNum: l1txs[i].EthBlockNum,
  531. // L1
  532. ToForgeL1TxsNum: l1txs[i].ToForgeL1TxsNum,
  533. UserOrigin: &l1txs[i].UserOrigin,
  534. FromEthAddr: &l1txs[i].FromEthAddr,
  535. FromBJJ: &l1txs[i].FromBJJ,
  536. DepositAmount: l1txs[i].DepositAmount,
  537. DepositAmountFloat: &depositAmountFloat,
  538. })
  539. }
  540. return tracerr.Wrap(hdb.addTxs(d, txs))
  541. }
  542. // AddL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
  543. func (hdb *HistoryDB) AddL2Txs(l2txs []common.L2Tx) error {
  544. return tracerr.Wrap(hdb.addL2Txs(hdb.db, l2txs))
  545. }
  546. // addL2Txs inserts L2 txs to the DB. TokenID, USD and FeeUSD will be set automatically before storing the tx.
  547. func (hdb *HistoryDB) addL2Txs(d meddler.DB, l2txs []common.L2Tx) error {
  548. txs := []txWrite{}
  549. for i := 0; i < len(l2txs); i++ {
  550. f := new(big.Float).SetInt(l2txs[i].Amount)
  551. amountFloat, _ := f.Float64()
  552. txs = append(txs, txWrite{
  553. // Generic
  554. IsL1: false,
  555. TxID: l2txs[i].TxID,
  556. Type: l2txs[i].Type,
  557. Position: l2txs[i].Position,
  558. FromIdx: &l2txs[i].FromIdx,
  559. EffectiveFromIdx: &l2txs[i].FromIdx,
  560. ToIdx: l2txs[i].ToIdx,
  561. TokenID: l2txs[i].TokenID,
  562. Amount: l2txs[i].Amount,
  563. AmountFloat: amountFloat,
  564. BatchNum: &l2txs[i].BatchNum,
  565. EthBlockNum: l2txs[i].EthBlockNum,
  566. // L2
  567. Fee: &l2txs[i].Fee,
  568. Nonce: &l2txs[i].Nonce,
  569. })
  570. }
  571. return tracerr.Wrap(hdb.addTxs(d, txs))
  572. }
  573. func (hdb *HistoryDB) addTxs(d meddler.DB, txs []txWrite) error {
  574. if len(txs) == 0 {
  575. return nil
  576. }
  577. return tracerr.Wrap(db.BulkInsert(
  578. d,
  579. `INSERT INTO tx (
  580. is_l1,
  581. id,
  582. type,
  583. position,
  584. from_idx,
  585. effective_from_idx,
  586. to_idx,
  587. amount,
  588. amount_f,
  589. token_id,
  590. batch_num,
  591. eth_block_num,
  592. to_forge_l1_txs_num,
  593. user_origin,
  594. from_eth_addr,
  595. from_bjj,
  596. deposit_amount,
  597. deposit_amount_f,
  598. fee,
  599. nonce
  600. ) VALUES %s;`,
  601. txs[:],
  602. ))
  603. }
  604. // GetAllExits returns all exit from the DB
  605. func (hdb *HistoryDB) GetAllExits() ([]common.ExitInfo, error) {
  606. var exits []*common.ExitInfo
  607. err := meddler.QueryAll(
  608. hdb.db, &exits,
  609. `SELECT exit_tree.batch_num, exit_tree.account_idx, exit_tree.merkle_proof,
  610. exit_tree.balance, exit_tree.instant_withdrawn, exit_tree.delayed_withdraw_request,
  611. exit_tree.delayed_withdrawn FROM exit_tree ORDER BY item_id;`,
  612. )
  613. return db.SlicePtrsToSlice(exits).([]common.ExitInfo), tracerr.Wrap(err)
  614. }
  615. // GetAllL1UserTxs returns all L1UserTxs from the DB
  616. func (hdb *HistoryDB) GetAllL1UserTxs() ([]common.L1Tx, error) {
  617. var txs []*common.L1Tx
  618. err := meddler.QueryAll(
  619. hdb.db, &txs, // Note that '\x' gets parsed as a big.Int with value = 0
  620. `SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
  621. tx.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
  622. tx.amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.amount_success THEN tx.amount ELSE '\x' END) AS effective_amount,
  623. tx.deposit_amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.deposit_amount_success THEN tx.deposit_amount ELSE '\x' END) AS effective_deposit_amount,
  624. tx.eth_block_num, tx.type, tx.batch_num
  625. FROM tx WHERE is_l1 = TRUE AND user_origin = TRUE ORDER BY item_id;`,
  626. )
  627. return db.SlicePtrsToSlice(txs).([]common.L1Tx), tracerr.Wrap(err)
  628. }
  629. // GetAllL1CoordinatorTxs returns all L1CoordinatorTxs from the DB
  630. func (hdb *HistoryDB) GetAllL1CoordinatorTxs() ([]common.L1Tx, error) {
  631. var txs []*common.L1Tx
  632. // Since the query specifies that only coordinator txs are returned, it's safe to assume
  633. // that returned txs will always have effective amounts
  634. err := meddler.QueryAll(
  635. hdb.db, &txs,
  636. `SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
  637. tx.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
  638. tx.amount, tx.amount AS effective_amount,
  639. tx.deposit_amount, tx.deposit_amount AS effective_deposit_amount,
  640. tx.eth_block_num, tx.type, tx.batch_num
  641. FROM tx WHERE is_l1 = TRUE AND user_origin = FALSE ORDER BY item_id;`,
  642. )
  643. return db.SlicePtrsToSlice(txs).([]common.L1Tx), tracerr.Wrap(err)
  644. }
  645. // GetAllL2Txs returns all L2Txs from the DB
  646. func (hdb *HistoryDB) GetAllL2Txs() ([]common.L2Tx, error) {
  647. var txs []*common.L2Tx
  648. err := meddler.QueryAll(
  649. hdb.db, &txs,
  650. `SELECT tx.id, tx.batch_num, tx.position,
  651. tx.from_idx, tx.to_idx, tx.amount, tx.token_id,
  652. tx.fee, tx.nonce, tx.type, tx.eth_block_num
  653. FROM tx WHERE is_l1 = FALSE ORDER BY item_id;`,
  654. )
  655. return db.SlicePtrsToSlice(txs).([]common.L2Tx), tracerr.Wrap(err)
  656. }
  657. // GetUnforgedL1UserTxs gets L1 User Txs to be forged in the L1Batch with toForgeL1TxsNum.
  658. func (hdb *HistoryDB) GetUnforgedL1UserTxs(toForgeL1TxsNum int64) ([]common.L1Tx, error) {
  659. var txs []*common.L1Tx
  660. err := meddler.QueryAll(
  661. hdb.db, &txs, // only L1 user txs can have batch_num set to null
  662. `SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
  663. tx.from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
  664. tx.amount, NULL AS effective_amount,
  665. tx.deposit_amount, NULL AS effective_deposit_amount,
  666. tx.eth_block_num, tx.type, tx.batch_num
  667. FROM tx WHERE batch_num IS NULL AND to_forge_l1_txs_num = $1
  668. ORDER BY position;`,
  669. toForgeL1TxsNum,
  670. )
  671. return db.SlicePtrsToSlice(txs).([]common.L1Tx), tracerr.Wrap(err)
  672. }
  673. // TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value.
  674. // GetLastTxsPosition for a given to_forge_l1_txs_num
  675. func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) {
  676. row := hdb.db.QueryRow(
  677. "SELECT position FROM tx WHERE to_forge_l1_txs_num = $1 ORDER BY position DESC;",
  678. toForgeL1TxsNum,
  679. )
  680. var lastL1TxsPosition int
  681. return lastL1TxsPosition, tracerr.Wrap(row.Scan(&lastL1TxsPosition))
  682. }
  683. // GetSCVars returns the rollup, auction and wdelayer smart contracts variables at their last update.
  684. func (hdb *HistoryDB) GetSCVars() (*common.RollupVariables, *common.AuctionVariables,
  685. *common.WDelayerVariables, error) {
  686. var rollup common.RollupVariables
  687. var auction common.AuctionVariables
  688. var wDelayer common.WDelayerVariables
  689. if err := meddler.QueryRow(hdb.db, &rollup,
  690. "SELECT * FROM rollup_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil {
  691. return nil, nil, nil, tracerr.Wrap(err)
  692. }
  693. if err := meddler.QueryRow(hdb.db, &auction,
  694. "SELECT * FROM auction_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil {
  695. return nil, nil, nil, tracerr.Wrap(err)
  696. }
  697. if err := meddler.QueryRow(hdb.db, &wDelayer,
  698. "SELECT * FROM wdelayer_vars ORDER BY eth_block_num DESC LIMIT 1;"); err != nil {
  699. return nil, nil, nil, tracerr.Wrap(err)
  700. }
  701. return &rollup, &auction, &wDelayer, nil
  702. }
  703. func (hdb *HistoryDB) setRollupVars(d meddler.DB, rollup *common.RollupVariables) error {
  704. return tracerr.Wrap(meddler.Insert(d, "rollup_vars", rollup))
  705. }
  706. func (hdb *HistoryDB) setAuctionVars(d meddler.DB, auction *common.AuctionVariables) error {
  707. return tracerr.Wrap(meddler.Insert(d, "auction_vars", auction))
  708. }
  709. func (hdb *HistoryDB) setWDelayerVars(d meddler.DB, wDelayer *common.WDelayerVariables) error {
  710. return tracerr.Wrap(meddler.Insert(d, "wdelayer_vars", wDelayer))
  711. }
  712. func (hdb *HistoryDB) addBucketUpdates(d meddler.DB, bucketUpdates []common.BucketUpdate) error {
  713. if len(bucketUpdates) == 0 {
  714. return nil
  715. }
  716. return tracerr.Wrap(db.BulkInsert(
  717. d,
  718. `INSERT INTO bucket_update (
  719. eth_block_num,
  720. num_bucket,
  721. block_stamp,
  722. withdrawals
  723. ) VALUES %s;`,
  724. bucketUpdates[:],
  725. ))
  726. }
  727. // AddBucketUpdatesTest allows call to unexported method
  728. // only for internal testing purposes
  729. func (hdb *HistoryDB) AddBucketUpdatesTest(d meddler.DB, bucketUpdates []common.BucketUpdate) error {
  730. return hdb.addBucketUpdates(d, bucketUpdates)
  731. }
  732. // GetAllBucketUpdates retrieves all the bucket updates
  733. func (hdb *HistoryDB) GetAllBucketUpdates() ([]common.BucketUpdate, error) {
  734. var bucketUpdates []*common.BucketUpdate
  735. err := meddler.QueryAll(
  736. hdb.db, &bucketUpdates,
  737. `SELECT eth_block_num, num_bucket, block_stamp, withdrawals
  738. FROM bucket_update ORDER BY item_id;`,
  739. )
  740. return db.SlicePtrsToSlice(bucketUpdates).([]common.BucketUpdate), tracerr.Wrap(err)
  741. }
  742. func (hdb *HistoryDB) addTokenExchanges(d meddler.DB, tokenExchanges []common.TokenExchange) error {
  743. if len(tokenExchanges) == 0 {
  744. return nil
  745. }
  746. return tracerr.Wrap(db.BulkInsert(
  747. d,
  748. `INSERT INTO token_exchange (
  749. eth_block_num,
  750. eth_addr,
  751. value_usd
  752. ) VALUES %s;`,
  753. tokenExchanges[:],
  754. ))
  755. }
  756. // GetAllTokenExchanges retrieves all the token exchanges
  757. func (hdb *HistoryDB) GetAllTokenExchanges() ([]common.TokenExchange, error) {
  758. var tokenExchanges []*common.TokenExchange
  759. err := meddler.QueryAll(
  760. hdb.db, &tokenExchanges,
  761. "SELECT eth_block_num, eth_addr, value_usd FROM token_exchange ORDER BY item_id;",
  762. )
  763. return db.SlicePtrsToSlice(tokenExchanges).([]common.TokenExchange), tracerr.Wrap(err)
  764. }
  765. func (hdb *HistoryDB) addEscapeHatchWithdrawals(d meddler.DB,
  766. escapeHatchWithdrawals []common.WDelayerEscapeHatchWithdrawal) error {
  767. if len(escapeHatchWithdrawals) == 0 {
  768. return nil
  769. }
  770. return tracerr.Wrap(db.BulkInsert(
  771. d,
  772. `INSERT INTO escape_hatch_withdrawal (
  773. eth_block_num,
  774. who_addr,
  775. to_addr,
  776. token_addr,
  777. amount
  778. ) VALUES %s;`,
  779. escapeHatchWithdrawals[:],
  780. ))
  781. }
  782. // GetAllEscapeHatchWithdrawals retrieves all the escape hatch withdrawals
  783. func (hdb *HistoryDB) GetAllEscapeHatchWithdrawals() ([]common.WDelayerEscapeHatchWithdrawal, error) {
  784. var escapeHatchWithdrawals []*common.WDelayerEscapeHatchWithdrawal
  785. err := meddler.QueryAll(
  786. hdb.db, &escapeHatchWithdrawals,
  787. "SELECT eth_block_num, who_addr, to_addr, token_addr, amount FROM escape_hatch_withdrawal ORDER BY item_id;",
  788. )
  789. return db.SlicePtrsToSlice(escapeHatchWithdrawals).([]common.WDelayerEscapeHatchWithdrawal),
  790. tracerr.Wrap(err)
  791. }
  792. // SetInitialSCVars sets the initial state of rollup, auction, wdelayer smart
  793. // contract variables. This initial state is stored linked to block 0, which
  794. // always exist in the DB and is used to store initialization data that always
  795. // exist in the smart contracts.
  796. func (hdb *HistoryDB) SetInitialSCVars(rollup *common.RollupVariables,
  797. auction *common.AuctionVariables, wDelayer *common.WDelayerVariables) error {
  798. txn, err := hdb.db.Beginx()
  799. if err != nil {
  800. return tracerr.Wrap(err)
  801. }
  802. defer func() {
  803. if err != nil {
  804. db.Rollback(txn)
  805. }
  806. }()
  807. // Force EthBlockNum to be 0 because it's the block used to link data
  808. // that belongs to the creation of the smart contracts
  809. rollup.EthBlockNum = 0
  810. auction.EthBlockNum = 0
  811. wDelayer.EthBlockNum = 0
  812. auction.DefaultSlotSetBidSlotNum = 0
  813. if err := hdb.setRollupVars(txn, rollup); err != nil {
  814. return tracerr.Wrap(err)
  815. }
  816. if err := hdb.setAuctionVars(txn, auction); err != nil {
  817. return tracerr.Wrap(err)
  818. }
  819. if err := hdb.setWDelayerVars(txn, wDelayer); err != nil {
  820. return tracerr.Wrap(err)
  821. }
  822. return tracerr.Wrap(txn.Commit())
  823. }
  824. // setExtraInfoForgedL1UserTxs sets the EffectiveAmount, EffectiveDepositAmount
  825. // and EffectiveFromIdx of the given l1UserTxs (with an UPDATE)
  826. func (hdb *HistoryDB) setExtraInfoForgedL1UserTxs(d sqlx.Ext, txs []common.L1Tx) error {
  827. if len(txs) == 0 {
  828. return nil
  829. }
  830. // Effective amounts are stored as success flags in the DB, with true value by default
  831. // to reduce the amount of updates. Therefore, only amounts that became uneffective should be
  832. // updated to become false. At the same time, all the txs that contain
  833. // accounts (FromIdx == 0) are updated to set the EffectiveFromIdx.
  834. type txUpdate struct {
  835. ID common.TxID `db:"id"`
  836. AmountSuccess bool `db:"amount_success"`
  837. DepositAmountSuccess bool `db:"deposit_amount_success"`
  838. EffectiveFromIdx common.Idx `db:"effective_from_idx"`
  839. }
  840. txUpdates := []txUpdate{}
  841. equal := func(a *big.Int, b *big.Int) bool {
  842. return a.Cmp(b) == 0
  843. }
  844. for i := range txs {
  845. amountSuccess := equal(txs[i].Amount, txs[i].EffectiveAmount)
  846. depositAmountSuccess := equal(txs[i].DepositAmount, txs[i].EffectiveDepositAmount)
  847. if !amountSuccess || !depositAmountSuccess || txs[i].FromIdx == 0 {
  848. txUpdates = append(txUpdates, txUpdate{
  849. ID: txs[i].TxID,
  850. AmountSuccess: amountSuccess,
  851. DepositAmountSuccess: depositAmountSuccess,
  852. EffectiveFromIdx: txs[i].EffectiveFromIdx,
  853. })
  854. }
  855. }
  856. const query string = `
  857. UPDATE tx SET
  858. amount_success = tx_update.amount_success,
  859. deposit_amount_success = tx_update.deposit_amount_success,
  860. effective_from_idx = tx_update.effective_from_idx
  861. FROM (VALUES
  862. (NULL::::BYTEA, NULL::::BOOL, NULL::::BOOL, NULL::::BIGINT),
  863. (:id, :amount_success, :deposit_amount_success, :effective_from_idx)
  864. ) as tx_update (id, amount_success, deposit_amount_success, effective_from_idx)
  865. WHERE tx.id = tx_update.id;
  866. `
  867. if len(txUpdates) > 0 {
  868. if _, err := sqlx.NamedExec(d, query, txUpdates); err != nil {
  869. return tracerr.Wrap(err)
  870. }
  871. }
  872. return nil
  873. }
  874. // AddBlockSCData stores all the information of a block retrieved by the
  875. // Synchronizer. Blocks should be inserted in order, leaving no gaps because
  876. // the pagination system of the API/DB depends on this. Within blocks, all
  877. // items should also be in the correct order (Accounts, Tokens, Txs, etc.)
  878. func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) {
  879. txn, err := hdb.db.Beginx()
  880. if err != nil {
  881. return tracerr.Wrap(err)
  882. }
  883. defer func() {
  884. if err != nil {
  885. db.Rollback(txn)
  886. }
  887. }()
  888. // Add block
  889. if err := hdb.addBlock(txn, &blockData.Block); err != nil {
  890. return tracerr.Wrap(err)
  891. }
  892. // Add Coordinators
  893. if err := hdb.addCoordinators(txn, blockData.Auction.Coordinators); err != nil {
  894. return tracerr.Wrap(err)
  895. }
  896. // Add Bids
  897. if err := hdb.addBids(txn, blockData.Auction.Bids); err != nil {
  898. return tracerr.Wrap(err)
  899. }
  900. // Add Tokens
  901. if err := hdb.addTokens(txn, blockData.Rollup.AddedTokens); err != nil {
  902. return tracerr.Wrap(err)
  903. }
  904. // Prepare user L1 txs to be added.
  905. // They must be added before the batch that will forge them (which can be in the same block)
  906. // and after the account that will be sent to (also can be in the same block).
  907. // Note: insert order is not relevant since item_id will be updated by a DB trigger when
  908. // the batch that forges those txs is inserted
  909. userL1s := make(map[common.BatchNum][]common.L1Tx)
  910. for i := range blockData.Rollup.L1UserTxs {
  911. batchThatForgesIsInTheBlock := false
  912. for _, batch := range blockData.Rollup.Batches {
  913. if batch.Batch.ForgeL1TxsNum != nil &&
  914. *batch.Batch.ForgeL1TxsNum == *blockData.Rollup.L1UserTxs[i].ToForgeL1TxsNum {
  915. // Tx is forged in this block. It's guaranteed that:
  916. // * the first batch of the block won't forge user L1 txs that have been added in this block
  917. // * batch nums are sequential therefore it's safe to add the tx at batch.BatchNum -1
  918. batchThatForgesIsInTheBlock = true
  919. addAtBatchNum := batch.Batch.BatchNum - 1
  920. userL1s[addAtBatchNum] = append(userL1s[addAtBatchNum], blockData.Rollup.L1UserTxs[i])
  921. break
  922. }
  923. }
  924. if !batchThatForgesIsInTheBlock {
  925. // User artificial batchNum 0 to add txs that are not forge in this block
  926. // after all the accounts of the block have been added
  927. userL1s[0] = append(userL1s[0], blockData.Rollup.L1UserTxs[i])
  928. }
  929. }
  930. // Add Batches
  931. for i := range blockData.Rollup.Batches {
  932. batch := &blockData.Rollup.Batches[i]
  933. // Add Batch: this will trigger an update on the DB
  934. // that will set the batch num of forged L1 txs in this batch
  935. if err = hdb.addBatch(txn, &batch.Batch); err != nil {
  936. return tracerr.Wrap(err)
  937. }
  938. // Add accounts
  939. if err := hdb.addAccounts(txn, batch.CreatedAccounts); err != nil {
  940. return tracerr.Wrap(err)
  941. }
  942. // Set the EffectiveAmount and EffectiveDepositAmount of all the
  943. // L1UserTxs that have been forged in this batch
  944. if err = hdb.setExtraInfoForgedL1UserTxs(txn, batch.L1UserTxs); err != nil {
  945. return tracerr.Wrap(err)
  946. }
  947. // Add forged l1 coordinator Txs
  948. if err := hdb.addL1Txs(txn, batch.L1CoordinatorTxs); err != nil {
  949. return tracerr.Wrap(err)
  950. }
  951. // Add l2 Txs
  952. if err := hdb.addL2Txs(txn, batch.L2Txs); err != nil {
  953. return tracerr.Wrap(err)
  954. }
  955. // Add user L1 txs that will be forged in next batch
  956. if userlL1s, ok := userL1s[batch.Batch.BatchNum]; ok {
  957. if err := hdb.addL1Txs(txn, userlL1s); err != nil {
  958. return tracerr.Wrap(err)
  959. }
  960. }
  961. // Add exit tree
  962. if err := hdb.addExitTree(txn, batch.ExitTree); err != nil {
  963. return tracerr.Wrap(err)
  964. }
  965. }
  966. // Add user L1 txs that won't be forged in this block
  967. if userL1sNotForgedInThisBlock, ok := userL1s[0]; ok {
  968. if err := hdb.addL1Txs(txn, userL1sNotForgedInThisBlock); err != nil {
  969. return tracerr.Wrap(err)
  970. }
  971. }
  972. // Set SC Vars if there was an update
  973. if blockData.Rollup.Vars != nil {
  974. if err := hdb.setRollupVars(txn, blockData.Rollup.Vars); err != nil {
  975. return tracerr.Wrap(err)
  976. }
  977. }
  978. if blockData.Auction.Vars != nil {
  979. if err := hdb.setAuctionVars(txn, blockData.Auction.Vars); err != nil {
  980. return tracerr.Wrap(err)
  981. }
  982. }
  983. if blockData.WDelayer.Vars != nil {
  984. if err := hdb.setWDelayerVars(txn, blockData.WDelayer.Vars); err != nil {
  985. return tracerr.Wrap(err)
  986. }
  987. }
  988. // Update withdrawals in exit tree table
  989. if err := hdb.updateExitTree(txn, blockData.Block.Num,
  990. blockData.Rollup.Withdrawals, blockData.WDelayer.Withdrawals); err != nil {
  991. return tracerr.Wrap(err)
  992. }
  993. // Add Escape Hatch Withdrawals
  994. if err := hdb.addEscapeHatchWithdrawals(txn,
  995. blockData.WDelayer.EscapeHatchWithdrawals); err != nil {
  996. return tracerr.Wrap(err)
  997. }
  998. // Add Buckets withdrawals updates
  999. if err := hdb.addBucketUpdates(txn, blockData.Rollup.UpdateBucketWithdraw); err != nil {
  1000. return tracerr.Wrap(err)
  1001. }
  1002. // Add Token exchange updates
  1003. if err := hdb.addTokenExchanges(txn, blockData.Rollup.TokenExchanges); err != nil {
  1004. return tracerr.Wrap(err)
  1005. }
  1006. return tracerr.Wrap(txn.Commit())
  1007. }
  1008. // GetCoordinatorAPI returns a coordinator by its bidderAddr
  1009. func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) {
  1010. coordinator := &CoordinatorAPI{}
  1011. err := meddler.QueryRow(
  1012. hdb.db, coordinator,
  1013. "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;",
  1014. bidderAddr,
  1015. )
  1016. return coordinator, tracerr.Wrap(err)
  1017. }
  1018. // AddAuctionVars insert auction vars into the DB
  1019. func (hdb *HistoryDB) AddAuctionVars(auctionVars *common.AuctionVariables) error {
  1020. return tracerr.Wrap(meddler.Insert(hdb.db, "auction_vars", auctionVars))
  1021. }
  1022. // GetTokensTest used to get tokens in a testing context
  1023. func (hdb *HistoryDB) GetTokensTest() ([]TokenWithUSD, error) {
  1024. tokens := []*TokenWithUSD{}
  1025. if err := meddler.QueryAll(
  1026. hdb.db, &tokens,
  1027. "SELECT * FROM TOKEN",
  1028. ); err != nil {
  1029. return nil, tracerr.Wrap(err)
  1030. }
  1031. if len(tokens) == 0 {
  1032. return []TokenWithUSD{}, nil
  1033. }
  1034. return db.SlicePtrsToSlice(tokens).([]TokenWithUSD), nil
  1035. }