Browse Source

Merge pull request #228 from hermeznetwork/feature/fees-to-coord

Add ProcessTxs send fees to Coordinator accounts
feature/sql-semaphore1
Eduard S 3 years ago
committed by GitHub
parent
commit
23160ce4eb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 195 additions and 65 deletions
  1. +2
    -2
      batchbuilder/batchbuilder.go
  2. +1
    -1
      common/l1tx.go
  3. +1
    -0
      common/pooll2tx.go
  4. +28
    -0
      common/tx.go
  5. +4
    -4
      coordinator/coordinator.go
  6. +46
    -15
      db/statedb/txprocessors.go
  7. +49
    -24
      db/statedb/txprocessors_test.go
  8. +13
    -0
      db/statedb/utils.go
  9. +1
    -1
      synchronizer/synchronizer.go
  10. +1
    -1
      synchronizer/synchronizer_test.go
  11. +1
    -1
      test/til/README.md
  12. +1
    -1
      test/til/lang.go
  13. +1
    -1
      test/til/lang_test.go
  14. +14
    -2
      test/til/sets.go
  15. +22
    -2
      test/til/txs.go
  16. +6
    -6
      test/til/txs_test.go
  17. +4
    -4
      txselector/txselector.go

+ 2
- 2
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 // 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 { if err != nil {
return nil, err return nil, err
} }

+ 1
- 1
common/l1tx.go

@ -60,7 +60,7 @@ func NewL1Tx(l1Tx *L1Tx) (*L1Tx, error) {
if l1Tx.ToIdx == Idx(0) { if l1Tx.ToIdx == Idx(0) {
txType = TxTypeDeposit txType = TxTypeDeposit
} else if l1Tx.ToIdx == Idx(1) { } else if l1Tx.ToIdx == Idx(1) {
txType = TxTypeExit
txType = TxTypeForceExit
} else if l1Tx.ToIdx >= IdxUserThreshold { } else if l1Tx.ToIdx >= IdxUserThreshold {
if l1Tx.LoadAmount.Int64() == int64(0) { if l1Tx.LoadAmount.Int64() == int64(0) {
txType = TxTypeForceTransfer txType = TxTypeForceTransfer

+ 1
- 0
common/pooll2tx.go

@ -250,6 +250,7 @@ func (tx PoolL2Tx) Tx() Tx {
FromIdx: tx.FromIdx, FromIdx: tx.FromIdx,
ToIdx: tx.ToIdx, ToIdx: tx.ToIdx,
Amount: tx.Amount, Amount: tx.Amount,
TokenID: tx.TokenID,
Nonce: &tx.Nonce, Nonce: &tx.Nonce,
Fee: &tx.Fee, Fee: &tx.Fee,
Type: tx.Type, Type: tx.Type,

+ 28
- 0
common/tx.go

@ -1,6 +1,7 @@
package common package common
import ( import (
"bytes"
"database/sql/driver" "database/sql/driver"
"encoding/hex" "encoding/hex"
"errors" "errors"
@ -145,6 +146,33 @@ type Tx struct {
Nonce *Nonce `meddler:"nonce"` 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 // L1Tx returns a *L1Tx from the Tx
func (tx *Tx) L1Tx() (*L1Tx, error) { func (tx *Tx) L1Tx() (*L1Tx, error) {
return &L1Tx{ return &L1Tx{

+ 4
- 4
coordinator/coordinator.go

@ -213,14 +213,14 @@ func (c *Coordinator) forge(serverProof ServerProofInterface) (*BatchInfo, error
if c.shouldL1L2Batch() { if c.shouldL1L2Batch() {
// 2a: L1+L2 txs // 2a: L1+L2 txs
// l1UserTxs, toForgeL1TxsNumber := c.hdb.GetNextL1UserTxs() // TODO once HistoryDB is ready, uncomment // 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 { if err != nil {
return nil, err return nil, err
} }
} else { } else {
// 2b: only L2 txs // 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 { if err != nil {
return nil, err return nil, err
} }
@ -244,7 +244,7 @@ func (c *Coordinator) forge(serverProof ServerProofInterface) (*BatchInfo, error
configBatch := &batchbuilder.ConfigBatch{ configBatch := &batchbuilder.ConfigBatch{
ForgerAddress: c.config.ForgerAddress, 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 { if err != nil {
return nil, err return nil, err
} }

+ 46
- 15
db/statedb/txprocessors.go

@ -38,7 +38,7 @@ type processedExit struct {
// type==TypeSynchronizer, assumes that the call is done from the Synchronizer, // type==TypeSynchronizer, assumes that the call is done from the Synchronizer,
// returns common.ExitTreeLeaf that is later used by the Synchronizer to update // returns common.ExitTreeLeaf that is later used by the Synchronizer to update
// the HistoryDB, and adds Nonce & TokenID to the L2Txs. // 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 err error
var exitTree *merkletree.MerkleTree var exitTree *merkletree.MerkleTree
@ -54,6 +54,12 @@ func (s *StateDB) ProcessTxs(l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []
} }
exits := make([]processedExit, nTx) exits := make([]processedExit, nTx)
// get TokenIDs of coordIdxs
coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs)
if err != nil {
return nil, nil, err
}
if s.typ == TypeBatchBuilder { 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 = 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() 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++ { 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -258,10 +264,13 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx)
} }
switch tx.Type { switch tx.Type {
case common.TxTypeForceTransfer, common.TxTypeTransfer:
case common.TxTypeForceTransfer:
// go to the MT account of sender and receiver, and update balance // go to the MT account of sender and receiver, and update balance
// & nonce // & 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 { if err != nil {
log.Error(err) log.Error(err)
return nil, nil, false, 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.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) s.zki.NewAccount[s.i] = big.NewInt(1)
} }
case common.TxTypeExit:
case common.TxTypeForceExit:
// execute exit flow // 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 { if err != nil {
log.Error(err) log.Error(err)
return nil, nil, false, 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 // StateDB depending on the transaction Type. It returns the 3 parameters
// related to the Exit (in case of): Idx, ExitAccount, boolean determining if // related to the Exit (in case of): Idx, ExitAccount, boolean determining if
// the Exit created a new Leaf in the ExitTree. // 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 var err error
// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ // if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) { 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: case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
// go to the MT account of sender and receiver, and update // go to the MT account of sender and receiver, and update
// balance & nonce // balance & nonce
err = s.applyTransfer(tx.Tx(), tx.AuxToIdx)
err = s.applyTransfer(coordIdxsMap, tx.Tx(), tx.AuxToIdx)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return nil, nil, false, err return nil, nil, false, err
} }
case common.TxTypeExit: case common.TxTypeExit:
// execute exit flow // execute exit flow
exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
exitAccount, newExit, err := s.applyExit(coordIdxsMap, exitTree, tx.Tx())
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return nil, nil, false, 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 // 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 receiver. This parameter is used when the tx.ToIdx is not specified and
// the real ToIdx is found trhrough the ToEthAddr or ToBJJ. // 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) { if auxToIdx == common.Idx(0) {
auxToIdx = tx.ToIdx 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) fee := common.CalcFeeAmount(tx.Amount, *tx.Fee)
feeAndAmount := new(big.Int).Add(tx.Amount, fee) feeAndAmount := new(big.Int).Add(tx.Amount, fee)
accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount) 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 // 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 // It returns the ExitAccount and a boolean determining if the Exit created a
// new Leaf in the ExitTree. // 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 // 0. subtract tx.Amount from current Account in StateMT
// add the tx.Amount into the Account (tx.FromIdx) in the ExitMT // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
acc, err := s.GetAccount(tx.FromIdx) 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) fee := common.CalcFeeAmount(tx.Amount, *tx.Fee)
feeAndAmount := new(big.Int).Add(tx.Amount, fee) feeAndAmount := new(big.Int).Add(tx.Amount, fee)
acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount) 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) p, err := s.UpdateAccount(tx.FromIdx, acc)

+ 49
- 24
db/statedb/txprocessors_test.go

@ -7,6 +7,7 @@ import (
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/eth"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/test/til" "github.com/hermeznetwork/hermez-node/test/til"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -28,53 +29,74 @@ func TestProcessTxsSynchronizer(t *testing.T) {
blocks, err := tc.GenerateBlocks(til.SetBlockchain0) blocks, err := tc.GenerateBlocks(til.SetBlockchain0)
require.Nil(t, err) 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, 1, len(blocks[1].Batches[0].L1CoordinatorTxs))
assert.Equal(t, 59, len(blocks[1].Batches[0].L2Txs)) assert.Equal(t, 59, len(blocks[1].Batches[0].L2Txs))
assert.Equal(t, 1, len(blocks[1].Batches[1].L1CoordinatorTxs)) assert.Equal(t, 1, len(blocks[1].Batches[1].L1CoordinatorTxs))
assert.Equal(t, 8, len(blocks[1].Batches[1].L2Txs)) 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) require.Nil(t, err)
assert.Equal(t, 0, len(exitInfos)) assert.Equal(t, 0, len(exitInfos))
acc, err := sdb.GetAccount(common.Idx(256))
acc, err := sdb.GetAccount(idxA1)
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, "50", acc.Balance.String()) 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) require.Nil(t, err)
// TODO once TTGL is updated, add a check that a input poolL2Tx with // TODO once TTGL is updated, add a check that a input poolL2Tx with
// Nonce & TokenID =0, after ProcessTxs call has the expected value // Nonce & TokenID =0, after ProcessTxs call has the expected value
assert.Equal(t, 0, len(exitInfos)) assert.Equal(t, 0, len(exitInfos))
acc, err = sdb.GetAccount(common.Idx(256))
acc, err = sdb.GetAccount(idxA1)
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, "28", acc.Balance.String()) assert.Equal(t, "28", acc.Balance.String())
// use second batch
log.Debug("1st batch, 2nd block")
l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[0].L2Txs) 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) require.Nil(t, err)
assert.Equal(t, 4, len(exitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs 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) require.Nil(t, err)
assert.Equal(t, "53", acc.Balance.String()) assert.Equal(t, "53", acc.Balance.String())
// use third batch
log.Debug("2nd batch, 2nd block")
l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[1].L2Txs) 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) 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' 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.Nil(t, err)
assert.Equal(t, "78", acc.Balance.String()) 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, 0, len(blocks[0].Batches[2].L1CoordinatorTxs))
assert.Equal(t, 8, len(blocks[0].Batches[2].L2Txs)) 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 // use first batch
l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs) 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) require.Nil(t, err)
assert.Equal(t, 0, len(exitInfos)) assert.Equal(t, 0, len(exitInfos))
acc, err := sdb.GetAccount(common.Idx(256))
acc, err := sdb.GetAccount(idxA1)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "28", acc.Balance.String()) assert.Equal(t, "28", acc.Balance.String())
// use second batch // use second batch
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[1].L2Txs) 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) require.Nil(t, err)
assert.Equal(t, 5, len(exitInfos)) assert.Equal(t, 5, len(exitInfos))
acc, err = sdb.GetAccount(common.Idx(256))
acc, err = sdb.GetAccount(idxA1)
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, "48", acc.Balance.String()) assert.Equal(t, "48", acc.Balance.String())
// use third batch // use third batch
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[2].L2Txs) 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) require.Nil(t, err)
assert.Equal(t, 1, len(exitInfos)) assert.Equal(t, 1, len(exitInfos))
acc, err = sdb.GetAccount(common.Idx(256))
acc, err = sdb.GetAccount(idxA1)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "23", acc.Balance.String()) 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)) assert.Equal(t, 21, len(blocks[0].Batches[0].L2Txs))
l2Txs := common.L2TxsToPoolL2Txs(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) require.Nil(t, err)
s, err := json.Marshal(zki) s, err := json.Marshal(zki)

+ 13
- 0
db/statedb/utils.go

@ -2,6 +2,7 @@ package statedb
import ( import (
"bytes" "bytes"
"fmt"
"math/big" "math/big"
ethCommon "github.com/ethereum/go-ethereum/common" 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 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 { func siblingsToZKInputFormat(s []*merkletree.Hash) []*big.Int {
b := make([]*big.Int, len(s)) b := make([]*big.Int, len(s))
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {

+ 1
- 1
synchronizer/synchronizer.go

@ -405,7 +405,7 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*rollupData, error) {
// TODO: Get CollectedFees from ProcessTxs() // TODO: Get CollectedFees from ProcessTxs()
// TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs() // TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs()
// ProcessTxs updates poolL2Txs adding: Nonce, TokenID // 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 { if err != nil {
return nil, err return nil, err
} }

+ 1
- 1
synchronizer/synchronizer_test.go

@ -103,7 +103,7 @@ func TestSync(t *testing.T) {
CreateAccountDeposit(1) C: 5 // Idx=256+4 CreateAccountDeposit(1) C: 5 // Idx=256+4
CreateAccountDeposit(1) D: 5 // Idx=256+5 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 L1UserTxs{nil}, freeze defined L1UserTxs
> batchL1 // forge defined L1UserTxs, freeze L1UserTxs{nil} > batchL1 // forge defined L1UserTxs, freeze L1UserTxs{nil}

+ 1
- 1
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 // transaction generated by the Coordinator, create account for user User0 for
// the TokenID=2, with a deposit of 0 // 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 // deposit of TokenID=1, at the account A, of 6 units

+ 1
- 1
test/til/lang.go

@ -350,7 +350,7 @@ func (p *parser) parseLine(setType setType) (*instruction, error) {
case "CreateAccountDepositTransfer": case "CreateAccountDepositTransfer":
c.typ = common.TxTypeCreateAccountDepositTransfer c.typ = common.TxTypeCreateAccountDepositTransfer
transferring = true transferring = true
case "CreateAccountDepositCoordinator":
case "CreateAccountCoordinator":
c.typ = txTypeCreateAccountDepositCoordinator c.typ = txTypeCreateAccountDepositCoordinator
// transferring is false, as the Coordinator tx transfer will be 0 // transferring is false, as the Coordinator tx transfer will be 0
case "DepositTransfer": case "DepositTransfer":

+ 1
- 1
test/til/lang_test.go

@ -25,7 +25,7 @@ func TestParseBlockchainTxs(t *testing.T) {
Deposit(1) B: 5 Deposit(1) B: 5
CreateAccountDeposit(1) C: 5 CreateAccountDeposit(1) C: 5
CreateAccountDepositTransfer(1) D-A: 15, 10 CreateAccountDepositTransfer(1) D-A: 15, 10
CreateAccountDepositCoordinator(1) E
CreateAccountCoordinator(1) E
// L2 transactions // L2 transactions
Transfer(1) A-B: 6 (1) Transfer(1) A-B: 6 (1)

+ 14
- 2
test/til/sets.go

@ -10,6 +10,14 @@ AddToken(1)
AddToken(2) AddToken(2)
AddToken(3) 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 // deposits TokenID: 1
CreateAccountDeposit(1) A: 50 CreateAccountDeposit(1) A: 50
CreateAccountDeposit(1) B: 5 CreateAccountDeposit(1) B: 5
@ -42,6 +50,9 @@ CreateAccountDeposit(2) B: 5
CreateAccountDeposit(2) A: 20 CreateAccountDeposit(2) A: 20
// deposits TokenID: 3 // deposits TokenID: 3
CreateAccountDeposit(3) B: 100 CreateAccountDeposit(3) B: 100
// deposits TokenID: 0
CreateAccountDeposit(0) B: 10000
CreateAccountDeposit(0) C: 1
> batchL1 > batchL1
@ -67,11 +78,12 @@ Transfer(1) G-K: 3 (1)
Transfer(1) H-K: 3 (2) Transfer(1) H-K: 3 (2)
Transfer(1) H-K: 3 (1) Transfer(1) H-K: 3 (1)
Transfer(1) H-K: 3 (1) Transfer(1) H-K: 3 (1)
Transfer(0) B-C: 50 (192)
> batchL1 > batchL1
> block > block
// A (3) still does not exist, coordinator should create new L1Tx to create the account // 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(3) B-A: 5 (1)
Transfer(2) A-B: 5 (1) Transfer(2) A-B: 5 (1)
@ -156,7 +168,7 @@ Transfer(1) I-H: 5 (1)
Exit(1) A: 5 (1) Exit(1) A: 5 (1)
// create CoordinatorTx CreateAccount for D, TokenId 2, used at SetPool0 for 'PoolTransfer(2) B-D: 3 (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
> batchL1 > batchL1

+ 22
- 2
test/til/txs.go

@ -219,6 +219,26 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
L2Tx: tx, L2Tx: tx,
} }
tc.currBatchTest.l2Txs = append(tc.currBatchTest.l2Txs, testTx) 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 case common.TxTypeExit: // tx source: L2Tx
if err := tc.checkIfTokenIsRegistered(inst); err != nil { if err := tc.checkIfTokenIsRegistered(inst); err != nil {
log.Error(err) log.Error(err)
@ -248,7 +268,7 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
TokenID: inst.tokenID, TokenID: inst.tokenID,
Amount: big.NewInt(int64(inst.amount)), Amount: big.NewInt(int64(inst.amount)),
LoadAmount: big.NewInt(0), LoadAmount: big.NewInt(0),
Type: common.TxTypeExit,
Type: common.TxTypeForceExit,
} }
testTx := L1Tx{ testTx := L1Tx{
lineNum: inst.lineNum, lineNum: inst.lineNum,
@ -415,7 +435,7 @@ func (tc *Context) addToL1Queue(tx L1Tx) error {
} }
tx.L1Tx.ToIdx = account.Idx tx.L1Tx.ToIdx = account.Idx
} }
if tx.L1Tx.Type == common.TxTypeExit {
if tx.L1Tx.Type == common.TxTypeForceExit {
tx.L1Tx.ToIdx = common.Idx(1) tx.L1Tx.ToIdx = common.Idx(1)
} }
nTx, err := common.NewL1Tx(&tx.L1Tx) nTx, err := common.NewL1Tx(&tx.L1Tx)

+ 6
- 6
test/til/txs_test.go

@ -54,8 +54,8 @@ func TestGenerateBlocks(t *testing.T) {
// set new batch // set new batch
> batch // batchNum = 3 > batch // batchNum = 3
CreateAccountDepositCoordinator(1) E
CreateAccountDepositCoordinator(2) B
CreateAccountCoordinator(1) E
CreateAccountCoordinator(2) B
DepositTransfer(1) A-B: 15, 10 DepositTransfer(1) A-B: 15, 10
Transfer(1) C-A : 3 (1) Transfer(1) C-A : 3 (1)
@ -64,8 +64,8 @@ func TestGenerateBlocks(t *testing.T) {
CreateAccountDeposit(1) User0: 20 CreateAccountDeposit(1) User0: 20
CreateAccountDeposit(3) User1: 20 CreateAccountDeposit(3) User1: 20
CreateAccountDepositCoordinator(1) User1
CreateAccountDepositCoordinator(3) User0
CreateAccountCoordinator(1) User1
CreateAccountCoordinator(3) User0
> batchL1 // batchNum = 4 > batchL1 // batchNum = 4
Transfer(1) User0-User1: 15 (1) Transfer(1) User0-User1: 15 (1)
Transfer(3) User1-User0: 15 (1) Transfer(3) User1-User0: 15 (1)
@ -329,7 +329,7 @@ func TestGenerateErrors(t *testing.T) {
AddToken(1) AddToken(1)
CreateAccountDeposit(1) A: 10 CreateAccountDeposit(1) A: 10
> batchL1 > batchL1
CreateAccountDepositCoordinator(1) B
CreateAccountCoordinator(1) B
> batchL1 > batchL1
> batch > batch
Transfer(1) A-B: 6 (1) Transfer(1) A-B: 6 (1)
@ -345,7 +345,7 @@ func TestGenerateErrors(t *testing.T) {
AddToken(1) AddToken(1)
CreateAccountDeposit(1) A: 10 CreateAccountDeposit(1) A: 10
> batchL1 > batchL1
CreateAccountDepositCoordinator(1) B
CreateAccountCoordinator(1) B
> batchL1 > batchL1
Transfer(1) A-B: 6 (1) 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 Transfer(1) A-B: 6 (1) // on purpose this is moving more money that what it has in the account, Til should not fail

+ 4
- 4
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 // 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 // get pending l2-tx from tx-pool
l2TxsRaw, err := txsel.l2db.GetPendingTxs() // once l2db ready, maybe use parameter 'batchNum' l2TxsRaw, err := txsel.l2db.GetPendingTxs() // once l2db ready, maybe use parameter 'batchNum'
if err != nil { if err != nil {
@ -89,7 +89,7 @@ func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]common.Po
txs := txsel.getL2Profitable(validTxs, txsel.MaxTxs) txs := txsel.getL2Profitable(validTxs, txsel.MaxTxs)
// process the txs in the local AccountsDB // 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 { if err != nil {
return nil, err return nil, err
} }
@ -98,7 +98,7 @@ func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]common.Po
} }
// GetL1L2TxSelection returns the selection of L1 + L2 txs // 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 // apply l1-user-tx to localAccountDB
// create new leaves // create new leaves
// update balances // update balances
@ -238,7 +238,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(batchNum common.BatchNum, l1Txs []co
l2Txs := txsel.getL2Profitable(validTxs, maxL2Txs) l2Txs := txsel.getL2Profitable(validTxs, maxL2Txs)
// process the txs in the local AccountsDB // 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 { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

Loading…
Cancel
Save