arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
Merge pull request #228 from hermeznetwork/feature/fees-to-coord

Add ProcessTxs send fees to Coordinator accounts
Eduard S eduard@iden3.io
Tue, 27 Oct 2020 10:32:26 +0100
commit

23160ce4eb4214f7518a54cb08d5909d214d8e58

parent

382bcfeee1daab3cc36eee2f2323af2921a3f834

M batchbuilder/batchbuilder.go → batchbuilder/batchbuilder.go

@@ -51,8 +51,8 @@ return bb.localStateDB.Reset(batchNum, fromSynchronizer)

} // 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 }
M common/l1tx.go → common/l1tx.go

@@ -60,7 +60,7 @@ } else if l1Tx.FromIdx >= IdxUserThreshold {

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
M common/pooll2tx.go → common/pooll2tx.go

@@ -250,6 +250,7 @@ TxID: tx.TxID,

FromIdx: tx.FromIdx, ToIdx: tx.ToIdx, Amount: tx.Amount, + TokenID: tx.TokenID, Nonce: &tx.Nonce, Fee: &tx.Fee, Type: tx.Type,
M common/tx.go → common/tx.go

@@ -1,6 +1,7 @@

package common import ( + "bytes" "database/sql/driver" "encoding/hex" "errors"

@@ -143,6 +144,33 @@ // L2

Fee *FeeSelector `meddler:"fee"` FeeUSD *float64 `meddler:"fee_usd"` 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
M coordinator/coordinator.go → coordinator/coordinator.go

@@ -213,14 +213,14 @@ // 1. Decide if we forge L2Tx or L1+L2Tx

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 @@ // 4. Call BatchBuilder with TxSelector output

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 }
M db/statedb/txprocessors.go → db/statedb/txprocessors.go

@@ -38,7 +38,7 @@ // SnarkProof later used by the BatchBuilder. If StateDB

// 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

@@ -53,6 +53,12 @@ // TODO return ZKInputs of batch without txs

return nil, nil, nil } 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

@@ -121,7 +127,7 @@ s.i++

} } 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 @@ s.zki.ISOnChain[s.i] = big.NewInt(1)

} 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 @@ if s.zki != nil {

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 @@ // processL2Tx process the given L2Tx applying the needed updates to the

// 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 @@ switch tx.Type {

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 @@ // Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if

// 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 @@ // compute fee and subtract it from the accSender

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 @@ }

// 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 @@ // compute fee and subtract it from the accSender

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)
M db/statedb/txprocessors_test.go → db/statedb/txprocessors_test.go

@@ -7,6 +7,7 @@ "testing"

"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 @@ tc := til.NewContext(eth.RollupConstMaxL1UserTx)

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 @@ assert.Equal(t, 9, len(blocks[0].Batches[2].L1UserTxs))

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 @@ assert.Equal(t, 0, len(blocks[0].Batches[0].L1CoordinatorTxs))

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)
M db/statedb/utils.go → db/statedb/utils.go

@@ -2,6 +2,7 @@ package statedb

import ( "bytes" + "fmt" "math/big" ethCommon "github.com/ethereum/go-ethereum/common"

@@ -106,6 +107,18 @@ return idx, nil

} // rest of cases (included case ToEthAddr==0) are not possible 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 {
M synchronizer/synchronizer.go → synchronizer/synchronizer.go

@@ -405,7 +405,7 @@ // TODO: Get createdAccounts from ProcessTxs()

// 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 }
M synchronizer/synchronizer_test.go → synchronizer/synchronizer_test.go

@@ -103,7 +103,7 @@ CreateAccountDeposit(1) B: 5 // Idx=256+3

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}
M test/til/README.md → 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
M test/til/lang.go → test/til/lang.go

@@ -350,7 +350,7 @@ c.typ = common.TxTypeCreateAccountDeposit

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":
M test/til/lang_test.go → test/til/lang_test.go

@@ -25,7 +25,7 @@ Deposit(2) A: 20

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)
M test/til/sets.go → 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
M test/til/txs.go → test/til/txs.go

@@ -219,6 +219,26 @@ tokenID: inst.tokenID,

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 @@ ToIdx: common.Idx(1), // as is an Exit

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 @@ "while account not created yet", tx.lineNum, tx.toIdxName, tx.L1Tx.TokenID)

} 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)
M test/til/txs_test.go → test/til/txs_test.go

@@ -54,8 +54,8 @@ Transfer(1) A-D: 1 (1)

// 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 @@ Transfer(1) A-E: 1 (1)

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 @@ Type: Blockchain

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 @@ Type: Blockchain

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
M txselector/txselector.go → txselector/txselector.go

@@ -68,7 +68,7 @@ return nil

} // 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 @@ // get most profitable L2-tx

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 @@ return txs, err

} // 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 @@ maxL2Txs := txsel.MaxTxs - uint64(len(l1CoordinatorTxs)) // - len(l1UserTxs)

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 }