diff --git a/test/zkproof/flows_test.go b/test/zkproof/flows_test.go index 5348cce..255407a 100644 --- a/test/zkproof/flows_test.go +++ b/test/zkproof/flows_test.go @@ -111,7 +111,7 @@ func initTxSelector(t *testing.T, chainID uint16, hermezContractAddr ethCommon.A return txsel, l2DB, syncStateDB } -func TestTxSelectorBatchBuilderZKInputs(t *testing.T) { +func TestTxSelectorBatchBuilderZKInputsMinimumFlow0(t *testing.T) { tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx) // generate test transactions, the L1CoordinatorTxs generated by Til // will be ignored at this test, as will be the TxSelector who @@ -253,3 +253,88 @@ func TestTxSelectorBatchBuilderZKInputs(t *testing.T) { err = l2DBTxSel.UpdateTxsInfo(discardedL2Txs) require.NoError(t, err) } + +// TestZKInputsExitWithFee0 checks the case where there is a PoolTxs of type +// Exit with fee 0 for a TokenID that the Coordinator does not have it +// registered yet +func TestZKInputsExitWithFee0(t *testing.T) { + tc := til.NewContext(ChainID, common.RollupConstMaxL1UserTx) + + var set = ` + Type: Blockchain + AddToken(1) + + CreateAccountDeposit(1) A: 1000 + CreateAccountDeposit(1) B: 1000 + CreateAccountDeposit(1) C: 1000 + > batchL1 + > batchL1 + + CreateAccountCoordinator(1) Coord + > batch + > block + ` + blocks, err := tc.GenerateBlocks(set) + require.NoError(t, err) + + hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6") + txsel, l2DBTxSel, syncStateDB := initTxSelector(t, ChainID, hermezContractAddr, tc.Users["Coord"]) + + bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB") + require.NoError(t, err) + bb, err := batchbuilder.NewBatchBuilder(bbDir, syncStateDB, 0, NLevels) + require.NoError(t, err) + + // restart nonces of TilContext, as will be set by generating directly + // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs + tc.RestartNonces() + // add tokens to HistoryDB to avoid breaking FK constrains + addTokens(t, tc, l2DBTxSel.DB()) + + selectionConfig := &txselector.SelectionConfig{ + MaxL1UserTxs: 100, + TxProcessorConfig: txprocConfig, + } + configBatch := &batchbuilder.ConfigBatch{ + TxProcessorConfig: txprocConfig, + } + + // batch2 + // TxSelector select the transactions for the next Batch + l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum]) + coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err := txsel.GetL1L2TxSelection(selectionConfig, l1UserTxs) + require.NoError(t, err) + // BatchBuilder build Batch + zki, err := bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs) + require.NoError(t, err) + assert.Equal(t, "8737171572459172806192626402462788826264011087579491137542380589998149683116", bb.LocalStateDB().MT.Root().BigInt().String()) + h, err := zki.HashGlobalData() + require.NoError(t, err) + assert.Equal(t, "9971598169768987067017223790214537222850903267980994716992761290793474746117", h.String()) + sendProofAndCheckResp(t, zki) + + // batch3 + batchPoolL2 := ` + Type: PoolL2 + PoolExit(1) A: 100 (0)` + l2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2) + require.NoError(t, err) + addL2Txs(t, l2DBTxSel, l2Txs) // Add L2s to TxSelector.L2DB + coordIdxs, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err := txsel.GetL1L2TxSelection(selectionConfig, nil) + require.NoError(t, err) + assert.Equal(t, 1, len(coordIdxs)) + assert.Equal(t, 0, len(oL1UserTxs)) + assert.Equal(t, 1, len(oL1CoordTxs)) + assert.Equal(t, 1, len(oL2Txs)) + assert.Equal(t, 0, len(discardedL2Txs)) + // BatchBuilder build Batch + zki, err = bb.BuildBatch(coordIdxs, configBatch, oL1UserTxs, oL1CoordTxs, oL2Txs) + require.NoError(t, err) + assert.Equal(t, "18306761925365215381387147754881756804475668085493847010988306480531520370130", bb.LocalStateDB().MT.Root().BigInt().String()) + h, err = zki.HashGlobalData() + require.NoError(t, err) + assert.Equal(t, "7992262236065691439683036344554725221924027193771770363772735722054938818364", h.String()) + assert.Equal(t, common.EthAddrToBigInt(tc.Users["Coord"].Addr), zki.EthAddr3[0]) + assert.Equal(t, "0", zki.EthAddr3[1].String()) + sendProofAndCheckResp(t, zki) +} diff --git a/txprocessor/txprocessor.go b/txprocessor/txprocessor.go index 51337dc..beaa474 100644 --- a/txprocessor/txprocessor.go +++ b/txprocessor/txprocessor.go @@ -360,35 +360,34 @@ func (tp *TxProcessor) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinat for _, idx := range coordIdxs { accumulatedFee := tp.AccumulatedFees[idx] - cmp := accumulatedFee.Cmp(big.NewInt(0)) - if cmp == 1 { // accumulatedFee>0 - // send the fee to the Idx of the Coordinator for the TokenID - accCoord, err := tp.s.GetAccount(idx) - if err != nil { - log.Errorw("Can not distribute accumulated fees to coordinator account: No coord Idx to receive fee", "idx", idx) - return nil, tracerr.Wrap(err) - } - if tp.zki != nil { - tp.zki.TokenID3[iFee] = accCoord.TokenID.BigInt() - tp.zki.Nonce3[iFee] = accCoord.Nonce.BigInt() - coordBJJSign, coordBJJY := babyjub.UnpackSignY(accCoord.BJJ) - if coordBJJSign { - tp.zki.Sign3[iFee] = big.NewInt(1) - } - tp.zki.Ay3[iFee] = coordBJJY - tp.zki.Balance3[iFee] = accCoord.Balance - tp.zki.EthAddr3[iFee] = common.EthAddrToBigInt(accCoord.EthAddr) - } - accCoord.Balance = new(big.Int).Add(accCoord.Balance, accumulatedFee) - pFee, err := tp.s.UpdateAccount(idx, accCoord) - if err != nil { - log.Error(err) - return nil, tracerr.Wrap(err) - } - if tp.zki != nil { - tp.zki.Siblings3[iFee] = siblingsToZKInputFormat(pFee.Siblings) - tp.zki.ISStateRootFee[iFee] = tp.s.MT.Root().BigInt() + // send the fee to the Idx of the Coordinator for the TokenID + // (even if the AccumulatedFee==0, as is how the zk circuit + // works) + accCoord, err := tp.s.GetAccount(idx) + if err != nil { + log.Errorw("Can not distribute accumulated fees to coordinator account: No coord Idx to receive fee", "idx", idx) + return nil, tracerr.Wrap(err) + } + if tp.zki != nil { + tp.zki.TokenID3[iFee] = accCoord.TokenID.BigInt() + tp.zki.Nonce3[iFee] = accCoord.Nonce.BigInt() + coordBJJSign, coordBJJY := babyjub.UnpackSignY(accCoord.BJJ) + if coordBJJSign { + tp.zki.Sign3[iFee] = big.NewInt(1) } + tp.zki.Ay3[iFee] = coordBJJY + tp.zki.Balance3[iFee] = accCoord.Balance + tp.zki.EthAddr3[iFee] = common.EthAddrToBigInt(accCoord.EthAddr) + } + accCoord.Balance = new(big.Int).Add(accCoord.Balance, accumulatedFee) + pFee, err := tp.s.UpdateAccount(idx, accCoord) + if err != nil { + log.Error(err) + return nil, tracerr.Wrap(err) + } + if tp.zki != nil { + tp.zki.Siblings3[iFee] = siblingsToZKInputFormat(pFee.Siblings) + tp.zki.ISStateRootFee[iFee] = tp.s.MT.Root().BigInt() } iFee++ }