|
@ -21,7 +21,7 @@ var ( |
|
|
|
|
|
|
|
|
func (s *StateDB) resetZKInputs() { |
|
|
func (s *StateDB) resetZKInputs() { |
|
|
s.zki = nil |
|
|
s.zki = nil |
|
|
s.i = 0 |
|
|
|
|
|
|
|
|
s.i = 0 // initialize current transaction index in the ZKInputs generation
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
type processedExit struct { |
|
|
type processedExit struct { |
|
@ -31,6 +31,14 @@ type processedExit struct { |
|
|
acc common.Account |
|
|
acc common.Account |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ProcessTxOutput contains the output of the ProcessTxs method
|
|
|
|
|
|
type ProcessTxOutput struct { |
|
|
|
|
|
ZKInputs *common.ZKInputs |
|
|
|
|
|
ExitInfos []common.ExitInfo |
|
|
|
|
|
CreatedAccounts []common.Account |
|
|
|
|
|
CoordinatorIdxsMap map[common.TokenID]common.Idx |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
|
|
|
// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
|
|
|
// the StateDB depending on the transaction Type. If StateDB
|
|
|
// the StateDB depending on the transaction Type. If StateDB
|
|
|
// type==TypeBatchBuilder, returns the common.ZKInputs to generate the
|
|
|
// type==TypeBatchBuilder, returns the common.ZKInputs to generate the
|
|
@ -38,26 +46,34 @@ 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(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (*common.ZKInputs, []common.ExitInfo, error) { |
|
|
|
|
|
|
|
|
// And if TypeSynchronizer returns an array of common.Account with all the
|
|
|
|
|
|
// created accounts.
|
|
|
|
|
|
func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (*ProcessTxOutput, error) { |
|
|
var err error |
|
|
var err error |
|
|
var exitTree *merkletree.MerkleTree |
|
|
var exitTree *merkletree.MerkleTree |
|
|
|
|
|
var createdAccounts []common.Account |
|
|
|
|
|
|
|
|
if s.zki != nil { |
|
|
if s.zki != nil { |
|
|
return nil, nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty") |
|
|
|
|
|
|
|
|
return nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty") |
|
|
} |
|
|
} |
|
|
defer s.resetZKInputs() |
|
|
defer s.resetZKInputs() |
|
|
|
|
|
|
|
|
nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs) |
|
|
nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs) |
|
|
if nTx == 0 { |
|
|
if nTx == 0 { |
|
|
// TODO return ZKInputs of batch without txs
|
|
|
// TODO return ZKInputs of batch without txs
|
|
|
return nil, nil, nil |
|
|
|
|
|
|
|
|
return &ProcessTxOutput{ |
|
|
|
|
|
ZKInputs: nil, |
|
|
|
|
|
ExitInfos: nil, |
|
|
|
|
|
CreatedAccounts: nil, |
|
|
|
|
|
CoordinatorIdxsMap: nil, |
|
|
|
|
|
}, nil |
|
|
} |
|
|
} |
|
|
exits := make([]processedExit, nTx) |
|
|
exits := make([]processedExit, nTx) |
|
|
|
|
|
|
|
|
// get TokenIDs of coordIdxs
|
|
|
// get TokenIDs of coordIdxs
|
|
|
coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs) |
|
|
coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if s.typ == TypeBatchBuilder { |
|
|
if s.typ == TypeBatchBuilder { |
|
@ -71,7 +87,7 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
tmpDir, err := ioutil.TempDir("", "hermez-statedb-exittree") |
|
|
tmpDir, err := ioutil.TempDir("", "hermez-statedb-exittree") |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
defer func() { |
|
|
defer func() { |
|
|
if err := os.RemoveAll(tmpDir); err != nil { |
|
|
if err := os.RemoveAll(tmpDir); err != nil { |
|
@ -80,19 +96,19 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
}() |
|
|
}() |
|
|
sto, err := pebble.NewPebbleStorage(tmpDir, false) |
|
|
sto, err := pebble.NewPebbleStorage(tmpDir, false) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
exitTree, err = merkletree.NewMerkleTree(sto, s.mt.MaxLevels()) |
|
|
exitTree, err = merkletree.NewMerkleTree(sto, s.mt.MaxLevels()) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// assumption: l1usertx are sorted by L1Tx.Position
|
|
|
// assumption: l1usertx are sorted by L1Tx.Position
|
|
|
for i := 0; i < len(l1usertxs); i++ { |
|
|
for i := 0; i < len(l1usertxs); i++ { |
|
|
exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, &l1usertxs[i]) |
|
|
|
|
|
|
|
|
exitIdx, exitAccount, newExit, createdAccount, err := s.processL1Tx(exitTree, &l1usertxs[i]) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
if exitIdx != nil && exitTree != nil { |
|
|
if exitIdx != nil && exitTree != nil { |
|
@ -105,31 +121,26 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
} |
|
|
} |
|
|
s.i++ |
|
|
s.i++ |
|
|
} |
|
|
} |
|
|
|
|
|
if s.typ == TypeSynchronizer && createdAccount != nil { |
|
|
|
|
|
createdAccounts = append(createdAccounts, *createdAccount) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
for i := 0; i < len(l1coordinatortxs); i++ { |
|
|
for i := 0; i < len(l1coordinatortxs); i++ { |
|
|
exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, &l1coordinatortxs[i]) |
|
|
|
|
|
|
|
|
exitIdx, _, _, createdAccount, err := s.processL1Tx(exitTree, &l1coordinatortxs[i]) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
if exitIdx != nil { |
|
|
if exitIdx != nil { |
|
|
log.Error("Unexpected Exit in L1CoordinatorTx") |
|
|
log.Error("Unexpected Exit in L1CoordinatorTx") |
|
|
} |
|
|
} |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
|
|
|
if exitIdx != nil && exitTree != nil { |
|
|
|
|
|
exits[s.i] = processedExit{ |
|
|
|
|
|
exit: true, |
|
|
|
|
|
newExit: newExit, |
|
|
|
|
|
idx: *exitIdx, |
|
|
|
|
|
acc: *exitAccount, |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
s.i++ |
|
|
|
|
|
|
|
|
if s.typ == TypeSynchronizer && createdAccount != nil { |
|
|
|
|
|
createdAccounts = append(createdAccounts, *createdAccount) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
for i := 0; i < len(l2txs); i++ { |
|
|
for i := 0; i < len(l2txs); i++ { |
|
|
exitIdx, exitAccount, newExit, err := s.processL2Tx(coordIdxsMap, 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, err |
|
|
} |
|
|
} |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { |
|
|
if exitIdx != nil && exitTree != nil { |
|
|
if exitIdx != nil && exitTree != nil { |
|
@ -145,12 +156,13 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if s.typ == TypeTxSelector { |
|
|
if s.typ == TypeTxSelector { |
|
|
return nil, nil, nil |
|
|
|
|
|
|
|
|
return nil, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// once all txs processed (exitTree root frozen), for each Exit,
|
|
|
// once all txs processed (exitTree root frozen), for each Exit,
|
|
|
// generate common.ExitInfo data
|
|
|
// generate common.ExitInfo data
|
|
|
var exitInfos []common.ExitInfo |
|
|
var exitInfos []common.ExitInfo |
|
|
|
|
|
// exitInfos := []common.ExitInfo{}
|
|
|
for i := 0; i < nTx; i++ { |
|
|
for i := 0; i < nTx; i++ { |
|
|
if !exits[i].exit { |
|
|
if !exits[i].exit { |
|
|
continue |
|
|
continue |
|
@ -161,7 +173,7 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
// 0. generate MerkleProof
|
|
|
// 0. generate MerkleProof
|
|
|
p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil) |
|
|
p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
// 1. generate common.ExitInfo
|
|
|
// 1. generate common.ExitInfo
|
|
|
ei := common.ExitInfo{ |
|
|
ei := common.ExitInfo{ |
|
@ -192,7 +204,14 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
if s.typ == TypeSynchronizer { |
|
|
if s.typ == TypeSynchronizer { |
|
|
return nil, exitInfos, nil |
|
|
|
|
|
|
|
|
// return exitInfos and createdAccounts, so Synchronizer will
|
|
|
|
|
|
// be able to store it into HistoryDB for the concrete BatchNum
|
|
|
|
|
|
return &ProcessTxOutput{ |
|
|
|
|
|
ZKInputs: nil, |
|
|
|
|
|
ExitInfos: exitInfos, |
|
|
|
|
|
CreatedAccounts: createdAccounts, |
|
|
|
|
|
CoordinatorIdxsMap: coordIdxsMap, |
|
|
|
|
|
}, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// compute last ZKInputs parameters
|
|
|
// compute last ZKInputs parameters
|
|
@ -200,7 +219,7 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
// zki.FeeIdxs = ? // TODO, this will be get from the config file
|
|
|
// zki.FeeIdxs = ? // TODO, this will be get from the config file
|
|
|
tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs) |
|
|
tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return nil, nil, err |
|
|
|
|
|
|
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
s.zki.FeePlanTokens = tokenIDs |
|
|
s.zki.FeePlanTokens = tokenIDs |
|
|
|
|
|
|
|
@ -209,9 +228,13 @@ func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs |
|
|
// TODO once the Node Config sets the Accounts where to send the Fees
|
|
|
// TODO once the Node Config sets the Accounts where to send the Fees
|
|
|
// compute fees & update ZKInputs
|
|
|
// compute fees & update ZKInputs
|
|
|
|
|
|
|
|
|
// return exitInfos, so Synchronizer will be able to store it into
|
|
|
|
|
|
// HistoryDB for the concrete BatchNum
|
|
|
|
|
|
return s.zki, exitInfos, nil |
|
|
|
|
|
|
|
|
// return ZKInputs as the BatchBuilder will return it to forge the Batch
|
|
|
|
|
|
return &ProcessTxOutput{ |
|
|
|
|
|
ZKInputs: s.zki, |
|
|
|
|
|
ExitInfos: nil, |
|
|
|
|
|
CreatedAccounts: nil, |
|
|
|
|
|
CoordinatorIdxsMap: coordIdxsMap, |
|
|
|
|
|
}, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
|
|
|
// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
|
|
@ -243,7 +266,10 @@ func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []common.L1Tx, l |
|
|
// 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) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, error) { |
|
|
|
|
|
|
|
|
// And another *common.Account parameter which contains the created account in
|
|
|
|
|
|
// case that has been a new created account and that the StateDB is of type
|
|
|
|
|
|
// TypeSynchronizer.
|
|
|
|
|
|
func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, *common.Account, error) { |
|
|
// ZKInputs
|
|
|
// ZKInputs
|
|
|
if s.zki != nil { |
|
|
if s.zki != nil { |
|
|
// Txs
|
|
|
// Txs
|
|
@ -273,14 +299,14 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) |
|
|
err := s.applyTransfer(nil, tx.Tx(), 0) |
|
|
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, nil, err |
|
|
} |
|
|
} |
|
|
case common.TxTypeCreateAccountDeposit: |
|
|
case common.TxTypeCreateAccountDeposit: |
|
|
// add new account to the MT, update balance of the MT account
|
|
|
// add new account to the MT, update balance of the MT account
|
|
|
err := s.applyCreateAccount(tx) |
|
|
err := s.applyCreateAccount(tx) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Error(err) |
|
|
log.Error(err) |
|
|
return nil, nil, false, err |
|
|
|
|
|
|
|
|
return nil, nil, false, nil, err |
|
|
} |
|
|
} |
|
|
// TODO applyCreateAccount will return the created account,
|
|
|
// TODO applyCreateAccount will return the created account,
|
|
|
// which in the case type==TypeSynchronizer will be added to an
|
|
|
// which in the case type==TypeSynchronizer will be added to an
|
|
@ -295,7 +321,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) |
|
|
err := s.applyDeposit(tx, false) |
|
|
err := s.applyDeposit(tx, false) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Error(err) |
|
|
log.Error(err) |
|
|
return nil, nil, false, err |
|
|
|
|
|
|
|
|
return nil, nil, false, nil, err |
|
|
} |
|
|
} |
|
|
case common.TxTypeDepositTransfer: |
|
|
case common.TxTypeDepositTransfer: |
|
|
// update balance in MT account, update balance & nonce of sender
|
|
|
// update balance in MT account, update balance & nonce of sender
|
|
@ -303,7 +329,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) |
|
|
err := s.applyDeposit(tx, true) |
|
|
err := s.applyDeposit(tx, true) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Error(err) |
|
|
log.Error(err) |
|
|
return nil, nil, false, err |
|
|
|
|
|
|
|
|
return nil, nil, false, nil, err |
|
|
} |
|
|
} |
|
|
case common.TxTypeCreateAccountDepositTransfer: |
|
|
case common.TxTypeCreateAccountDepositTransfer: |
|
|
// add new account to the merkletree, update balance in MT account,
|
|
|
// add new account to the merkletree, update balance in MT account,
|
|
@ -311,7 +337,7 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) |
|
|
err := s.applyCreateAccountDepositTransfer(tx) |
|
|
err := s.applyCreateAccountDepositTransfer(tx) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Error(err) |
|
|
log.Error(err) |
|
|
return nil, nil, false, err |
|
|
|
|
|
|
|
|
return nil, nil, false, nil, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if s.zki != nil { |
|
|
if s.zki != nil { |
|
@ -324,13 +350,23 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) |
|
|
exitAccount, newExit, err := s.applyExit(nil, exitTree, tx.Tx()) |
|
|
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, nil, err |
|
|
} |
|
|
} |
|
|
return &tx.FromIdx, exitAccount, newExit, nil |
|
|
|
|
|
|
|
|
return &tx.FromIdx, exitAccount, newExit, nil, nil |
|
|
default: |
|
|
default: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return nil, nil, false, nil |
|
|
|
|
|
|
|
|
var createdAccount *common.Account |
|
|
|
|
|
if s.typ == TypeSynchronizer && (tx.Type == common.TxTypeCreateAccountDeposit || tx.Type == common.TxTypeCreateAccountDepositTransfer) { |
|
|
|
|
|
var err error |
|
|
|
|
|
createdAccount, err = s.GetAccount(s.idx) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
return nil, nil, false, nil, err |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return nil, nil, false, createdAccount, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// processL2Tx process the given L2Tx applying the needed updates to the
|
|
|
// processL2Tx process the given L2Tx applying the needed updates to the
|
|
|