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.

957 lines
31 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.
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
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.
3 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 made of a string. 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. return tc.generateBlocks()
  146. }
  147. // GenerateBlocksFromInstructions returns an array of BlockData for a given set made of instructions. It uses the
  148. // users (keys & nonces) of the Context.
  149. func (tc *Context) GenerateBlocksFromInstructions(set []Instruction) ([]common.BlockData, error) {
  150. userNames := []string{}
  151. addedNames := make(map[string]bool)
  152. for _, inst := range set {
  153. if _, ok := addedNames[inst.From]; !ok {
  154. // If the name wasn't already added
  155. userNames = append(userNames, inst.From)
  156. addedNames[inst.From] = true
  157. }
  158. if _, ok := addedNames[inst.To]; !ok {
  159. // If the name wasn't already added
  160. userNames = append(userNames, inst.To)
  161. addedNames[inst.To] = true
  162. }
  163. }
  164. tc.userNames = userNames
  165. tc.instructions = set
  166. return tc.generateBlocks()
  167. }
  168. func (tc *Context) generateBlocks() ([]common.BlockData, error) {
  169. tc.generateKeys(tc.userNames)
  170. var blocks []common.BlockData
  171. for _, inst := range tc.instructions {
  172. switch inst.Typ {
  173. case TxTypeCreateAccountDepositCoordinator: // tx source: L1CoordinatorTx
  174. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  175. log.Error(err)
  176. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  177. }
  178. tx := common.L1Tx{
  179. FromEthAddr: tc.Users[inst.From].Addr,
  180. FromBJJ: tc.Users[inst.From].BJJ.Public(),
  181. TokenID: inst.TokenID,
  182. Amount: big.NewInt(0),
  183. LoadAmount: big.NewInt(0),
  184. Type: common.TxTypeCreateAccountDeposit, // as TxTypeCreateAccountDepositCoordinator is not valid oustide Til package
  185. }
  186. testTx := L1Tx{
  187. lineNum: inst.LineNum,
  188. fromIdxName: inst.From,
  189. L1Tx: tx,
  190. }
  191. tc.currBatchTest.l1CoordinatorTxs = append(tc.currBatchTest.l1CoordinatorTxs, testTx)
  192. case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer: // tx source: L1UserTx
  193. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  194. log.Error(err)
  195. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  196. }
  197. tx := common.L1Tx{
  198. FromEthAddr: tc.Users[inst.From].Addr,
  199. FromBJJ: tc.Users[inst.From].BJJ.Public(),
  200. TokenID: inst.TokenID,
  201. Amount: big.NewInt(0),
  202. LoadAmount: inst.LoadAmount,
  203. Type: inst.Typ,
  204. }
  205. if inst.Typ == common.TxTypeCreateAccountDepositTransfer {
  206. tx.Amount = inst.Amount
  207. }
  208. testTx := L1Tx{
  209. lineNum: inst.LineNum,
  210. fromIdxName: inst.From,
  211. toIdxName: inst.To,
  212. L1Tx: tx,
  213. }
  214. if err := tc.addToL1UserQueue(testTx); err != nil {
  215. return nil, tracerr.Wrap(err)
  216. }
  217. case common.TxTypeDeposit, common.TxTypeDepositTransfer: // tx source: L1UserTx
  218. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  219. log.Error(err)
  220. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  221. }
  222. if err := tc.checkIfAccountExists(inst.From, inst); err != nil {
  223. log.Error(err)
  224. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  225. }
  226. tx := common.L1Tx{
  227. TokenID: inst.TokenID,
  228. Amount: big.NewInt(0),
  229. LoadAmount: inst.LoadAmount,
  230. Type: inst.Typ,
  231. }
  232. if inst.Typ == common.TxTypeDepositTransfer {
  233. tx.Amount = inst.Amount
  234. }
  235. testTx := L1Tx{
  236. lineNum: inst.LineNum,
  237. fromIdxName: inst.From,
  238. toIdxName: inst.To,
  239. L1Tx: tx,
  240. }
  241. if err := tc.addToL1UserQueue(testTx); err != nil {
  242. return nil, tracerr.Wrap(err)
  243. }
  244. case common.TxTypeTransfer: // L2Tx
  245. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  246. log.Error(err)
  247. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  248. }
  249. tx := common.L2Tx{
  250. Amount: inst.Amount,
  251. Fee: common.FeeSelector(inst.Fee),
  252. Type: common.TxTypeTransfer,
  253. EthBlockNum: tc.blockNum,
  254. }
  255. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  256. testTx := L2Tx{
  257. lineNum: inst.LineNum,
  258. fromIdxName: inst.From,
  259. toIdxName: inst.To,
  260. tokenID: inst.TokenID,
  261. L2Tx: tx,
  262. }
  263. tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx)
  264. case common.TxTypeForceTransfer: // tx source: L1UserTx
  265. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  266. log.Error(err)
  267. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  268. }
  269. tx := common.L1Tx{
  270. TokenID: inst.TokenID,
  271. Amount: inst.Amount,
  272. LoadAmount: big.NewInt(0),
  273. Type: common.TxTypeForceTransfer,
  274. }
  275. testTx := L1Tx{
  276. lineNum: inst.LineNum,
  277. fromIdxName: inst.From,
  278. toIdxName: inst.To,
  279. L1Tx: tx,
  280. }
  281. if err := tc.addToL1UserQueue(testTx); err != nil {
  282. return nil, tracerr.Wrap(err)
  283. }
  284. case common.TxTypeExit: // tx source: L2Tx
  285. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  286. log.Error(err)
  287. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  288. }
  289. tx := common.L2Tx{
  290. ToIdx: common.Idx(1), // as is an Exit
  291. Fee: common.FeeSelector(inst.Fee),
  292. Amount: inst.Amount,
  293. Type: common.TxTypeExit,
  294. EthBlockNum: tc.blockNum,
  295. }
  296. tx.BatchNum = common.BatchNum(tc.currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  297. testTx := L2Tx{
  298. lineNum: inst.LineNum,
  299. fromIdxName: inst.From,
  300. toIdxName: inst.To,
  301. tokenID: inst.TokenID,
  302. L2Tx: tx,
  303. }
  304. tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx)
  305. case common.TxTypeForceExit: // tx source: L1UserTx
  306. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  307. log.Error(err)
  308. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  309. }
  310. tx := common.L1Tx{
  311. ToIdx: common.Idx(1), // as is an Exit
  312. TokenID: inst.TokenID,
  313. Amount: inst.Amount,
  314. LoadAmount: big.NewInt(0),
  315. Type: common.TxTypeForceExit,
  316. }
  317. testTx := L1Tx{
  318. lineNum: inst.LineNum,
  319. fromIdxName: inst.From,
  320. toIdxName: inst.To,
  321. L1Tx: tx,
  322. }
  323. if err := tc.addToL1UserQueue(testTx); err != nil {
  324. return nil, tracerr.Wrap(err)
  325. }
  326. case TypeNewBatch:
  327. if err := tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil {
  328. return nil, tracerr.Wrap(err)
  329. }
  330. if err := tc.setIdxs(); err != nil {
  331. log.Error(err)
  332. return nil, tracerr.Wrap(err)
  333. }
  334. case TypeNewBatchL1:
  335. // for each L1UserTx of the Queues[ToForgeNum], calculate the Idx
  336. if err := tc.calculateIdxForL1Txs(false, tc.Queues[tc.ToForgeNum]); err != nil {
  337. return nil, tracerr.Wrap(err)
  338. }
  339. if err := tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil {
  340. return nil, tracerr.Wrap(err)
  341. }
  342. tc.currBatch.L1Batch = true
  343. if err := tc.setIdxs(); err != nil {
  344. log.Error(err)
  345. return nil, tracerr.Wrap(err)
  346. }
  347. toForgeL1TxsNum := int64(tc.openToForge)
  348. tc.currBatch.Batch.ForgeL1TxsNum = &toForgeL1TxsNum
  349. // advance batch
  350. tc.ToForgeNum++
  351. if tc.ToForgeNum == tc.openToForge {
  352. tc.openToForge++
  353. newQueue := []L1Tx{}
  354. tc.Queues = append(tc.Queues, newQueue)
  355. }
  356. case TypeNewBlock:
  357. blocks = append(blocks, tc.currBlock)
  358. tc.blockNum++
  359. tc.currBlock = newBlock(tc.blockNum)
  360. case TypeAddToken:
  361. newToken := common.Token{
  362. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(inst.TokenID * 100))), //nolint:gomnd
  363. // Name: fmt.Sprintf("Token %d", inst.TokenID),
  364. // Symbol: fmt.Sprintf("TK%d", inst.TokenID),
  365. // Decimals: 18,
  366. TokenID: inst.TokenID,
  367. EthBlockNum: tc.blockNum,
  368. }
  369. if inst.TokenID != tc.LastRegisteredTokenID+1 {
  370. 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))
  371. }
  372. tc.LastRegisteredTokenID++
  373. tc.currBlock.Rollup.AddedTokens = append(tc.currBlock.Rollup.AddedTokens, newToken)
  374. default:
  375. return nil, tracerr.Wrap(fmt.Errorf("Line %d: Unexpected type: %s", inst.LineNum, inst.Typ))
  376. }
  377. }
  378. return blocks, nil
  379. }
  380. // calculateIdxsForL1Txs calculates new Idx for new created accounts. If
  381. // 'isCoordinatorTxs==true', adds the tx to tc.currBatch.L1CoordinatorTxs.
  382. func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error {
  383. // for each batch.L1CoordinatorTxs of the Queues[ToForgeNum], calculate the Idx
  384. for i := 0; i < len(txs); i++ {
  385. tx := txs[i]
  386. if tx.L1Tx.Type == common.TxTypeCreateAccountDeposit || tx.L1Tx.Type == common.TxTypeCreateAccountDepositTransfer {
  387. if tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] != nil { // if account already exists, return error
  388. 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))
  389. }
  390. tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{
  391. Idx: common.Idx(tc.idx),
  392. TokenID: tx.L1Tx.TokenID,
  393. Nonce: common.Nonce(0),
  394. BatchNum: tc.currBatchNum,
  395. }
  396. tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
  397. tc.accountsByIdx[tc.idx] = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID]
  398. tc.UsersByIdx[tc.idx] = tc.Users[tx.fromIdxName]
  399. tc.idx++
  400. }
  401. if isCoordinatorTxs {
  402. tc.currBatch.L1CoordinatorTxs = append(tc.currBatch.L1CoordinatorTxs, tx.L1Tx)
  403. }
  404. }
  405. return nil
  406. }
  407. // setIdxs sets the Idxs to the transactions of the tc.currBatch
  408. func (tc *Context) setIdxs() error {
  409. // once Idxs are calculated, update transactions to use the new Idxs
  410. for i := 0; i < len(tc.currBatchTest.l2Txs); i++ {
  411. testTx := &tc.currBatchTest.l2Txs[i]
  412. if tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID] == nil {
  413. 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))
  414. }
  415. if testTx.L2Tx.Type == common.TxTypeTransfer {
  416. if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(testTx.toIdxName, testTx.tokenID)]; !ok {
  417. 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))
  418. }
  419. }
  420. tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce++
  421. // next line is commented to avoid Blockchain L2Txs to have
  422. // Nonce different from 0, as from Blockchain those
  423. // transactions will come without Nonce
  424. // testTx.L2Tx.Nonce = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Nonce
  425. // set real Idx
  426. testTx.L2Tx.FromIdx = tc.Users[testTx.fromIdxName].Accounts[testTx.tokenID].Idx
  427. if testTx.L2Tx.Type == common.TxTypeTransfer {
  428. testTx.L2Tx.ToIdx = tc.Users[testTx.toIdxName].Accounts[testTx.tokenID].Idx
  429. }
  430. // in case Type==Exit, ToIdx=1, already set at the
  431. // GenerateBlocks main switch inside TxTypeExit case
  432. nTx, err := common.NewL2Tx(&testTx.L2Tx)
  433. if err != nil {
  434. return tracerr.Wrap(fmt.Errorf("Line %d: %s", testTx.lineNum, err.Error()))
  435. }
  436. testTx.L2Tx = *nTx
  437. tc.currBatch.L2Txs = append(tc.currBatch.L2Txs, testTx.L2Tx)
  438. }
  439. tc.currBatch.Batch.LastIdx = int64(tc.idx - 1) // `-1` because tc.idx is the next available idx
  440. tc.currBlock.Rollup.Batches = append(tc.currBlock.Rollup.Batches, tc.currBatch)
  441. tc.currBatchNum++
  442. tc.currBatch = newBatchData(tc.currBatchNum)
  443. tc.currBatchTest.l1CoordinatorTxs = nil
  444. tc.currBatchTest.l2Txs = nil
  445. return nil
  446. }
  447. // addToL1UserQueue adds the L1UserTx into the queue that is open and has space
  448. func (tc *Context) addToL1UserQueue(tx L1Tx) error {
  449. if len(tc.Queues[tc.openToForge]) >= tc.rollupConstMaxL1UserTx {
  450. // if current OpenToForge queue reached its Max, move into a
  451. // new queue
  452. tc.openToForge++
  453. newQueue := []L1Tx{}
  454. tc.Queues = append(tc.Queues, newQueue)
  455. }
  456. // Fill L1UserTx specific parameters
  457. tx.L1Tx.UserOrigin = true
  458. toForgeL1TxsNum := int64(tc.openToForge)
  459. tx.L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
  460. tx.L1Tx.EthBlockNum = tc.blockNum
  461. tx.L1Tx.Position = len(tc.Queues[tc.openToForge])
  462. // When an L1UserTx is generated, all idxs must be available (except when idx == 0 or idx == 1)
  463. if tx.L1Tx.Type != common.TxTypeCreateAccountDeposit && tx.L1Tx.Type != common.TxTypeCreateAccountDepositTransfer {
  464. tx.L1Tx.FromIdx = tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID].Idx
  465. }
  466. tx.L1Tx.FromEthAddr = tc.Users[tx.fromIdxName].Addr
  467. tx.L1Tx.FromBJJ = tc.Users[tx.fromIdxName].BJJ.Public()
  468. if tx.toIdxName == "" {
  469. tx.L1Tx.ToIdx = common.Idx(0)
  470. } else {
  471. account, ok := tc.Users[tx.toIdxName].Accounts[tx.L1Tx.TokenID]
  472. if !ok {
  473. return tracerr.Wrap(fmt.Errorf("Line %d: Transfer to User: %s, for TokenID: %d, "+
  474. "while account not created yet", tx.lineNum, tx.toIdxName, tx.L1Tx.TokenID))
  475. }
  476. tx.L1Tx.ToIdx = account.Idx
  477. }
  478. if tx.L1Tx.Type == common.TxTypeForceExit {
  479. tx.L1Tx.ToIdx = common.Idx(1)
  480. }
  481. nTx, err := common.NewL1Tx(&tx.L1Tx)
  482. if err != nil {
  483. return tracerr.Wrap(fmt.Errorf("Line %d: %s", tx.lineNum, err.Error()))
  484. }
  485. tx.L1Tx = *nTx
  486. tc.Queues[tc.openToForge] = append(tc.Queues[tc.openToForge], tx)
  487. tc.currBlock.Rollup.L1UserTxs = append(tc.currBlock.Rollup.L1UserTxs, tx.L1Tx)
  488. return nil
  489. }
  490. func (tc *Context) checkIfAccountExists(tf string, inst Instruction) error {
  491. if tc.Users[tf].Accounts[inst.TokenID] == nil {
  492. return tracerr.Wrap(fmt.Errorf("%s at User: %s, for TokenID: %d, while account not created yet", inst.Typ, tf, inst.TokenID))
  493. }
  494. return nil
  495. }
  496. func (tc *Context) checkIfTokenIsRegistered(inst Instruction) error {
  497. if inst.TokenID > tc.LastRegisteredTokenID {
  498. return tracerr.Wrap(fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.Typ, inst.TokenID, tc.LastRegisteredTokenID))
  499. }
  500. return nil
  501. }
  502. // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set made of a string. It
  503. // uses the users (keys) of the Context.
  504. func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
  505. parser := newParser(strings.NewReader(set))
  506. parsedSet, err := parser.parse()
  507. if err != nil {
  508. return nil, tracerr.Wrap(err)
  509. }
  510. if parsedSet.typ != SetTypePoolL2 {
  511. return nil, tracerr.Wrap(fmt.Errorf("Expected set type: %s, found: %s", SetTypePoolL2, parsedSet.typ))
  512. }
  513. tc.instructions = parsedSet.instructions
  514. tc.userNames = parsedSet.users
  515. return tc.generatePoolL2Txs()
  516. }
  517. // GeneratePoolL2TxsFromInstructions returns an array of common.PoolL2Tx from a given set made of instructions. It
  518. // uses the users (keys) of the Context.
  519. func (tc *Context) GeneratePoolL2TxsFromInstructions(set []Instruction) ([]common.PoolL2Tx, error) {
  520. userNames := []string{}
  521. addedNames := make(map[string]bool)
  522. for _, inst := range set {
  523. if _, ok := addedNames[inst.From]; !ok {
  524. // If the name wasn't already added
  525. userNames = append(userNames, inst.From)
  526. addedNames[inst.From] = true
  527. }
  528. if _, ok := addedNames[inst.To]; !ok {
  529. // If the name wasn't already added
  530. userNames = append(userNames, inst.To)
  531. addedNames[inst.To] = true
  532. }
  533. }
  534. tc.userNames = userNames
  535. tc.instructions = set
  536. return tc.generatePoolL2Txs()
  537. }
  538. func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) {
  539. tc.generateKeys(tc.userNames)
  540. txs := []common.PoolL2Tx{}
  541. for _, inst := range tc.instructions {
  542. switch inst.Typ {
  543. case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
  544. if err := tc.checkIfAccountExists(inst.From, inst); err != nil {
  545. log.Error(err)
  546. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  547. }
  548. if inst.Typ == common.TxTypeTransfer {
  549. // if TxTypeTransfer, need to exist the ToIdx account
  550. if err := tc.checkIfAccountExists(inst.To, inst); err != nil {
  551. log.Error(err)
  552. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  553. }
  554. }
  555. tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
  556. // if account of receiver does not exist, don't use
  557. // ToIdx, and use only ToEthAddr & ToBJJ
  558. tx := common.PoolL2Tx{
  559. FromIdx: tc.Users[inst.From].Accounts[inst.TokenID].Idx,
  560. TokenID: inst.TokenID,
  561. Amount: inst.Amount,
  562. Fee: common.FeeSelector(inst.Fee),
  563. Nonce: tc.Users[inst.From].Accounts[inst.TokenID].Nonce,
  564. State: common.PoolL2TxStatePending,
  565. Timestamp: time.Now(),
  566. RqToEthAddr: common.EmptyAddr,
  567. RqToBJJ: nil,
  568. Type: inst.Typ,
  569. }
  570. if tx.Type == common.TxTypeTransfer {
  571. tx.ToIdx = tc.Users[inst.To].Accounts[inst.TokenID].Idx
  572. tx.ToEthAddr = tc.Users[inst.To].Addr
  573. tx.ToBJJ = tc.Users[inst.To].BJJ.Public()
  574. } else if tx.Type == common.TxTypeTransferToEthAddr {
  575. tx.ToIdx = common.Idx(0)
  576. tx.ToEthAddr = tc.Users[inst.To].Addr
  577. } else if tx.Type == common.TxTypeTransferToBJJ {
  578. tx.ToIdx = common.Idx(0)
  579. tx.ToEthAddr = common.FFAddr
  580. tx.ToBJJ = tc.Users[inst.To].BJJ.Public()
  581. }
  582. nTx, err := common.NewPoolL2Tx(&tx)
  583. if err != nil {
  584. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  585. }
  586. tx = *nTx
  587. // perform signature and set it to tx.Signature
  588. toSign, err := tx.HashToSign()
  589. if err != nil {
  590. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  591. }
  592. sig := tc.Users[inst.From].BJJ.SignPoseidon(toSign)
  593. tx.Signature = sig.Compress()
  594. txs = append(txs, tx)
  595. case common.TxTypeExit:
  596. tc.Users[inst.From].Accounts[inst.TokenID].Nonce++
  597. tx := common.PoolL2Tx{
  598. FromIdx: tc.Users[inst.From].Accounts[inst.TokenID].Idx,
  599. ToIdx: common.Idx(1), // as is an Exit
  600. Fee: common.FeeSelector(inst.Fee),
  601. TokenID: inst.TokenID,
  602. Amount: inst.Amount,
  603. Nonce: tc.Users[inst.From].Accounts[inst.TokenID].Nonce,
  604. State: common.PoolL2TxStatePending,
  605. Type: common.TxTypeExit,
  606. }
  607. nTx, err := common.NewPoolL2Tx(&tx)
  608. if err != nil {
  609. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  610. }
  611. tx = *nTx
  612. // perform signature and set it to tx.Signature
  613. toSign, err := tx.HashToSign()
  614. if err != nil {
  615. return nil, tracerr.Wrap(fmt.Errorf("Line %d: %s", inst.LineNum, err.Error()))
  616. }
  617. sig := tc.Users[inst.From].BJJ.SignPoseidon(toSign)
  618. tx.Signature = sig.Compress()
  619. txs = append(txs, tx)
  620. default:
  621. return nil, tracerr.Wrap(fmt.Errorf("Line %d: instruction type unrecognized: %s", inst.LineNum, inst.Typ))
  622. }
  623. }
  624. return txs, nil
  625. }
  626. // generateKeys generates BabyJubJub & Address keys for the given list of user
  627. // names in a deterministic way. This means, that for the same given
  628. // 'userNames' in a certain order, the keys will be always the same.
  629. func (tc *Context) generateKeys(userNames []string) {
  630. for i := 1; i < len(userNames)+1; i++ {
  631. if _, ok := tc.Users[userNames[i-1]]; ok {
  632. // account already created
  633. continue
  634. }
  635. // babyjubjub key
  636. var sk babyjub.PrivateKey
  637. copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
  638. // eth address
  639. var key ecdsa.PrivateKey
  640. key.D = big.NewInt(int64(i)) // only for testing
  641. key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
  642. key.Curve = ethCrypto.S256()
  643. addr := ethCrypto.PubkeyToAddress(key.PublicKey)
  644. u := User{
  645. Name: userNames[i-1],
  646. BJJ: &sk,
  647. Addr: addr,
  648. Accounts: make(map[common.TokenID]*Account),
  649. }
  650. tc.Users[userNames[i-1]] = &u
  651. }
  652. }
  653. // L1TxsToCommonL1Txs converts an array of []til.L1Tx to []common.L1Tx
  654. func L1TxsToCommonL1Txs(l1 []L1Tx) []common.L1Tx {
  655. var r []common.L1Tx
  656. for i := 0; i < len(l1); i++ {
  657. r = append(r, l1[i].L1Tx)
  658. }
  659. return r
  660. }
  661. // ConfigExtra is the configuration used in FillBlocksExtra to extend the
  662. // blocks returned by til.
  663. type ConfigExtra struct {
  664. // Address to set as forger for each batch
  665. BootCoordAddr ethCommon.Address
  666. // Coordinator user name used to select the corresponding accounts to
  667. // collect coordinator fees
  668. CoordUser string
  669. }
  670. // FillBlocksL1UserTxsBatchNum fills the BatchNum of forged L1UserTxs:
  671. // - blocks[].Rollup.L1UserTxs[].BatchNum
  672. func (tc *Context) FillBlocksL1UserTxsBatchNum(blocks []common.BlockData) {
  673. for i := range blocks {
  674. block := &blocks[i]
  675. for j := range block.Rollup.Batches {
  676. batch := &block.Rollup.Batches[j]
  677. if batch.L1Batch {
  678. // Set BatchNum for forged L1UserTxs to til blocks
  679. bn := batch.Batch.BatchNum
  680. for k := range blocks {
  681. block := &blocks[k]
  682. for l := range block.Rollup.L1UserTxs {
  683. tx := &block.Rollup.L1UserTxs[l]
  684. if *tx.ToForgeL1TxsNum == tc.extra.openToForge {
  685. tx.BatchNum = &bn
  686. }
  687. }
  688. }
  689. tc.extra.openToForge++
  690. }
  691. }
  692. }
  693. }
  694. // FillBlocksForgedL1UserTxs fills the L1UserTxs of a batch with the L1UserTxs
  695. // that are forged in that batch. It always sets `EffectiveAmount` = `Amount`
  696. // and `EffectiveLoadAmount` = `LoadAmount`.
  697. func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error {
  698. for i := range blocks {
  699. block := &blocks[i]
  700. for j := range block.Rollup.Batches {
  701. batch := &block.Rollup.Batches[j]
  702. if batch.L1Batch {
  703. batchNum := batch.Batch.BatchNum
  704. queue := tc.Queues[int(*batch.Batch.ForgeL1TxsNum)]
  705. batch.L1UserTxs = make([]common.L1Tx, len(queue))
  706. for k := range queue {
  707. tx := &batch.L1UserTxs[k]
  708. *tx = queue[k].L1Tx
  709. tx.EffectiveAmount = tx.Amount
  710. tx.EffectiveLoadAmount = tx.LoadAmount
  711. tx.BatchNum = &batchNum
  712. _tx, err := common.NewL1Tx(tx)
  713. if err != nil {
  714. return tracerr.Wrap(err)
  715. }
  716. *tx = *_tx
  717. }
  718. }
  719. }
  720. }
  721. return nil
  722. }
  723. // FillBlocksExtra fills extra fields not generated by til in each block, so
  724. // that the blockData is closer to what the HistoryDB stores. The filled fields are:
  725. // - blocks[].Rollup.Batch.EthBlockNum
  726. // - blocks[].Rollup.Batch.ForgerAddr
  727. // - blocks[].Rollup.Batch.ForgeL1TxsNum
  728. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].TxID
  729. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].BatchNum
  730. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EthBlockNum
  731. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].Position
  732. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveAmount
  733. // - blocks[].Rollup.Batch.L1CoordinatorTxs[].EffectiveLoadAmount
  734. // - blocks[].Rollup.Batch.L2Txs[].TxID
  735. // - blocks[].Rollup.Batch.L2Txs[].Position
  736. // - blocks[].Rollup.Batch.L2Txs[].Nonce
  737. // - blocks[].Rollup.Batch.ExitTree
  738. // - blocks[].Rollup.Batch.CreatedAccounts
  739. // - blocks[].Rollup.Batch.FeeIdxCoordinator
  740. // - blocks[].Rollup.Batch.CollectedFees
  741. func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra) error {
  742. // Fill extra fields not generated by til in til block
  743. for i := range blocks {
  744. block := &blocks[i]
  745. for j := range block.Rollup.Batches {
  746. batch := &block.Rollup.Batches[j]
  747. batch.Batch.EthBlockNum = block.Block.Num
  748. // til doesn't fill the batch forger addr
  749. batch.Batch.ForgerAddr = cfg.BootCoordAddr
  750. if batch.L1Batch {
  751. toForgeL1TxsNumCpy := tc.extra.toForgeL1TxsNum
  752. // til doesn't fill the ForgeL1TxsNum
  753. batch.Batch.ForgeL1TxsNum = &toForgeL1TxsNumCpy
  754. tc.extra.toForgeL1TxsNum++
  755. }
  756. batchNum := batch.Batch.BatchNum
  757. for k := range batch.L1CoordinatorTxs {
  758. tx := &batch.L1CoordinatorTxs[k]
  759. tx.BatchNum = &batchNum
  760. tx.EthBlockNum = batch.Batch.EthBlockNum
  761. }
  762. }
  763. }
  764. // Fill CreatedAccounts
  765. for i := range blocks {
  766. block := &blocks[i]
  767. for j := range block.Rollup.Batches {
  768. batch := &block.Rollup.Batches[j]
  769. l1Txs := []common.L1Tx{}
  770. if batch.L1Batch {
  771. for _, tx := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
  772. l1Txs = append(l1Txs, tx.L1Tx)
  773. }
  774. }
  775. l1Txs = append(l1Txs, batch.L1CoordinatorTxs...)
  776. for k := range l1Txs {
  777. tx := &l1Txs[k]
  778. if tx.Type == common.TxTypeCreateAccountDeposit ||
  779. tx.Type == common.TxTypeCreateAccountDepositTransfer {
  780. user, ok := tc.UsersByIdx[tc.extra.idx]
  781. if !ok {
  782. return tracerr.Wrap(fmt.Errorf("Created account with idx: %v not found", tc.extra.idx))
  783. }
  784. batch.CreatedAccounts = append(batch.CreatedAccounts,
  785. common.Account{
  786. Idx: common.Idx(tc.extra.idx),
  787. TokenID: tx.TokenID,
  788. BatchNum: batch.Batch.BatchNum,
  789. PublicKey: user.BJJ.Public(),
  790. EthAddr: user.Addr,
  791. Nonce: 0,
  792. Balance: big.NewInt(0),
  793. })
  794. tc.extra.idx++
  795. }
  796. }
  797. }
  798. }
  799. // Fill expected positions in L1CoordinatorTxs and L2Txs
  800. for i := range blocks {
  801. block := &blocks[i]
  802. for j := range block.Rollup.Batches {
  803. batch := &block.Rollup.Batches[j]
  804. position := 0
  805. if batch.L1Batch {
  806. position = len(tc.Queues[*batch.Batch.ForgeL1TxsNum])
  807. }
  808. for k := range batch.L1CoordinatorTxs {
  809. tx := &batch.L1CoordinatorTxs[k]
  810. tx.Position = position
  811. position++
  812. tx.EffectiveAmount = big.NewInt(0)
  813. tx.EffectiveLoadAmount = big.NewInt(0)
  814. nTx, err := common.NewL1Tx(tx)
  815. if err != nil {
  816. return tracerr.Wrap(err)
  817. }
  818. *tx = *nTx
  819. }
  820. for k := range batch.L2Txs {
  821. tx := &batch.L2Txs[k]
  822. tx.Position = position
  823. position++
  824. tc.extra.nonces[tx.FromIdx]++
  825. tx.Nonce = tc.extra.nonces[tx.FromIdx]
  826. nTx, err := common.NewL2Tx(tx)
  827. if err != nil {
  828. return tracerr.Wrap(err)
  829. }
  830. *tx = *nTx
  831. }
  832. }
  833. }
  834. // Fill ExitTree (only AccountIdx and Balance)
  835. for i := range blocks {
  836. block := &blocks[i]
  837. for j := range block.Rollup.Batches {
  838. batch := &block.Rollup.Batches[j]
  839. if batch.L1Batch {
  840. for _, _tx := range tc.Queues[*batch.Batch.ForgeL1TxsNum] {
  841. tx := _tx.L1Tx
  842. if tx.Type == common.TxTypeForceExit {
  843. batch.ExitTree =
  844. append(batch.ExitTree,
  845. common.ExitInfo{
  846. BatchNum: batch.Batch.BatchNum,
  847. AccountIdx: tx.FromIdx,
  848. Balance: tx.Amount,
  849. })
  850. }
  851. }
  852. }
  853. for k := range batch.L2Txs {
  854. tx := &batch.L2Txs[k]
  855. if tx.Type == common.TxTypeExit {
  856. batch.ExitTree = append(batch.ExitTree, common.ExitInfo{
  857. BatchNum: batch.Batch.BatchNum,
  858. AccountIdx: tx.FromIdx,
  859. Balance: tx.Amount,
  860. })
  861. }
  862. fee, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
  863. if err != nil {
  864. return tracerr.Wrap(err)
  865. }
  866. // Find the TokenID of the tx
  867. fromAcc, ok := tc.accountsByIdx[int(tx.FromIdx)]
  868. if !ok {
  869. return tracerr.Wrap(fmt.Errorf("L2tx.FromIdx idx: %v not found", tx.FromIdx))
  870. }
  871. // Find the idx of the CoordUser for the
  872. // TokenID, and if it exists, add the fee to
  873. // the collectedFees. Only consider the
  874. // coordinator account to receive fee if it was
  875. // created in this or a previous batch
  876. if acc, ok := tc.l1CreatedAccounts[idxTokenIDToString(cfg.CoordUser, fromAcc.TokenID)]; ok &&
  877. common.BatchNum(acc.BatchNum) <= batch.Batch.BatchNum {
  878. found := false
  879. for _, idx := range batch.Batch.FeeIdxsCoordinator {
  880. if idx == common.Idx(acc.Idx) {
  881. found = true
  882. break
  883. }
  884. }
  885. if !found {
  886. batch.Batch.FeeIdxsCoordinator = append(batch.Batch.FeeIdxsCoordinator,
  887. common.Idx(acc.Idx))
  888. batch.Batch.CollectedFees[fromAcc.TokenID] = big.NewInt(0)
  889. }
  890. collected := batch.Batch.CollectedFees[fromAcc.TokenID]
  891. collected.Add(collected, fee)
  892. }
  893. }
  894. }
  895. }
  896. return nil
  897. }