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.

873 lines
29 KiB

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.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
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 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.
4 years ago
  1. package til
  2. import (
  3. "crypto/ecdsa"
  4. "fmt"
  5. "math/big"
  6. "strconv"
  7. "strings"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. "github.com/hermeznetwork/tracerr"
  14. "github.com/iden3/go-iden3-crypto/babyjub"
  15. )
  16. func newBatchData(batchNum int) common.BatchData {
  17. return common.BatchData{
  18. L1CoordinatorTxs: []common.L1Tx{},
  19. L2Txs: []common.L2Tx{},
  20. Batch: common.Batch{
  21. BatchNum: common.BatchNum(batchNum),
  22. StateRoot: big.NewInt(0), ExitRoot: big.NewInt(0),
  23. FeeIdxsCoordinator: make([]common.Idx, 0),
  24. CollectedFees: make(map[common.TokenID]*big.Int),
  25. },
  26. }
  27. }
  28. func newBlock(blockNum int64) common.BlockData {
  29. return common.BlockData{
  30. Block: common.Block{
  31. Num: blockNum,
  32. },
  33. Rollup: common.RollupData{
  34. L1UserTxs: []common.L1Tx{},
  35. },
  36. }
  37. }
  38. type contextExtra struct {
  39. openToForge int64
  40. toForgeL1TxsNum int64
  41. nonces map[common.Idx]common.Nonce
  42. idx int
  43. }
  44. // Context contains the data of the test
  45. type Context struct {
  46. Instructions []instruction
  47. userNames []string
  48. Users map[string]*User // Name -> *User
  49. UsersByIdx map[int]*User
  50. accountsByIdx map[int]*Account
  51. LastRegisteredTokenID common.TokenID
  52. l1CreatedAccounts map[string]*Account // (Name, TokenID) -> *Account
  53. // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch
  54. rollupConstMaxL1UserTx int
  55. idx int
  56. currBlock common.BlockData
  57. currBatch common.BatchData
  58. currBatchNum int
  59. Queues [][]L1Tx
  60. ToForgeNum int
  61. openToForge int
  62. currBatchTest struct {
  63. l1CoordinatorTxs []L1Tx
  64. l2Txs []L2Tx
  65. }
  66. blockNum int64
  67. extra contextExtra
  68. }
  69. // NewContext returns a new Context
  70. func NewContext(rollupConstMaxL1UserTx int) *Context {
  71. currBatchNum := 1 // The protocol defines the first batchNum to be 1
  72. return &Context{
  73. Users: make(map[string]*User),
  74. l1CreatedAccounts: make(map[string]*Account),
  75. UsersByIdx: make(map[int]*User),
  76. accountsByIdx: make(map[int]*Account),
  77. LastRegisteredTokenID: 0,
  78. rollupConstMaxL1UserTx: rollupConstMaxL1UserTx,
  79. idx: common.UserThreshold,
  80. // We use some placeholder values for StateRoot and ExitTree
  81. // because these values will never be nil
  82. currBlock: newBlock(2), //nolint:gomnd
  83. currBatch: newBatchData(currBatchNum),
  84. currBatchNum: currBatchNum,
  85. // start with 2 queues, one for toForge, and the other for openToForge
  86. Queues: make([][]L1Tx, 2),
  87. ToForgeNum: 0,
  88. openToForge: 1,
  89. //nolint:gomnd
  90. blockNum: 2, // rollup genesis blockNum
  91. extra: contextExtra{
  92. openToForge: 0,
  93. toForgeL1TxsNum: 0,
  94. nonces: make(map[common.Idx]common.Nonce),
  95. idx: common.UserThreshold,
  96. },
  97. }
  98. }
  99. // Account contains the data related to the account for a specific TokenID of a User
  100. type Account struct {
  101. Idx common.Idx
  102. TokenID common.TokenID
  103. Nonce common.Nonce
  104. BatchNum int
  105. }
  106. // User contains the data related to a testing user
  107. type User struct {
  108. Name string
  109. BJJ *babyjub.PrivateKey
  110. Addr ethCommon.Address
  111. Accounts map[common.TokenID]*Account
  112. }
  113. // L1Tx is the data structure used internally for transaction test generation,
  114. // which contains a common.L1Tx data plus some intermediate data for the
  115. // transaction generation.
  116. type L1Tx struct {
  117. lineNum int
  118. fromIdxName string
  119. toIdxName string
  120. L1Tx common.L1Tx
  121. }
  122. // L2Tx is the data structure used internally for transaction test generation,
  123. // which contains a common.L2Tx data plus some intermediate data for the
  124. // transaction generation.
  125. type L2Tx struct {
  126. lineNum int
  127. fromIdxName string
  128. toIdxName string
  129. tokenID common.TokenID
  130. L2Tx common.L2Tx
  131. }
  132. // GenerateBlocks returns an array of BlockData for a given set. It uses the
  133. // users (keys & nonces) of the Context.
  134. func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
  135. parser := newParser(strings.NewReader(set))
  136. parsedSet, err := parser.parse()
  137. if err != nil {
  138. return nil, tracerr.Wrap(err)
  139. }
  140. if parsedSet.typ != setTypeBlockchain {
  141. return nil, tracerr.Wrap(fmt.Errorf("Expected set type: %s, found: %s", setTypeBlockchain, parsedSet.typ))
  142. }
  143. tc.Instructions = parsedSet.instructions
  144. tc.userNames = parsedSet.users
  145. tc.generateKeys(tc.userNames)
  146. var blocks []common.BlockData
  147. for _, inst := range parsedSet.instructions {
  148. switch inst.typ {
  149. case txTypeCreateAccountDepositCoordinator: // tx source: L1CoordinatorTx
  150. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  151. log.Error(err)
  152. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  153. }
  154. tx := common.L1Tx{
  155. FromEthAddr: tc.Users[inst.from].Addr,
  156. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  157. TokenID: inst.tokenID,
  158. Amount: big.NewInt(0),
  159. LoadAmount: big.NewInt(0),
  160. Type: common.TxTypeCreateAccountDeposit, // as txTypeCreateAccountDepositCoordinator is not valid oustide Til package
  161. }
  162. testTx := L1Tx{
  163. lineNum: inst.lineNum,
  164. fromIdxName: inst.from,
  165. L1Tx: tx,
  166. }
  167. tc.currBatchTest.l1CoordinatorTxs = append(tc.currBatchTest.l1CoordinatorTxs, testTx)
  168. case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer: // tx source: L1UserTx
  169. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  170. log.Error(err)
  171. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  172. }
  173. tx := common.L1Tx{
  174. FromEthAddr: tc.Users[inst.from].Addr,
  175. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  176. TokenID: inst.tokenID,
  177. Amount: big.NewInt(0),
  178. LoadAmount: inst.loadAmount,
  179. Type: inst.typ,
  180. }
  181. if inst.typ == common.TxTypeCreateAccountDepositTransfer {
  182. tx.Amount = inst.amount
  183. }
  184. testTx := L1Tx{
  185. lineNum: inst.lineNum,
  186. fromIdxName: inst.from,
  187. toIdxName: inst.to,
  188. L1Tx: tx,
  189. }
  190. if err := tc.addToL1UserQueue(testTx); err != nil {
  191. return nil, tracerr.Wrap(err)
  192. }
  193. case common.TxTypeDeposit, common.TxTypeDepositTransfer: // tx source: L1UserTx
  194. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  195. log.Error(err)
  196. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  197. }
  198. if err := tc.checkIfAccountExists(inst.from, inst); err != nil {
  199. log.Error(err)
  200. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  201. }
  202. tx := common.L1Tx{
  203. TokenID: inst.tokenID,
  204. Amount: big.NewInt(0),
  205. LoadAmount: inst.loadAmount,
  206. Type: inst.typ,
  207. }
  208. if inst.typ == common.TxTypeDepositTransfer {
  209. tx.Amount = inst.amount
  210. }
  211. testTx := L1Tx{
  212. lineNum: inst.lineNum,
  213. fromIdxName: inst.from,
  214. toIdxName: inst.to,
  215. L1Tx: tx,
  216. }
  217. if err := tc.addToL1UserQueue(testTx); err != nil {
  218. return nil, tracerr.Wrap(err)
  219. }
  220. case common.TxTypeTransfer: // L2Tx
  221. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  222. log.Error(err)
  223. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  224. }
  225. tx := common.L2Tx{
  226. Amount: inst.amount,
  227. Fee: common.FeeSelector(inst.fee),
  228. Type: common.TxTypeTransfer,
  229. EthBlockNum: tc.blockNum,
  230. }
  231. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  232. testTx := L2Tx{
  233. lineNum: inst.lineNum,
  234. fromIdxName: inst.from,
  235. toIdxName: inst.to,
  236. tokenID: inst.tokenID,
  237. L2Tx: tx,
  238. }
  239. tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx)
  240. case common.TxTypeForceTransfer: // tx source: L1UserTx
  241. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  242. log.Error(err)
  243. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  244. }
  245. tx := common.L1Tx{
  246. TokenID: inst.tokenID,
  247. Amount: inst.amount,
  248. LoadAmount: big.NewInt(0),
  249. Type: common.TxTypeForceTransfer,
  250. }
  251. testTx := L1Tx{
  252. lineNum: inst.lineNum,
  253. fromIdxName: inst.from,
  254. toIdxName: inst.to,
  255. L1Tx: tx,
  256. }
  257. if err := tc.addToL1UserQueue(testTx); err != nil {
  258. return nil, tracerr.Wrap(err)
  259. }
  260. case common.TxTypeExit: // tx source: L2Tx
  261. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  262. log.Error(err)
  263. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  264. }
  265. tx := common.L2Tx{
  266. ToIdx: common.Idx(1), // as is an Exit
  267. Fee: common.FeeSelector(inst.fee),
  268. Amount: inst.amount,
  269. Type: common.TxTypeExit,
  270. EthBlockNum: tc.blockNum,
  271. }
  272. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  273. testTx := L2Tx{
  274. lineNum: inst.lineNum,
  275. fromIdxName: inst.from,
  276. toIdxName: inst.to,
  277. tokenID: inst.tokenID,
  278. L2Tx: tx,
  279. }
  280. tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx)
  281. case common.TxTypeForceExit: // tx source: L1UserTx
  282. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  283. log.Error(err)
  284. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  285. }
  286. tx := common.L1Tx{
  287. ToIdx: common.Idx(1), // as is an Exit
  288. TokenID: inst.tokenID,
  289. Amount: inst.amount,
  290. LoadAmount: big.NewInt(0),
  291. Type: common.TxTypeForceExit,
  292. }
  293. testTx := L1Tx{
  294. lineNum: inst.lineNum,
  295. fromIdxName: inst.from,
  296. toIdxName: inst.to,
  297. L1Tx: tx,
  298. }
  299. if err := tc.addToL1UserQueue(testTx); err != nil {
  300. return nil, tracerr.Wrap(err)
  301. }
  302. case typeNewBatch:
  303. if err = tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil {
  304. return nil, tracerr.Wrap(err)
  305. }
  306. if err = tc.setIdxs(); err != nil {
  307. log.Error(err)
  308. return nil, tracerr.Wrap(err)
  309. }
  310. case typeNewBatchL1:
  311. // for each L1UserTx of the Queues[ToForgeNum], calculate the Idx
  312. if err = tc.calculateIdxForL1Txs(false, tc.Queues[tc.ToForgeNum]); err != nil {
  313. return nil, tracerr.Wrap(err)
  314. }
  315. if err = tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil {
  316. return nil, tracerr.Wrap(err)
  317. }
  318. tc.currBatch.L1Batch = true
  319. if err = tc.setIdxs(); err != nil {
  320. log.Error(err)
  321. return nil, tracerr.Wrap(err)
  322. }
  323. toForgeL1TxsNum := int64(tc.openToForge)
  324. tc.currBatch.Batch.ForgeL1TxsNum = &toForgeL1TxsNum
  325. // advance batch
  326. tc.ToForgeNum++
  327. if tc.ToForgeNum == tc.openToForge {
  328. tc.openToForge++
  329. newQueue := []L1Tx{}
  330. tc.Queues = append(tc.Queues, newQueue)
  331. }
  332. case typeNewBlock:
  333. blocks = append(blocks, tc.currBlock)
  334. tc.blockNum++
  335. tc.currBlock = newBlock(tc.blockNum)
  336. case typeAddToken:
  337. newToken := common.Token{
  338. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(inst.tokenID * 100))), //nolint:gomnd
  339. // Name: fmt.Sprintf("Token %d", inst.tokenID),
  340. // Symbol: fmt.Sprintf("TK%d", inst.tokenID),
  341. // Decimals: 18,
  342. TokenID: inst.tokenID,
  343. EthBlockNum: tc.blockNum,
  344. }
  345. if inst.tokenID != tc.LastRegisteredTokenID+1 {
  346. return nil, tracerr.Wrap(fmt.Errorf("Line %d: AddToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", inst.lineNum, tc.LastRegisteredTokenID+1, inst.tokenID))
  347. }
  348. tc.LastRegisteredTokenID++
  349. tc.currBlock.Rollup.AddedTokens = append(tc.currBlock.Rollup.AddedTokens, newToken)
  350. default:
  351. return nil, tracerr.Wrap(fmt.Errorf("Line %d: Unexpected type: %s", inst.lineNum, inst.typ))
  352. }
  353. }
  354. return blocks, nil
  355. }
  356. // calculateIdxsForL1Txs calculates new Idx for new created accounts. If
  357. // 'isCoordinatorTxs==true', adds the tx to tc.currBatch.L1CoordinatorTxs.
  358. func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error {
  359. // for each batch.L1CoordinatorTxs of the Queues[ToForgeNum], calculate the Idx
  360. for i := 0; i < len(txs); i++ {
  361. tx := txs[i]
  362. if tx.L1Tx.Type == common.TxTypeCreateAccountDeposit || tx.L1Tx.Type == common.TxTypeCreateAccountDepositTransfer {
  363. if tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] != nil { // if account already exists, return error
  364. return tracerr.Wrap(fmt.Errorf("Can not create same account twice (same User (%s) & same TokenID (%d)) (this is a design property of Til)", tx.fromIdxName, tx.L1Tx.TokenID))
  365. }
  366. tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{
  367. Idx: common.Idx(tc.idx),
  368. TokenID: tx.L1Tx.TokenID,
  369. Nonce: common.Nonce(0),
  370. BatchNum: tc.currBatchNum,
  371. }
  372. tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
  373. tc.accountsByIdx[tc.idx] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
  374. tc.UsersByIdx[tc.idx] = tc.Users[tx.fromIdxName]
  375. tc.idx++
  376. }
  377. if isCoordinatorTxs {
  378. tc.currBatch.L1CoordinatorTxs = append(tc.currBatch.L1CoordinatorTxs, tx.L1Tx)
  379. }
  380. }
  381. return nil
  382. }
  383. // setIdxs sets the Idxs to the transactions of the tc.currBatch
  384. func (tc *Context) setIdxs() error {
  385. // once Idxs are calculated, update transactions to use the new Idxs
  386. for i := 0; i < len(tc.currBatchTest.l2Txs); i++ {
  387. testTx := &tc.currBatchTest.l2Txs[i]
  388. if tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID] == nil {
  389. return tracerr.Wrap(fmt.Errorf("Line %d: %s from User %s for TokenID %d while account not created yet", testTx.lineNum, testTx.L2Tx.Type, testTx.fromIdxName, testTx.tokenID))
  390. }
  391. if testTx.L2Tx.Type == common.TxTypeTransfer {
  392. if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(testTx.toIdxName, testTx.tokenID)]; !ok {
  393. return tracerr.Wrap(fmt.Errorf("Line %d: Can not create Transfer for a non existing account. Batch %d, ToIdx name: %s, TokenID: %d", testTx.lineNum, tc.currBatchNum, testTx.toIdxName, testTx.tokenID))
  394. }
  395. }
  396. tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce++
  397. // next line is commented to avoid Blockchain L2Txs to have
  398. // Nonce different from 0, as from Blockchain those
  399. // transactions will come without Nonce
  400. // testTx.L2Tx.Nonce = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce
  401. // set real Idx
  402. testTx.L2Tx.FromIdx = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Idx
  403. if testTx.L2Tx.Type == common.TxTypeTransfer {
  404. testTx.L2Tx.ToIdx = tc.Users[testTx.toIdxName].Accounts[testTx.tokenID].Idx
  405. }
  406. // in case Type==Exit, ToIdx=1, already set at the
  407. // GenerateBlocks main switch inside TxTypeExit case
  408. nTx, err := common.NewL2Tx(&testTx.L2Tx)
  409. if err != nil {
  410. return tracerr.Wrap(fmt.Errorf("Line %d: %s", testTx.lineNum, err.Error()))
  411. }
  412. testTx.L2Tx = *nTx
  413. tc.currBatch.L2Txs = append(tc.currBatch.L2Txs, testTx.L2Tx)
  414. }
  415. tc.currBatch.Batch.LastIdx = int64(tc.idx - 1) // `-1` because tc.idx is the next available idx
  416. tc.currBlock.Rollup.Batches = append(tc.currBlock.Rollup.Batches, tc.currBatch)
  417. tc.currBatchNum++
  418. tc.currBatch = newBatchData(tc.currBatchNum)
  419. tc.currBatchTest.l1CoordinatorTxs = nil
  420. tc.currBatchTest.l2Txs = nil
  421. return nil
  422. }
  423. // addToL1UserQueue adds the L1UserTx into the queue that is open and has space
  424. func (tc *Context) addToL1UserQueue(tx L1Tx) error {
  425. if len(tc.Queues[tc.openToForge]) >= tc.rollupConstMaxL1UserTx {
  426. // if current OpenToForge queue reached its Max, move into a
  427. // new queue
  428. tc.openToForge++
  429. newQueue := []L1Tx{}
  430. tc.Queues = append(tc.Queues, newQueue)
  431. }
  432. // Fill L1UserTx specific parameters
  433. tx.L1Tx.UserOrigin = true
  434. toForgeL1TxsNum := int64(tc.openToForge)
  435. tx.L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
  436. tx.L1Tx.EthBlockNum = tc.blockNum
  437. tx.L1Tx.Position = len(tc.Queues[tc.openToForge])
  438. // When an L1UserTx is generated, all idxs must be available (except when idx == 0 or idx == 1)
  439. if tx.L1Tx.Type != common.TxTypeCreateAccountDeposit && tx.L1Tx.Type != common.TxTypeCreateAccountDepositTransfer {
  440. tx.L1Tx.FromIdx = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID].Idx
  441. }
  442. tx.L1Tx.FromEthAddr = tc.Users[tx.fromIdxName].Addr
  443. tx.L1Tx.FromBJJ = tc.Users[tx.fromIdxName].BJJ.Public()
  444. if tx.toIdxName == "" {
  445. tx.L1Tx.ToIdx = common.Idx(0)
  446. } else {
  447. account, ok := tc.Users[tx.toIdxName].Accounts[tx.L1Tx.TokenID]
  448. if !ok {
  449. return tracerr.Wrap(fmt.Errorf("Line %d: Transfer to User: %s, for TokenID: %d, "+
  450. "while account not created yet", tx.lineNum, tx.toIdxName, tx.L1Tx.TokenID))
  451. }
  452. tx.L1Tx.ToIdx = account.Idx
  453. }
  454. if tx.L1Tx.Type == common.TxTypeForceExit {
  455. tx.L1Tx.ToIdx = common.Idx(1)
  456. }
  457. nTx, err := common.NewL1Tx(&tx.L1Tx)
  458. if err != nil {
  459. return tracerr.Wrap(fmt.Errorf("Line %d: %s", tx.lineNum, err.Error()))
  460. }
  461. tx.L1Tx = *nTx
  462. tc.Queues[tc.openToForge] = append(tc.Queues[tc.openToForge], tx)
  463. tc.currBlock.Rollup.L1UserTxs = append(tc.currBlock.Rollup.L1UserTxs, tx.L1Tx)
  464. return nil
  465. }
  466. func (tc *Context) checkIfAccountExists(tf string, inst instruction) error {
  467. if tc.Users[tf].Accounts[inst.tokenID] == nil {
  468. return tracerr.Wrap(fmt.Errorf("%s at User: %s, for TokenID: %d, while account not created yet", inst.typ, tf, inst.tokenID))
  469. }
  470. return nil
  471. }
  472. func (tc *Context) checkIfTokenIsRegistered(inst instruction) error {
  473. if inst.tokenID > tc.LastRegisteredTokenID {
  474. return tracerr.Wrap(fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.LastRegisteredTokenID))
  475. }
  476. return nil
  477. }
  478. // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It
  479. // uses the users (keys) of the Context.
  480. func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
  481. parser := newParser(strings.NewReader(set))
  482. parsedSet, err := parser.parse()
  483. if err != nil {
  484. return nil, tracerr.Wrap(err)
  485. }
  486. if parsedSet.typ != setTypePoolL2 {
  487. return nil, tracerr.Wrap(fmt.Errorf("Expected set type: %s, found: %s", setTypePoolL2, parsedSet.typ))
  488. }
  489. tc.Instructions = parsedSet.instructions
  490. tc.userNames = parsedSet.users
  491. tc.generateKeys(tc.userNames)
  492. txs := []common.PoolL2Tx{}
  493. for _, inst := range tc.Instructions {
  494. switch inst.typ {
  495. case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
  496. if err := tc.checkIfAccountExists(inst.from, inst); err != nil {
  497. log.Error(err)
  498. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  499. }
  500. if inst.typ == common.TxTypeTransfer {
  501. // if TxTypeTransfer, need to exist the ToIdx account
  502. if err := tc.checkIfAccountExists(inst.to, inst); err != nil {
  503. log.Error(err)
  504. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  505. }
  506. }
  507. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  508. // if account of receiver does not exist, don't use
  509. // ToIdx, and use only ToEthAddr & ToBJJ
  510. tx := common.PoolL2Tx{
  511. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  512. TokenID: inst.tokenID,
  513. Amount: inst.amount,
  514. Fee: common.FeeSelector(inst.fee),
  515. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  516. State: common.PoolL2TxStatePending,
  517. Timestamp: time.Now(),
  518. RqToEthAddr: common.EmptyAddr,
  519. RqToBJJ: nil,
  520. Type: inst.typ,
  521. }
  522. if tx.Type == common.TxTypeTransfer {
  523. tx.ToIdx = tc.Users[inst.to].Accounts[inst.tokenID].Idx
  524. tx.ToEthAddr = tc.Users[inst.to].Addr
  525. tx.ToBJJ = tc.Users[inst.to].BJJ.Public()
  526. } else if tx.Type == common.TxTypeTransferToEthAddr {
  527. tx.ToIdx = common.Idx(0)
  528. tx.ToEthAddr = tc.Users[inst.to].Addr
  529. } else if tx.Type == common.TxTypeTransferToBJJ {
  530. tx.ToIdx = common.Idx(0)
  531. tx.ToEthAddr = common.FFAddr
  532. tx.ToBJJ = tc.Users[inst.to].BJJ.Public()
  533. }
  534. nTx, err := common.NewPoolL2Tx(&tx)
  535. if err != nil {
  536. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  537. }
  538. tx = *nTx
  539. // perform signature and set it to tx.Signature
  540. toSign, err := tx.HashToSign()
  541. if err != nil {
  542. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  543. }
  544. sig := tc.Users[inst.from].BJJ.SignPoseidon(toSign)
  545. tx.Signature = sig.Compress()
  546. txs = append(txs, tx)
  547. case common.TxTypeExit:
  548. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  549. tx := common.PoolL2Tx{
  550. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  551. ToIdx: common.Idx(1), // as is an Exit
  552. Fee: common.FeeSelector(inst.fee),
  553. TokenID: inst.tokenID,
  554. Amount: inst.amount,
  555. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  556. State: common.PoolL2TxStatePending,
  557. Type: common.TxTypeExit,
  558. }
  559. nTx, err := common.NewPoolL2Tx(&tx)
  560. if err != nil {
  561. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  562. }
  563. tx = *nTx
  564. // perform signature and set it to tx.Signature
  565. toSign, err := tx.HashToSign()
  566. if err != nil {
  567. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()))
  568. }
  569. sig := tc.Users[inst.from].BJJ.SignPoseidon(toSign)
  570. tx.Signature = sig.Compress()
  571. txs = append(txs, tx)
  572. default:
  573. return nil, tracerr.Wrap(fmt.Errorf("Line %d: instruction type unrecognized: %s", inst.lineNum, inst.typ))
  574. }
  575. }
  576. return txs, nil
  577. }
  578. // generateKeys generates BabyJubJub & Address keys for the given list of user
  579. // names in a deterministic way. This means, that for the same given
  580. // 'userNames' in a certain order, the keys will be always the same.
  581. func (tc *Context) generateKeys(userNames []string) {
  582. for i := 1; i < len(userNames)+1; i++ {
  583. if _, ok := tc.Users[userNames[i-1]]; ok {
  584. // account already created
  585. continue
  586. }
  587. // babyjubjub key
  588. var sk babyjub.PrivateKey
  589. copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
  590. // eth address
  591. var key ecdsa.PrivateKey
  592. key.D = big.NewInt(int64(i)) // only for testing
  593. key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
  594. key.Curve = ethCrypto.S256()
  595. addr := ethCrypto.PubkeyToAddress(key.PublicKey)
  596. u := User{
  597. Name: userNames[i-1],
  598. BJJ: &sk,
  599. Addr: addr,
  600. Accounts: make(map[common.TokenID]*Account),
  601. }
  602. tc.Users[userNames[i-1]] = &u
  603. }
  604. }
  605. // L1TxsToCommonL1Txs converts an array of []til.L1Tx to []common.L1Tx
  606. func L1TxsToCommonL1Txs(l1 []L1Tx) []common.L1Tx {
  607. var r []common.L1Tx
  608. for i := 0; i < len(l1); i++ {
  609. r = append(r, l1[i].L1Tx)
  610. }
  611. return r
  612. }
  613. // ConfigExtra is the configuration used in FillBlocksExtra to extend the
  614. // blocks returned by til.
  615. type ConfigExtra struct {
  616. // Address to set as forger for each batch
  617. BootCoordAddr ethCommon.Address
  618. // Coordinator user name used to select the corresponding accounts to
  619. // collect coordinator fees
  620. CoordUser string
  621. }
  622. // FillBlocksL1UserTxsBatchNum fills the BatchNum of forged L1UserTxs:
  623. // - blocks[].Rollup.L1UserTxs[].BatchNum
  624. func (tc *Context) FillBlocksL1UserTxsBatchNum(blocks []common.BlockData) {
  625. for i := range blocks {
  626. block := &blocks[i]
  627. for j := range block.Rollup.Batches {
  628. batch := &block.Rollup.Batches[j]
  629. if batch.L1Batch {
  630. // Set BatchNum for forged L1UserTxs to til blocks
  631. bn := batch.Batch.BatchNum
  632. for k := range blocks {
  633. block := &blocks[k]
  634. for l := range block.Rollup.L1UserTxs {
  635. tx := &block.Rollup.L1UserTxs[l]
  636. if *tx.ToForgeL1TxsNum == tc.extra.openToForge {
  637. tx.BatchNum = &bn
  638. }
  639. }
  640. }
  641. tc.extra.openToForge++
  642. }
  643. }
  644. }
  645. }
  646. // FillBlocksExtra fills extra fields not generated by til in each block, so
  647. // that the blockData is closer to what the HistoryDB stores. The filled fields are:
  648. // - blocks[].Rollup.Batch.EthBlockNum
  649. // - blocks[].Rollup.Batch.ForgerAddr
  650. // - blocks[].Rollup.Batch.ForgeL1TxsNum
  651. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].TxID
  652. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].BatchNum
  653. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EthBlockNum
  654. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].Position
  655. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveAmount
  656. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveLoadAmount
  657. // - blocks[].Rollup.Batch.L2Txs[].TxID
  658. // - blocks[].Rollup.Batch.L2Txs[].Position
  659. // - blocks[].Rollup.Batch.L2Txs[].Nonce
  660. // - blocks[].Rollup.Batch.ExitTree
  661. // - blocks[].Rollup.Batch.CreatedAccounts
  662. // - blocks[].Rollup.Batch.FeeIdxCoordinator
  663. // - blocks[].Rollup.Batch.CollectedFees
  664. func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra) error {
  665. // Fill extra fields not generated by til in til block
  666. for i := range blocks {
  667. block := &blocks[i]
  668. for j := range block.Rollup.Batches {
  669. batch := &block.Rollup.Batches[j]
  670. batch.Batch.EthBlockNum = block.Block.Num
  671. // til doesn't fill the batch forger addr
  672. batch.Batch.ForgerAddr = cfg.BootCoordAddr
  673. if batch.L1Batch {
  674. toForgeL1TxsNumCpy := tc.extra.toForgeL1TxsNum
  675. // til doesn't fill the ForgeL1TxsNum
  676. batch.Batch.ForgeL1TxsNum = &toForgeL1TxsNumCpy
  677. tc.extra.toForgeL1TxsNum++
  678. }
  679. batchNum := batch.Batch.BatchNum
  680. for k := range batch.L1CoordinatorTxs {
  681. tx := &batch.L1CoordinatorTxs[k]
  682. tx.BatchNum = &batchNum
  683. tx.EthBlockNum = batch.Batch.EthBlockNum
  684. }
  685. }
  686. }
  687. // Fill CreatedAccounts
  688. for i := range blocks {
  689. block := &blocks[i]
  690. for j := range block.Rollup.Batches {
  691. batch := &block.Rollup.Batches[j]
  692. l1Txs := []common.L1Tx{}
  693. if batch.L1Batch {
  694. for _, tx := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
  695. l1Txs = append(l1Txs, tx.L1Tx)
  696. }
  697. }
  698. l1Txs = append(l1Txs, batch.L1CoordinatorTxs...)
  699. for k := range l1Txs {
  700. tx := &l1Txs[k]
  701. if tx.Type == common.TxTypeCreateAccountDeposit ||
  702. tx.Type == common.TxTypeCreateAccountDepositTransfer {
  703. user, ok := tc.UsersByIdx[tc.extra.idx]
  704. if !ok {
  705. return tracerr.Wrap(fmt.Errorf("Created account with idx: %v not found", tc.extra.idx))
  706. }
  707. batch.CreatedAccounts = append(batch.CreatedAccounts,
  708. common.Account{
  709. Idx: common.Idx(tc.extra.idx),
  710. TokenID: tx.TokenID,
  711. BatchNum: batch.Batch.BatchNum,
  712. PublicKey: user.BJJ.Public(),
  713. EthAddr: user.Addr,
  714. Nonce: 0,
  715. Balance: big.NewInt(0),
  716. })
  717. tc.extra.idx++
  718. }
  719. }
  720. }
  721. }
  722. // Fill expected positions in L1CoordinatorTxs and L2Txs
  723. for i := range blocks {
  724. block := &blocks[i]
  725. for j := range block.Rollup.Batches {
  726. batch := &block.Rollup.Batches[j]
  727. position := 0
  728. if batch.L1Batch {
  729. position = len(tc.Queues[*batch.Batch.ForgeL1TxsNum])
  730. }
  731. for k := range batch.L1CoordinatorTxs {
  732. tx := &batch.L1CoordinatorTxs[k]
  733. tx.Position = position
  734. position++
  735. tx.EffectiveAmount = big.NewInt(0)
  736. tx.EffectiveLoadAmount = big.NewInt(0)
  737. nTx, err := common.NewL1Tx(tx)
  738. if err != nil {
  739. return tracerr.Wrap(err)
  740. }
  741. *tx = *nTx
  742. }
  743. for k := range batch.L2Txs {
  744. tx := &batch.L2Txs[k]
  745. tx.Position = position
  746. position++
  747. tc.extra.nonces[tx.FromIdx]++
  748. tx.Nonce = tc.extra.nonces[tx.FromIdx]
  749. nTx, err := common.NewL2Tx(tx)
  750. if err != nil {
  751. return tracerr.Wrap(err)
  752. }
  753. *tx = *nTx
  754. }
  755. }
  756. }
  757. // Fill ExitTree (only AccountIdx and Balance)
  758. for i := range blocks {
  759. block := &blocks[i]
  760. for j := range block.Rollup.Batches {
  761. batch := &block.Rollup.Batches[j]
  762. if batch.L1Batch {
  763. for _, _tx := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
  764. tx := _tx.L1Tx
  765. if tx.Type == common.TxTypeForceExit {
  766. batch.ExitTree =
  767. append(batch.ExitTree,
  768. common.ExitInfo{
  769. BatchNum: batch.Batch.BatchNum,
  770. AccountIdx: tx.FromIdx,
  771. Balance: tx.Amount,
  772. })
  773. }
  774. }
  775. }
  776. for k := range batch.L2Txs {
  777. tx := &batch.L2Txs[k]
  778. if tx.Type == common.TxTypeExit {
  779. batch.ExitTree = append(batch.ExitTree, common.ExitInfo{
  780. BatchNum: batch.Batch.BatchNum,
  781. AccountIdx: tx.FromIdx,
  782. Balance: tx.Amount,
  783. })
  784. }
  785. fee, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
  786. if err != nil {
  787. return tracerr.Wrap(err)
  788. }
  789. // Find the TokenID of the tx
  790. fromAcc, ok := tc.accountsByIdx[int(tx.FromIdx)]
  791. if !ok {
  792. return tracerr.Wrap(fmt.Errorf("L2tx.FromIdx idx: %v not found", tx.FromIdx))
  793. }
  794. // Find the idx of the CoordUser for the
  795. // TokenID, and if it exists, add the fee to
  796. // the collectedFees. Only consider the
  797. // coordinator account to receive fee if it was
  798. // created in this or a previous batch
  799. if acc, ok := tc.l1CreatedAccounts[idxTokenIDToString(cfg.CoordUser, fromAcc.TokenID)]; ok &&
  800. common.BatchNum(acc.BatchNum) <= batch.Batch.BatchNum {
  801. found := false
  802. for _, idx := range batch.Batch.FeeIdxsCoordinator {
  803. if idx == common.Idx(acc.Idx) {
  804. found = true
  805. break
  806. }
  807. }
  808. if !found {
  809. batch.Batch.FeeIdxsCoordinator = append(batch.Batch.FeeIdxsCoordinator,
  810. common.Idx(acc.Idx))
  811. batch.Batch.CollectedFees[fromAcc.TokenID] = big.NewInt(0)
  812. }
  813. collected := batch.Batch.CollectedFees[fromAcc.TokenID]
  814. collected.Add(collected, fee)
  815. }
  816. }
  817. }
  818. }
  819. return nil
  820. }