From 8f24aa93c9e805cb6db2803637a96da62a2c5f19 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 26 Oct 2020 17:35:23 +0100 Subject: [PATCH] Add ProcessTxs send fees to Coordinator accounts --- batchbuilder/batchbuilder.go | 4 +- common/l1tx.go | 2 +- common/pooll2tx.go | 1 + common/tx.go | 28 ++++++++++++ coordinator/coordinator.go | 8 ++-- db/statedb/txprocessors.go | 61 +++++++++++++++++++------- db/statedb/txprocessors_test.go | 73 +++++++++++++++++++++---------- db/statedb/utils.go | 13 ++++++ synchronizer/synchronizer.go | 2 +- synchronizer/synchronizer_test.go | 2 +- test/til/README.md | 2 +- test/til/lang.go | 2 +- test/til/lang_test.go | 2 +- test/til/sets.go | 16 ++++++- test/til/txs.go | 24 +++++++++- test/til/txs_test.go | 12 ++--- txselector/txselector.go | 8 ++-- 17 files changed, 195 insertions(+), 65 deletions(-) diff --git a/batchbuilder/batchbuilder.go b/batchbuilder/batchbuilder.go index 5e9aa32..d54db54 100644 --- a/batchbuilder/batchbuilder.go +++ b/batchbuilder/batchbuilder.go @@ -51,8 +51,8 @@ func (bb *BatchBuilder) Reset(batchNum common.BatchNum, fromSynchronizer bool) e } // BuildBatch takes the transactions and returns the common.ZKInputs of the next batch -func (bb *BatchBuilder) BuildBatch(configBatch *ConfigBatch, l1usertxs, l1coordinatortxs []common.L1Tx, pooll2txs []common.PoolL2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) { - zkInputs, _, err := bb.localStateDB.ProcessTxs(l1usertxs, l1coordinatortxs, pooll2txs) +func (bb *BatchBuilder) BuildBatch(coordIdxs []common.Idx, configBatch *ConfigBatch, l1usertxs, l1coordinatortxs []common.L1Tx, pooll2txs []common.PoolL2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) { + zkInputs, _, err := bb.localStateDB.ProcessTxs(coordIdxs, l1usertxs, l1coordinatortxs, pooll2txs) if err != nil { return nil, err } diff --git a/common/l1tx.go b/common/l1tx.go index 7a75564..a690357 100644 --- a/common/l1tx.go +++ b/common/l1tx.go @@ -60,7 +60,7 @@ func NewL1Tx(l1Tx *L1Tx) (*L1Tx, error) { if l1Tx.ToIdx == Idx(0) { txType = TxTypeDeposit } else if l1Tx.ToIdx == Idx(1) { - txType = TxTypeExit + txType = TxTypeForceExit } else if l1Tx.ToIdx >= IdxUserThreshold { if l1Tx.LoadAmount.Int64() == int64(0) { txType = TxTypeForceTransfer diff --git a/common/pooll2tx.go b/common/pooll2tx.go index d6a5cd9..377a214 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -250,6 +250,7 @@ func (tx PoolL2Tx) Tx() Tx { FromIdx: tx.FromIdx, ToIdx: tx.ToIdx, Amount: tx.Amount, + TokenID: tx.TokenID, Nonce: &tx.Nonce, Fee: &tx.Fee, Type: tx.Type, diff --git a/common/tx.go b/common/tx.go index f035d10..8e5cba5 100644 --- a/common/tx.go +++ b/common/tx.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "database/sql/driver" "encoding/hex" "errors" @@ -145,6 +146,33 @@ type Tx struct { Nonce *Nonce `meddler:"nonce"` } +func (tx *Tx) String() string { + buf := bytes.NewBufferString("") + fmt.Fprintf(buf, "Type: %s, ", tx.Type) + fmt.Fprintf(buf, "FromIdx: %s, ", tx.FromIdx) + if tx.Type == TxTypeTransfer || + tx.Type == TxTypeDepositTransfer || + tx.Type == TxTypeCreateAccountDepositTransfer { + fmt.Fprintf(buf, "ToIdx: %s, ", tx.ToIdx) + } + if tx.Type == TxTypeDeposit || + tx.Type == TxTypeDepositTransfer || + tx.Type == TxTypeCreateAccountDepositTransfer { + fmt.Fprintf(buf, "LoadAmount: %d, ", tx.LoadAmount) + } + if tx.Type != TxTypeDeposit { + fmt.Fprintf(buf, "Amount: %s, ", tx.Amount) + } + if tx.Type == TxTypeTransfer || + tx.Type == TxTypeDepositTransfer || + tx.Type == TxTypeCreateAccountDepositTransfer { + fmt.Fprintf(buf, "Fee: %d, ", tx.Fee) + } + fmt.Fprintf(buf, "TokenID: %d\n", tx.TokenID) + + return buf.String() +} + // L1Tx returns a *L1Tx from the Tx func (tx *Tx) L1Tx() (*L1Tx, error) { return &L1Tx{ diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 8dc607e..0bf2c9f 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -213,14 +213,14 @@ func (c *Coordinator) forge(serverProof ServerProofInterface) (*BatchInfo, error if c.shouldL1L2Batch() { // 2a: L1+L2 txs // l1UserTxs, toForgeL1TxsNumber := c.hdb.GetNextL1UserTxs() // TODO once HistoryDB is ready, uncomment - var l1UserTxs []common.L1Tx = nil // tmp, depends on HistoryDB - l1UserTxsExtra, l1OperatorTxs, poolL2Txs, err = c.txsel.GetL1L2TxSelection(c.batchNum, l1UserTxs) // TODO once feesInfo is added to method return, add the var + var l1UserTxs []common.L1Tx = nil // tmp, depends on HistoryDB + l1UserTxsExtra, l1OperatorTxs, poolL2Txs, err = c.txsel.GetL1L2TxSelection([]common.Idx{}, c.batchNum, l1UserTxs) // TODO once feesInfo is added to method return, add the var if err != nil { return nil, err } } else { // 2b: only L2 txs - poolL2Txs, err = c.txsel.GetL2TxSelection(c.batchNum) // TODO once feesInfo is added to method return, add the var + poolL2Txs, err = c.txsel.GetL2TxSelection([]common.Idx{}, c.batchNum) // TODO once feesInfo is added to method return, add the var if err != nil { return nil, err } @@ -244,7 +244,7 @@ func (c *Coordinator) forge(serverProof ServerProofInterface) (*BatchInfo, error configBatch := &batchbuilder.ConfigBatch{ ForgerAddress: c.config.ForgerAddress, } - zkInputs, err := c.batchBuilder.BuildBatch(configBatch, l1UserTxsExtra, l1OperatorTxs, poolL2Txs, nil) // TODO []common.TokenID --> feesInfo + zkInputs, err := c.batchBuilder.BuildBatch([]common.Idx{}, configBatch, l1UserTxsExtra, l1OperatorTxs, poolL2Txs, nil) // TODO []common.TokenID --> feesInfo if err != nil { return nil, err } diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index d6c8368..6565ed3 100644 --- a/db/statedb/txprocessors.go +++ b/db/statedb/txprocessors.go @@ -38,7 +38,7 @@ type processedExit struct { // type==TypeSynchronizer, assumes that the call is done from the Synchronizer, // returns common.ExitTreeLeaf that is later used by the Synchronizer to update // the HistoryDB, and adds Nonce & TokenID to the L2Txs. -func (s *StateDB) ProcessTxs(l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (*common.ZKInputs, []common.ExitInfo, error) { +func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (*common.ZKInputs, []common.ExitInfo, error) { var err error var exitTree *merkletree.MerkleTree @@ -54,6 +54,12 @@ func (s *StateDB) ProcessTxs(l1usertxs, l1coordinatortxs []common.L1Tx, l2txs [] } exits := make([]processedExit, nTx) + // get TokenIDs of coordIdxs + coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs) + if err != nil { + return nil, nil, err + } + if s.typ == TypeBatchBuilder { s.zki = common.NewZKInputs(nTx, 24, 32) // TODO this values will be parameters of the function, taken from config file/coordinator call s.zki.OldLastIdx = (s.idx - 1).BigInt() @@ -121,7 +127,7 @@ func (s *StateDB) ProcessTxs(l1usertxs, l1coordinatortxs []common.L1Tx, l2txs [] } } for i := 0; i < len(l2txs); i++ { - exitIdx, exitAccount, newExit, err := s.processL2Tx(exitTree, &l2txs[i]) + exitIdx, exitAccount, newExit, err := s.processL2Tx(coordIdxsMap, exitTree, &l2txs[i]) if err != nil { return nil, nil, err } @@ -258,10 +264,13 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) } switch tx.Type { - case common.TxTypeForceTransfer, common.TxTypeTransfer: + case common.TxTypeForceTransfer: // go to the MT account of sender and receiver, and update balance // & nonce - err := s.applyTransfer(tx.Tx(), 0) // 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in the Deposit type case. + + // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees + // 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in the Deposit type case. + err := s.applyTransfer(nil, tx.Tx(), 0) if err != nil { log.Error(err) return nil, nil, false, err @@ -309,9 +318,10 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account s.zki.NewAccount[s.i] = big.NewInt(1) } - case common.TxTypeExit: + case common.TxTypeForceExit: // execute exit flow - exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx()) + // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees + exitAccount, newExit, err := s.applyExit(nil, exitTree, tx.Tx()) if err != nil { log.Error(err) return nil, nil, false, err @@ -327,7 +337,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) // StateDB depending on the transaction Type. It returns the 3 parameters // related to the Exit (in case of): Idx, ExitAccount, boolean determining if // the Exit created a new Leaf in the ExitTree. -func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) { +func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) { var err error // if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) { @@ -394,14 +404,14 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2 case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ: // go to the MT account of sender and receiver, and update // balance & nonce - err = s.applyTransfer(tx.Tx(), tx.AuxToIdx) + err = s.applyTransfer(coordIdxsMap, tx.Tx(), tx.AuxToIdx) if err != nil { log.Error(err) return nil, nil, false, err } case common.TxTypeExit: // execute exit flow - exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx()) + exitAccount, newExit, err := s.applyExit(coordIdxsMap, exitTree, tx.Tx()) if err != nil { log.Error(err) return nil, nil, false, err @@ -519,7 +529,7 @@ func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error { // tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of // the receiver. This parameter is used when the tx.ToIdx is not specified and // the real ToIdx is found trhrough the ToEthAddr or ToBJJ. -func (s *StateDB) applyTransfer(tx common.Tx, auxToIdx common.Idx) error { +func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, tx common.Tx, auxToIdx common.Idx) error { if auxToIdx == common.Idx(0) { auxToIdx = tx.ToIdx } @@ -543,8 +553,18 @@ func (s *StateDB) applyTransfer(tx common.Tx, auxToIdx common.Idx) error { fee := common.CalcFeeAmount(tx.Amount, *tx.Fee) feeAndAmount := new(big.Int).Add(tx.Amount, fee) accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount) - // TODO send the fee to the Fee Idx of the Coordinator for the - // TokenID + // send the fee to the Idx of the Coordinator for the TokenID + accCoord, err := s.GetAccount(coordIdxsMap[tx.TokenID]) + if err != nil { + log.Errorf("applyTransfer error: Tx=%s, error: %s", tx.String(), err) + return err + } + accCoord.Balance = new(big.Int).Add(accCoord.Balance, fee) + _, err = s.UpdateAccount(coordIdxsMap[tx.TokenID], accCoord) + if err != nil { + log.Error(err) + return err + } } // add amount-feeAmount to the receiver @@ -653,7 +673,7 @@ func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error { // It returns the ExitAccount and a boolean determining if the Exit created a // new Leaf in the ExitTree. -func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx common.Tx) (*common.Account, bool, error) { +func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, exitTree *merkletree.MerkleTree, tx common.Tx) (*common.Account, bool, error) { // 0. subtract tx.Amount from current Account in StateMT // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT acc, err := s.GetAccount(tx.FromIdx) @@ -666,8 +686,19 @@ func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx common.Tx) (*com fee := common.CalcFeeAmount(tx.Amount, *tx.Fee) feeAndAmount := new(big.Int).Add(tx.Amount, fee) acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount) - // TODO send the fee to the Fee Idx of the Coordinator for the - // TokenID + + // send the fee to the Idx of the Coordinator for the TokenID + accCoord, err := s.GetAccount(coordIdxsMap[tx.TokenID]) + if err != nil { + log.Errorf("applyExit error: Tx=%s, error: %s", tx.String(), err) + return nil, false, err + } + accCoord.Balance = new(big.Int).Add(accCoord.Balance, fee) + _, err = s.UpdateAccount(coordIdxsMap[tx.TokenID], accCoord) + if err != nil { + log.Error(err) + return nil, false, err + } } p, err := s.UpdateAccount(tx.FromIdx, acc) diff --git a/db/statedb/txprocessors_test.go b/db/statedb/txprocessors_test.go index f657e16..93474f3 100644 --- a/db/statedb/txprocessors_test.go +++ b/db/statedb/txprocessors_test.go @@ -7,6 +7,7 @@ import ( "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/eth" + "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/test/til" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -28,53 +29,74 @@ func TestProcessTxsSynchronizer(t *testing.T) { blocks, err := tc.GenerateBlocks(til.SetBlockchain0) require.Nil(t, err) - assert.Equal(t, 29, len(blocks[0].L1UserTxs)) - assert.Equal(t, 0, len(blocks[0].Batches[0].L1CoordinatorTxs)) - assert.Equal(t, 21, len(blocks[0].Batches[1].L2Txs)) + assert.Equal(t, 31, len(blocks[0].L1UserTxs)) + assert.Equal(t, 4, len(blocks[0].Batches[0].L1CoordinatorTxs)) + assert.Equal(t, 0, len(blocks[0].Batches[1].L1CoordinatorTxs)) + assert.Equal(t, 22, len(blocks[0].Batches[2].L2Txs)) assert.Equal(t, 1, len(blocks[1].Batches[0].L1CoordinatorTxs)) assert.Equal(t, 59, len(blocks[1].Batches[0].L2Txs)) assert.Equal(t, 1, len(blocks[1].Batches[1].L1CoordinatorTxs)) assert.Equal(t, 8, len(blocks[1].Batches[1].L2Txs)) - // use first batch - l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs) - _, exitInfos, err := sdb.ProcessTxs(blocks[0].L1UserTxs, blocks[0].Batches[0].L1CoordinatorTxs, l2Txs) + // Coordinator Idx where to send the fees + coordIdxs := []common.Idx{256, 257, 258, 259} + + // Idx of user 'A' + idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx + + log.Debug("1st batch, 1st block, only L1CoordinatorTxs") + _, _, err = sdb.ProcessTxs(nil, nil, blocks[0].Batches[0].L1CoordinatorTxs, nil) + require.Nil(t, err) + + log.Debug("2nd batch, 1st block") + l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[1].L2Txs) + _, exitInfos, err := sdb.ProcessTxs(coordIdxs, blocks[0].L1UserTxs, blocks[0].Batches[1].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 0, len(exitInfos)) - acc, err := sdb.GetAccount(common.Idx(256)) + acc, err := sdb.GetAccount(idxA1) require.Nil(t, err) assert.Equal(t, "50", acc.Balance.String()) - // second batch of first block - l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[1].L2Txs) - _, exitInfos, err = sdb.ProcessTxs(nil, blocks[0].Batches[1].L1CoordinatorTxs, l2Txs) + log.Debug("3rd batch, 1st block") + l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[2].L2Txs) + _, exitInfos, err = sdb.ProcessTxs(coordIdxs, nil, blocks[0].Batches[2].L1CoordinatorTxs, l2Txs) require.Nil(t, err) // TODO once TTGL is updated, add a check that a input poolL2Tx with // Nonce & TokenID =0, after ProcessTxs call has the expected value assert.Equal(t, 0, len(exitInfos)) - acc, err = sdb.GetAccount(common.Idx(256)) + acc, err = sdb.GetAccount(idxA1) require.Nil(t, err) assert.Equal(t, "28", acc.Balance.String()) - // use second batch + log.Debug("1st batch, 2nd block") l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[0].L2Txs) - _, exitInfos, err = sdb.ProcessTxs(nil, blocks[1].Batches[0].L1CoordinatorTxs, l2Txs) + _, exitInfos, err = sdb.ProcessTxs(coordIdxs, nil, blocks[1].Batches[0].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 4, len(exitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs - acc, err = sdb.GetAccount(common.Idx(256)) + acc, err = sdb.GetAccount(idxA1) require.Nil(t, err) assert.Equal(t, "53", acc.Balance.String()) - // use third batch + log.Debug("2nd batch, 2nd block") l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[1].L2Txs) - _, exitInfos, err = sdb.ProcessTxs(blocks[1].L1UserTxs, blocks[1].Batches[1].L1CoordinatorTxs, l2Txs) + _, exitInfos, err = sdb.ProcessTxs(coordIdxs, blocks[1].L1UserTxs, blocks[1].Batches[1].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 2, len(exitInfos)) // 2, as previous batch was without L1UserTxs, and has pending the 'ForceExit(1) A: 5' - acc, err = sdb.GetAccount(common.Idx(256)) + acc, err = sdb.GetAccount(idxA1) assert.Nil(t, err) assert.Equal(t, "78", acc.Balance.String()) + + idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx + acc, err = sdb.GetAccount(idxB0) + require.Nil(t, err) + assert.Equal(t, "51", acc.Balance.String()) + + // get balance of Coordinator account for TokenID==0 + acc, err = sdb.GetAccount(common.Idx(256)) + require.Nil(t, err) + assert.Equal(t, "2", acc.Balance.String()) } /* @@ -102,30 +124,33 @@ func TestProcessTxsBatchBuilder(t *testing.T) { assert.Equal(t, 0, len(blocks[0].Batches[2].L1CoordinatorTxs)) assert.Equal(t, 8, len(blocks[0].Batches[2].L2Txs)) + // Idx of user 'A' + idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx + // use first batch l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs) - _, exitInfos, err := sdb.ProcessTxs(blocks[0].Batches[0].L1UserTxs, blocks[0].Batches[0].L1CoordinatorTxs, l2Txs) + _, exitInfos, err := sdb.ProcessTxs(coordIdxs, blocks[0].Batches[0].L1UserTxs, blocks[0].Batches[0].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 0, len(exitInfos)) - acc, err := sdb.GetAccount(common.Idx(256)) + acc, err := sdb.GetAccount(idxA1) assert.Nil(t, err) assert.Equal(t, "28", acc.Balance.String()) // use second batch l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[1].L2Txs) - _, exitInfos, err = sdb.ProcessTxs(blocks[0].Batches[1].L1UserTxs, blocks[0].Batches[1].L1CoordinatorTxs, l2Txs) + _, exitInfos, err = sdb.ProcessTxs(coordIdxs, blocks[0].Batches[1].L1UserTxs, blocks[0].Batches[1].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 5, len(exitInfos)) - acc, err = sdb.GetAccount(common.Idx(256)) + acc, err = sdb.GetAccount(idxA1) require.Nil(t, err) assert.Equal(t, "48", acc.Balance.String()) // use third batch l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[2].L2Txs) - _, exitInfos, err = sdb.ProcessTxs(blocks[0].Batches[2].L1UserTxs, blocks[0].Batches[2].L1CoordinatorTxs, l2Txs) + _, exitInfos, err = sdb.ProcessTxs(coordIdxs, blocks[0].Batches[2].L1UserTxs, blocks[0].Batches[2].L1CoordinatorTxs, l2Txs) require.Nil(t, err) assert.Equal(t, 1, len(exitInfos)) - acc, err = sdb.GetAccount(common.Idx(256)) + acc, err = sdb.GetAccount(idxA1) assert.Nil(t, err) assert.Equal(t, "23", acc.Balance.String()) } @@ -146,7 +171,7 @@ func TestZKInputsGeneration(t *testing.T) { assert.Equal(t, 21, len(blocks[0].Batches[0].L2Txs)) l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs) - zki, _, err := sdb.ProcessTxs(blocks[0].Batches[0].L1UserTxs, blocks[0].Batches[0].L1CoordinatorTxs, l2Txs) + zki, _, err := sdb.ProcessTxs(coordIdxs, blocks[0].Batches[0].L1UserTxs, blocks[0].Batches[0].L1CoordinatorTxs, l2Txs) require.Nil(t, err) s, err := json.Marshal(zki) diff --git a/db/statedb/utils.go b/db/statedb/utils.go index cce91eb..95bdddf 100644 --- a/db/statedb/utils.go +++ b/db/statedb/utils.go @@ -2,6 +2,7 @@ package statedb import ( "bytes" + "fmt" "math/big" ethCommon "github.com/ethereum/go-ethereum/common" @@ -108,6 +109,18 @@ func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicK return common.Idx(0), ErrToIdxNotFound } +func (s *StateDB) getTokenIDsFromIdxs(idxs []common.Idx) (map[common.TokenID]common.Idx, error) { + m := make(map[common.TokenID]common.Idx) + for i := 0; i < len(idxs); i++ { + a, err := s.GetAccount(idxs[i]) + if err != nil { + return nil, fmt.Errorf("getTokenIDsFromIdxs error on GetAccount with Idx==%d: %s", idxs[i], err.Error()) + } + m[a.TokenID] = idxs[i] + } + return m, nil +} + func siblingsToZKInputFormat(s []*merkletree.Hash) []*big.Int { b := make([]*big.Int, len(s)) for i := 0; i < len(s); i++ { diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index f24d598..3cb3532 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -405,7 +405,7 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*rollupData, error) { // TODO: Get CollectedFees from ProcessTxs() // TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs() // ProcessTxs updates poolL2Txs adding: Nonce, TokenID - _, exitInfo, err := s.stateDB.ProcessTxs(l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs) + _, exitInfo, err := s.stateDB.ProcessTxs([]common.Idx{}, l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs) if err != nil { return nil, err } diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 7d962f8..7b73a9b 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -103,7 +103,7 @@ func TestSync(t *testing.T) { CreateAccountDeposit(1) C: 5 // Idx=256+4 CreateAccountDeposit(1) D: 5 // Idx=256+5 - CreateAccountDepositCoordinator(2) B // Idx=256+0 + CreateAccountCoordinator(2) B // Idx=256+0 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs > batchL1 // forge defined L1UserTxs, freeze L1UserTxs{nil} diff --git a/test/til/README.md b/test/til/README.md index 2f2293a..c0ae10d 100644 --- a/test/til/README.md +++ b/test/til/README.md @@ -32,7 +32,7 @@ CreateAccountDepositTransfer(1) B-A: 40, 10 // transaction generated by the Coordinator, create account for user User0 for // the TokenID=2, with a deposit of 0 -CreateAccountDepositCoordinator(2) User0 +CreateAccountCoordinator(2) User0 // deposit of TokenID=1, at the account A, of 6 units diff --git a/test/til/lang.go b/test/til/lang.go index 31b80d5..b96ccc0 100644 --- a/test/til/lang.go +++ b/test/til/lang.go @@ -350,7 +350,7 @@ func (p *parser) parseLine(setType setType) (*instruction, error) { case "CreateAccountDepositTransfer": c.typ = common.TxTypeCreateAccountDepositTransfer transferring = true - case "CreateAccountDepositCoordinator": + case "CreateAccountCoordinator": c.typ = txTypeCreateAccountDepositCoordinator // transferring is false, as the Coordinator tx transfer will be 0 case "DepositTransfer": diff --git a/test/til/lang_test.go b/test/til/lang_test.go index 6d9a987..893e4f0 100644 --- a/test/til/lang_test.go +++ b/test/til/lang_test.go @@ -25,7 +25,7 @@ func TestParseBlockchainTxs(t *testing.T) { Deposit(1) B: 5 CreateAccountDeposit(1) C: 5 CreateAccountDepositTransfer(1) D-A: 15, 10 - CreateAccountDepositCoordinator(1) E + CreateAccountCoordinator(1) E // L2 transactions Transfer(1) A-B: 6 (1) diff --git a/test/til/sets.go b/test/til/sets.go index 9a795a8..0c1107b 100644 --- a/test/til/sets.go +++ b/test/til/sets.go @@ -10,6 +10,14 @@ AddToken(1) AddToken(2) AddToken(3) +// Coordinator accounts, Idxs: 256, 257, 258, 259 +CreateAccountCoordinator(0) Coord +CreateAccountCoordinator(1) Coord +CreateAccountCoordinator(2) Coord +CreateAccountCoordinator(3) Coord + +> batch + // deposits TokenID: 1 CreateAccountDeposit(1) A: 50 CreateAccountDeposit(1) B: 5 @@ -42,6 +50,9 @@ CreateAccountDeposit(2) B: 5 CreateAccountDeposit(2) A: 20 // deposits TokenID: 3 CreateAccountDeposit(3) B: 100 +// deposits TokenID: 0 +CreateAccountDeposit(0) B: 10000 +CreateAccountDeposit(0) C: 1 > batchL1 @@ -67,11 +78,12 @@ Transfer(1) G-K: 3 (1) Transfer(1) H-K: 3 (2) Transfer(1) H-K: 3 (1) Transfer(1) H-K: 3 (1) +Transfer(0) B-C: 50 (192) > batchL1 > block // A (3) still does not exist, coordinator should create new L1Tx to create the account -CreateAccountDepositCoordinator(3) A +CreateAccountCoordinator(3) A Transfer(3) B-A: 5 (1) Transfer(2) A-B: 5 (1) @@ -156,7 +168,7 @@ Transfer(1) I-H: 5 (1) Exit(1) A: 5 (1) // create CoordinatorTx CreateAccount for D, TokenId 2, used at SetPool0 for 'PoolTransfer(2) B-D: 3 (1)' -CreateAccountDepositCoordinator(2) D +CreateAccountCoordinator(2) D > batchL1 > batchL1 diff --git a/test/til/txs.go b/test/til/txs.go index 0ab20c4..1389b98 100644 --- a/test/til/txs.go +++ b/test/til/txs.go @@ -219,6 +219,26 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) { L2Tx: tx, } tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx) + case common.TxTypeForceTransfer: // tx source: L1UserTx + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + log.Error(err) + return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error()) + } + tx := common.L1Tx{ + TokenID: inst.tokenID, + Amount: big.NewInt(int64(inst.amount)), + LoadAmount: big.NewInt(0), + Type: common.TxTypeForceTransfer, + } + testTx := L1Tx{ + lineNum: inst.lineNum, + fromIdxName: inst.from, + toIdxName: inst.to, + L1Tx: tx, + } + if err := tc.addToL1Queue(testTx); err != nil { + return nil, err + } case common.TxTypeExit: // tx source: L2Tx if err := tc.checkIfTokenIsRegistered(inst); err != nil { log.Error(err) @@ -248,7 +268,7 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) { TokenID: inst.tokenID, Amount: big.NewInt(int64(inst.amount)), LoadAmount: big.NewInt(0), - Type: common.TxTypeExit, + Type: common.TxTypeForceExit, } testTx := L1Tx{ lineNum: inst.lineNum, @@ -415,7 +435,7 @@ func (tc *Context) addToL1Queue(tx L1Tx) error { } tx.L1Tx.ToIdx = account.Idx } - if tx.L1Tx.Type == common.TxTypeExit { + if tx.L1Tx.Type == common.TxTypeForceExit { tx.L1Tx.ToIdx = common.Idx(1) } nTx, err := common.NewL1Tx(&tx.L1Tx) diff --git a/test/til/txs_test.go b/test/til/txs_test.go index 3fdf0e0..ed9463d 100644 --- a/test/til/txs_test.go +++ b/test/til/txs_test.go @@ -54,8 +54,8 @@ func TestGenerateBlocks(t *testing.T) { // set new batch > batch // batchNum = 3 - CreateAccountDepositCoordinator(1) E - CreateAccountDepositCoordinator(2) B + CreateAccountCoordinator(1) E + CreateAccountCoordinator(2) B DepositTransfer(1) A-B: 15, 10 Transfer(1) C-A : 3 (1) @@ -64,8 +64,8 @@ func TestGenerateBlocks(t *testing.T) { CreateAccountDeposit(1) User0: 20 CreateAccountDeposit(3) User1: 20 - CreateAccountDepositCoordinator(1) User1 - CreateAccountDepositCoordinator(3) User0 + CreateAccountCoordinator(1) User1 + CreateAccountCoordinator(3) User0 > batchL1 // batchNum = 4 Transfer(1) User0-User1: 15 (1) Transfer(3) User1-User0: 15 (1) @@ -329,7 +329,7 @@ func TestGenerateErrors(t *testing.T) { AddToken(1) CreateAccountDeposit(1) A: 10 > batchL1 - CreateAccountDepositCoordinator(1) B + CreateAccountCoordinator(1) B > batchL1 > batch Transfer(1) A-B: 6 (1) @@ -345,7 +345,7 @@ func TestGenerateErrors(t *testing.T) { AddToken(1) CreateAccountDeposit(1) A: 10 > batchL1 - CreateAccountDepositCoordinator(1) B + CreateAccountCoordinator(1) B > batchL1 Transfer(1) A-B: 6 (1) Transfer(1) A-B: 6 (1) // on purpose this is moving more money that what it has in the account, Til should not fail diff --git a/txselector/txselector.go b/txselector/txselector.go index 0e5dd8c..ced653a 100644 --- a/txselector/txselector.go +++ b/txselector/txselector.go @@ -68,7 +68,7 @@ func (txsel *TxSelector) Reset(batchNum common.BatchNum) error { } // GetL2TxSelection returns a selection of the L2Txs for the next batch, from the L2DB pool -func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]common.PoolL2Tx, error) { +func (txsel *TxSelector) GetL2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum) ([]common.PoolL2Tx, error) { // get pending l2-tx from tx-pool l2TxsRaw, err := txsel.l2db.GetPendingTxs() // once l2db ready, maybe use parameter 'batchNum' if err != nil { @@ -89,7 +89,7 @@ func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]common.Po txs := txsel.getL2Profitable(validTxs, txsel.MaxTxs) // process the txs in the local AccountsDB - _, _, err = txsel.localAccountsDB.ProcessTxs(nil, nil, txs) + _, _, err = txsel.localAccountsDB.ProcessTxs(coordIdxs, nil, nil, txs) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]common.Po } // GetL1L2TxSelection returns the selection of L1 + L2 txs -func (txsel *TxSelector) GetL1L2TxSelection(batchNum common.BatchNum, l1Txs []common.L1Tx) ([]common.L1Tx, []common.L1Tx, []common.PoolL2Tx, error) { +func (txsel *TxSelector) GetL1L2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum, l1Txs []common.L1Tx) ([]common.L1Tx, []common.L1Tx, []common.PoolL2Tx, error) { // apply l1-user-tx to localAccountDB // create new leaves // update balances @@ -238,7 +238,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(batchNum common.BatchNum, l1Txs []co l2Txs := txsel.getL2Profitable(validTxs, maxL2Txs) // process the txs in the local AccountsDB - _, _, err = txsel.localAccountsDB.ProcessTxs(l1Txs, l1CoordinatorTxs, l2Txs) + _, _, err = txsel.localAccountsDB.ProcessTxs(coordIdxs, l1Txs, l1CoordinatorTxs, l2Txs) if err != nil { return nil, nil, nil, err }