Browse Source

Merge pull request #171 from hermeznetwork/feature/processtx-l2tx-nonces

Add StateDB compute nonces on ProcessTx L2Tx
feature/sql-semaphore1
Eduard S 4 years ago
committed by GitHub
parent
commit
9e4f020c2b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 192 additions and 94 deletions
  1. +1
    -1
      api/api_test.go
  2. +2
    -2
      batchbuilder/batchbuilder.go
  3. +1
    -1
      batchbuilder/batchbuilder_test.go
  4. +13
    -4
      coordinator/coordinator_test.go
  5. +43
    -24
      db/statedb/statedb.go
  6. +8
    -8
      db/statedb/statedb_test.go
  7. +48
    -35
      db/statedb/txprocessors.go
  8. +66
    -9
      db/statedb/txprocessors_test.go
  9. +1
    -1
      db/statedb/utils_test.go
  10. +1
    -1
      node/node.go
  11. +3
    -3
      synchronizer/synchronizer.go
  12. +1
    -1
      synchronizer/synchronizer_test.go
  13. +3
    -3
      txselector/txselector.go
  14. +1
    -1
      txselector/txselector_test.go

+ 1
- 1
api/api_test.go

@ -96,7 +96,7 @@ func TestMain(m *testing.M) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
sdb, err := statedb.NewStateDB(dir, false, 0)
sdb, err := statedb.NewStateDB(dir, statedb.TypeTxSelector, 0)
if err != nil { if err != nil {
panic(err) panic(err)
} }

+ 2
- 2
batchbuilder/batchbuilder.go

@ -28,7 +28,7 @@ type ConfigBatch struct {
// NewBatchBuilder constructs a new BatchBuilder, and executes the bb.Reset // NewBatchBuilder constructs a new BatchBuilder, and executes the bb.Reset
// method // method
func NewBatchBuilder(dbpath string, synchronizerStateDB *statedb.StateDB, configCircuits []ConfigCircuit, batchNum common.BatchNum, nLevels uint64) (*BatchBuilder, error) { func NewBatchBuilder(dbpath string, synchronizerStateDB *statedb.StateDB, configCircuits []ConfigCircuit, batchNum common.BatchNum, nLevels uint64) (*BatchBuilder, error) {
localStateDB, err := statedb.NewLocalStateDB(dbpath, synchronizerStateDB, true, int(nLevels))
localStateDB, err := statedb.NewLocalStateDB(dbpath, synchronizerStateDB, statedb.TypeBatchBuilder, int(nLevels))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -52,7 +52,7 @@ 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) { func (bb *BatchBuilder) BuildBatch(configBatch *ConfigBatch, l1usertxs, l1coordinatortxs []*common.L1Tx, pooll2txs []*common.PoolL2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) {
zkInputs, _, err := bb.localStateDB.ProcessTxs(false, true, l1usertxs, l1coordinatortxs, pooll2txs)
zkInputs, _, err := bb.localStateDB.ProcessTxs(l1usertxs, l1coordinatortxs, pooll2txs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

+ 1
- 1
batchbuilder/batchbuilder_test.go

@ -13,7 +13,7 @@ func TestBatchBuilder(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
synchDB, err := statedb.NewStateDB(dir, false, 0)
synchDB, err := statedb.NewStateDB(dir, statedb.TypeBatchBuilder, 0)
assert.Nil(t, err) assert.Nil(t, err)
bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB") bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")

+ 13
- 4
coordinator/coordinator_test.go

@ -23,11 +23,20 @@ import (
func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBuilder) { // FUTURE once Synchronizer is ready, should return it also func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBuilder) { // FUTURE once Synchronizer is ready, should return it also
nLevels := 32 nLevels := 32
synchDB, err := ioutil.TempDir("", "tmpSynchDB")
synchDBPath, err := ioutil.TempDir("", "tmpSynchDB")
require.Nil(t, err) require.Nil(t, err)
sdb, err := statedb.NewStateDB(synchDB, true, nLevels)
synchSdb, err := statedb.NewStateDB(synchDBPath, statedb.TypeSynchronizer, nLevels)
assert.Nil(t, err) assert.Nil(t, err)
// txselDBPath, err := ioutil.TempDir("", "tmpTxSelDB")
// require.Nil(t, err)
// bbDBPath, err := ioutil.TempDir("", "tmpBBDB")
// require.Nil(t, err)
// txselSdb, err := statedb.NewLocalStateDB(txselDBPath, synchSdb, statedb.TypeTxSelector, nLevels)
// assert.Nil(t, err)
// bbSdb, err := statedb.NewLocalStateDB(bbDBPath, synchSdb, statedb.TypeBatchBuilder, nLevels)
// assert.Nil(t, err)
pass := os.Getenv("POSTGRES_PASS") pass := os.Getenv("POSTGRES_PASS")
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez") db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
require.Nil(t, err) require.Nil(t, err)
@ -35,12 +44,12 @@ func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBu
txselDir, err := ioutil.TempDir("", "tmpTxSelDB") txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
require.Nil(t, err) require.Nil(t, err)
txsel, err := txselector.NewTxSelector(txselDir, sdb, l2DB, 10, 10, 10)
txsel, err := txselector.NewTxSelector(txselDir, synchSdb, l2DB, 10, 10, 10)
assert.Nil(t, err) assert.Nil(t, err)
bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB") bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
require.Nil(t, err) require.Nil(t, err)
bb, err := batchbuilder.NewBatchBuilder(bbDir, sdb, nil, 0, uint64(nLevels))
bb, err := batchbuilder.NewBatchBuilder(bbDir, synchSdb, nil, 0, uint64(nLevels))
assert.Nil(t, err) assert.Nil(t, err)
// l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0) // l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0)

+ 43
- 24
db/statedb/statedb.go

@ -15,31 +15,45 @@ import (
// TODO(Edu): Document here how StateDB is kept consistent // TODO(Edu): Document here how StateDB is kept consistent
// ErrStateDBWithoutMT is used when a method that requires a MerkleTree is
// called in a StateDB that does not have a MerkleTree defined
var ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
var (
// ErrStateDBWithoutMT is used when a method that requires a MerkleTree
// is called in a StateDB that does not have a MerkleTree defined
ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
// ErrAccountAlreadyExists is used when CreateAccount is called and the Account
// already exists
var ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
// ErrAccountAlreadyExists is used when CreateAccount is called and the
// Account already exists
ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
// ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr or
// ToEthAddr&ToBJJ
var ErrToIdxNotFound = errors.New("ToIdx can not be found")
// ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr
// or ToEthAddr&ToBJJ
ErrToIdxNotFound = errors.New("ToIdx can not be found")
// KeyCurrentBatch is used as key in the db to store the current BatchNum
var KeyCurrentBatch = []byte("currentbatch")
// PathStateDB defines the subpath of the StateDB
const PathStateDB = "/statedb"
// KeyCurrentBatch is used as key in the db to store the current BatchNum
KeyCurrentBatch = []byte("currentbatch")
)
// PathBatchNum defines the subpath of the Batch Checkpoint in the subpath of
// the StateDB
const PathBatchNum = "/BatchNum"
const (
// PathStateDB defines the subpath of the StateDB
PathStateDB = "/statedb"
// PathBatchNum defines the subpath of the Batch Checkpoint in the
// subpath of the StateDB
PathBatchNum = "/BatchNum"
// PathCurrent defines the subpath of the current Batch in the subpath
// of the StateDB
PathCurrent = "/current"
// TypeSynchronizer defines a StateDB used by the Synchronizer, that
// generates the ExitTree when processing the txs
TypeSynchronizer = "synchronizer"
// TypeTxSelector defines a StateDB used by the TxSelector, without
// computing ExitTree neither the ZKInputs
TypeTxSelector = "txselector"
// TypeBatchBuilder defines a StateDB used by the BatchBuilder, that
// generates the ExitTree and the ZKInput when processing the txs
TypeBatchBuilder = "batchbuilder"
)
// PathCurrent defines the subpath of the current Batch in the subpath of the
// StateDB
const PathCurrent = "/current"
// TypeStateDB determines the type of StateDB
type TypeStateDB string
// StateDB represents the StateDB object // StateDB represents the StateDB object
type StateDB struct { type StateDB struct {
@ -47,6 +61,7 @@ type StateDB struct {
currentBatch common.BatchNum currentBatch common.BatchNum
db *pebble.PebbleStorage db *pebble.PebbleStorage
mt *merkletree.MerkleTree mt *merkletree.MerkleTree
typ TypeStateDB
// idx holds the current Idx that the BatchBuilder is using // idx holds the current Idx that the BatchBuilder is using
idx common.Idx idx common.Idx
zki *common.ZKInputs zki *common.ZKInputs
@ -55,7 +70,7 @@ type StateDB struct {
// NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
// storage // storage
func NewStateDB(path string, withMT bool, nLevels int) (*StateDB, error) {
func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
var sto *pebble.PebbleStorage var sto *pebble.PebbleStorage
var err error var err error
sto, err = pebble.NewPebbleStorage(path+PathStateDB+PathCurrent, false) sto, err = pebble.NewPebbleStorage(path+PathStateDB+PathCurrent, false)
@ -64,17 +79,21 @@ func NewStateDB(path string, withMT bool, nLevels int) (*StateDB, error) {
} }
var mt *merkletree.MerkleTree = nil var mt *merkletree.MerkleTree = nil
if withMT {
if typ == TypeSynchronizer || typ == TypeBatchBuilder {
mt, err = merkletree.NewMerkleTree(sto, nLevels) mt, err = merkletree.NewMerkleTree(sto, nLevels)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if typ == TypeTxSelector && nLevels != 0 {
return nil, fmt.Errorf("invalid StateDB parameters: StateDB type==TypeStateDB can not have nLevels!=0")
}
sdb := &StateDB{ sdb := &StateDB{
path: path + PathStateDB, path: path + PathStateDB,
db: sto, db: sto,
mt: mt, mt: mt,
typ: typ,
} }
// load currentBatch // load currentBatch
@ -382,8 +401,8 @@ type LocalStateDB struct {
// NewLocalStateDB returns a new LocalStateDB connected to the given // NewLocalStateDB returns a new LocalStateDB connected to the given
// synchronizerDB // synchronizerDB
func NewLocalStateDB(path string, synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalStateDB, error) {
s, err := NewStateDB(path, withMT, nLevels)
func NewLocalStateDB(path string, synchronizerDB *StateDB, typ TypeStateDB, nLevels int) (*LocalStateDB, error) {
s, err := NewStateDB(path, typ, nLevels)
if err != nil { if err != nil {
return nil, err return nil, err
} }

+ 8
- 8
db/statedb/statedb_test.go

@ -38,7 +38,7 @@ func TestNewStateDBIntermediateState(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, false, 0)
sdb, err := NewStateDB(dir, TypeTxSelector, 0)
assert.Nil(t, err) assert.Nil(t, err)
// test values // test values
@ -60,7 +60,7 @@ func TestNewStateDBIntermediateState(t *testing.T) {
// call NewStateDB which should get the db at the last checkpoint state // call NewStateDB which should get the db at the last checkpoint state
// executing a Reset (discarding the last 'testkey0'&'testvalue0' data) // executing a Reset (discarding the last 'testkey0'&'testvalue0' data)
sdb, err = NewStateDB(dir, false, 0)
sdb, err = NewStateDB(dir, TypeTxSelector, 0)
assert.Nil(t, err) assert.Nil(t, err)
v, err = sdb.db.Get(k0) v, err = sdb.db.Get(k0)
assert.NotNil(t, err) assert.NotNil(t, err)
@ -102,7 +102,7 @@ func TestNewStateDBIntermediateState(t *testing.T) {
// call NewStateDB which should get the db at the last checkpoint state // call NewStateDB which should get the db at the last checkpoint state
// executing a Reset (discarding the last 'testkey1'&'testvalue1' data) // executing a Reset (discarding the last 'testkey1'&'testvalue1' data)
sdb, err = NewStateDB(dir, false, 0)
sdb, err = NewStateDB(dir, TypeTxSelector, 0)
assert.Nil(t, err) assert.Nil(t, err)
v, err = sdb.db.Get(k0) v, err = sdb.db.Get(k0)
@ -119,7 +119,7 @@ func TestStateDBWithoutMT(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, false, 0)
sdb, err := NewStateDB(dir, TypeTxSelector, 0)
assert.Nil(t, err) assert.Nil(t, err)
// create test accounts // create test accounts
@ -168,7 +168,7 @@ func TestStateDBWithMT(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, true, 32)
sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
assert.Nil(t, err) assert.Nil(t, err)
// create test accounts // create test accounts
@ -219,7 +219,7 @@ func TestCheckpoints(t *testing.T) {
dir, err := ioutil.TempDir("", "sdb") dir, err := ioutil.TempDir("", "sdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, true, 32)
sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
assert.Nil(t, err) assert.Nil(t, err)
// create test accounts // create test accounts
@ -285,7 +285,7 @@ func TestCheckpoints(t *testing.T) {
// Create a LocalStateDB from the initial StateDB // Create a LocalStateDB from the initial StateDB
dirLocal, err := ioutil.TempDir("", "ldb") dirLocal, err := ioutil.TempDir("", "ldb")
require.Nil(t, err) require.Nil(t, err)
ldb, err := NewLocalStateDB(dirLocal, sdb, true, 32)
ldb, err := NewLocalStateDB(dirLocal, sdb, TypeBatchBuilder, 32)
assert.Nil(t, err) assert.Nil(t, err)
// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB) // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)
@ -305,7 +305,7 @@ func TestCheckpoints(t *testing.T) {
// Create a 2nd LocalStateDB from the initial StateDB // Create a 2nd LocalStateDB from the initial StateDB
dirLocal2, err := ioutil.TempDir("", "ldb2") dirLocal2, err := ioutil.TempDir("", "ldb2")
require.Nil(t, err) require.Nil(t, err)
ldb2, err := NewLocalStateDB(dirLocal2, sdb, true, 32)
ldb2, err := NewLocalStateDB(dirLocal2, sdb, TypeBatchBuilder, 32)
assert.Nil(t, err) assert.Nil(t, err)
// get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB) // get checkpoint 4 from sdb (StateDB) to ldb (LocalStateDB)

+ 48
- 35
db/statedb/txprocessors.go

@ -30,11 +30,13 @@ type processedExit struct {
} }
// 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. Returns the common.ZKInputs
// to generate the SnarkProof later used by the BatchBuilder, and if
// cmpExitTree is set to true, returns common.ExitTreeLeaf that is later used
// by the Synchronizer to update the HistoryDB.
func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) (*common.ZKInputs, []*common.ExitInfo, error) {
// the StateDB depending on the transaction Type. If StateDB
// type==TypeBatchBuilder, returns the common.ZKInputs to generate the
// 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) {
var err error var err error
var exitTree *merkletree.MerkleTree var exitTree *merkletree.MerkleTree
@ -50,7 +52,7 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
} }
exits := make([]processedExit, nTx) exits := make([]processedExit, nTx)
if cmpZKInputs {
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()
s.zki.OldStateRoot = s.mt.Root().BigInt() s.zki.OldStateRoot = s.mt.Root().BigInt()
@ -58,7 +60,7 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
// TBD if ExitTree is only in memory or stored in disk, for the moment // TBD if ExitTree is only in memory or stored in disk, for the moment
// only needed in memory // only needed in memory
if cmpExitTree {
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels()) exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -71,15 +73,15 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if exitIdx != nil && cmpExitTree {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
if exitIdx != nil && exitTree != nil {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
}
} }
}
if s.zki != nil {
s.i++ s.i++
} }
} }
@ -91,15 +93,15 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
if exitIdx != nil { if exitIdx != nil {
log.Error("Unexpected Exit in L1CoordinatorTx") log.Error("Unexpected Exit in L1CoordinatorTx")
} }
if exitIdx != nil && cmpExitTree {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
if exitIdx != nil && exitTree != nil {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
}
} }
}
if s.zki != nil {
s.i++ s.i++
} }
} }
@ -108,26 +110,26 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if exitIdx != nil && cmpExitTree {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
if exitIdx != nil && exitTree != nil {
exits[s.i] = processedExit{
exit: true,
newExit: newExit,
idx: *exitIdx,
acc: *exitAccount,
}
} }
}
if s.zki != nil {
s.i++ s.i++
} }
} }
if !cmpExitTree && !cmpZKInputs {
if s.typ == TypeTxSelector {
return nil, nil, nil return nil, 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
for i := 0; i < nTx; i++ { for i := 0; i < nTx; i++ {
if !exits[i].exit { if !exits[i].exit {
continue continue
@ -141,7 +143,7 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
return nil, nil, err return nil, nil, err
} }
// 1. generate common.ExitInfo // 1. generate common.ExitInfo
ei := &common.ExitInfo{
ei := common.ExitInfo{
AccountIdx: exitIdx, AccountIdx: exitIdx,
MerkleProof: p, MerkleProof: p,
Balance: exitAccount.Balance, Balance: exitAccount.Balance,
@ -168,7 +170,7 @@ func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordin
s.zki.OldValue2[i] = p.OldValue.BigInt() s.zki.OldValue2[i] = p.OldValue.BigInt()
} }
} }
if !cmpZKInputs {
if s.typ == TypeSynchronizer {
return nil, exitInfos, nil return nil, exitInfos, nil
} }
@ -345,6 +347,17 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
s.zki.R8y[s.i] = tx.Signature.R8.Y s.zki.R8y[s.i] = tx.Signature.R8.Y
} }
// if StateDB type==TypeSynchronizer, will need to add Nonce and
// TokenID to the transaction
if s.typ == TypeSynchronizer {
acc, err := s.GetAccount(tx.ToIdx)
if err != nil {
return nil, nil, false, err
}
tx.Nonce = acc.Nonce
tx.TokenID = acc.TokenID
}
switch tx.Type { switch tx.Type {
case common.TxTypeTransfer: case common.TxTypeTransfer:
// go to the MT account of sender and receiver, and update // go to the MT account of sender and receiver, and update

+ 66
- 9
db/statedb/txprocessors_test.go

@ -19,7 +19,7 @@ func TestProcessTxs(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, true, 32)
sdb, err := NewStateDB(dir, TypeBatchBuilder, 32)
assert.Nil(t, err) assert.Nil(t, err)
// generate test transactions from test.SetTest0 code // generate test transactions from test.SetTest0 code
@ -36,7 +36,7 @@ func TestProcessTxs(t *testing.T) {
for i := 0; i < len(l1Txs); i++ { for i := 0; i < len(l1Txs); i++ {
// l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs[i]) // l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs[i])
_, _, err := sdb.ProcessTxs(true, true, l1Txs[i], coordinatorL1Txs[i], poolL2Txs[i])
_, _, err := sdb.ProcessTxs(l1Txs[i], coordinatorL1Txs[i], poolL2Txs[i])
require.Nil(t, err) require.Nil(t, err)
} }
@ -45,11 +45,68 @@ func TestProcessTxs(t *testing.T) {
assert.Equal(t, "23", acc.Balance.String()) assert.Equal(t, "23", acc.Balance.String())
} }
func TestProcessTxsBatchByBatch(t *testing.T) {
func TestProcessTxsSynchronizer(t *testing.T) {
// TODO once TTGL is updated, use the blockchain L2Tx (not PoolL2Tx) for
// the Synchronizer tests
dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err)
sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
assert.Nil(t, err)
// generate test transactions from test.SetTest0 code
parser := test.NewParser(strings.NewReader(test.SetTest0))
instructions, err := parser.Parse()
assert.Nil(t, err)
l1Txs, coordinatorL1Txs, poolL2Txs, _ := test.GenerateTestTxs(t, instructions)
assert.Equal(t, 29, len(l1Txs[0]))
assert.Equal(t, 0, len(coordinatorL1Txs[0]))
assert.Equal(t, 21, len(poolL2Txs[0]))
assert.Equal(t, 5, len(l1Txs[1]))
assert.Equal(t, 1, len(coordinatorL1Txs[1]))
assert.Equal(t, 55, len(poolL2Txs[1]))
assert.Equal(t, 10, len(l1Txs[2]))
assert.Equal(t, 0, len(coordinatorL1Txs[2]))
assert.Equal(t, 7, len(poolL2Txs[2]))
// use first batch
// l2txs := common.PoolL2TxsToL2Txs(poolL2Txs[0])
_, exitInfos, err := sdb.ProcessTxs(l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
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))
assert.Nil(t, err)
assert.Equal(t, "28", acc.Balance.String())
// use second batch
// l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[1])
_, exitInfos, err = sdb.ProcessTxs(l1Txs[1], coordinatorL1Txs[1], poolL2Txs[1])
require.Nil(t, err)
assert.Equal(t, 5, len(exitInfos))
acc, err = sdb.GetAccount(common.Idx(256))
require.Nil(t, err)
assert.Equal(t, "48", acc.Balance.String())
// use third batch
// l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[2])
_, exitInfos, err = sdb.ProcessTxs(l1Txs[2], coordinatorL1Txs[2], poolL2Txs[2])
require.Nil(t, err)
assert.Equal(t, 1, len(exitInfos))
acc, err = sdb.GetAccount(common.Idx(256))
assert.Nil(t, err)
assert.Equal(t, "23", acc.Balance.String())
}
func TestProcessTxsBatchBuilder(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, true, 32)
sdb, err := NewStateDB(dir, TypeBatchBuilder, 32)
assert.Nil(t, err) assert.Nil(t, err)
// generate test transactions from test.SetTest0 code // generate test transactions from test.SetTest0 code
@ -70,7 +127,7 @@ func TestProcessTxsBatchByBatch(t *testing.T) {
// use first batch // use first batch
// l2txs := common.PoolL2TxsToL2Txs(poolL2Txs[0]) // l2txs := common.PoolL2TxsToL2Txs(poolL2Txs[0])
_, exitInfos, err := sdb.ProcessTxs(true, true, l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
_, exitInfos, err := sdb.ProcessTxs(l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
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(common.Idx(256))
@ -79,7 +136,7 @@ func TestProcessTxsBatchByBatch(t *testing.T) {
// use second batch // use second batch
// l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[1]) // l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[1])
_, exitInfos, err = sdb.ProcessTxs(true, true, l1Txs[1], coordinatorL1Txs[1], poolL2Txs[1])
_, exitInfos, err = sdb.ProcessTxs(l1Txs[1], coordinatorL1Txs[1], poolL2Txs[1])
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(common.Idx(256))
@ -88,7 +145,7 @@ func TestProcessTxsBatchByBatch(t *testing.T) {
// use third batch // use third batch
// l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[2]) // l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[2])
_, exitInfos, err = sdb.ProcessTxs(true, true, l1Txs[2], coordinatorL1Txs[2], poolL2Txs[2])
_, exitInfos, err = sdb.ProcessTxs(l1Txs[2], coordinatorL1Txs[2], poolL2Txs[2])
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(common.Idx(256))
@ -100,7 +157,7 @@ func TestZKInputsGeneration(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, true, 32)
sdb, err := NewStateDB(dir, TypeBatchBuilder, 32)
assert.Nil(t, err) assert.Nil(t, err)
// generate test transactions from test.SetTest0 code // generate test transactions from test.SetTest0 code
@ -113,7 +170,7 @@ func TestZKInputsGeneration(t *testing.T) {
assert.Equal(t, 0, len(coordinatorL1Txs[0])) assert.Equal(t, 0, len(coordinatorL1Txs[0]))
assert.Equal(t, 21, len(poolL2Txs[0])) assert.Equal(t, 21, len(poolL2Txs[0]))
zki, _, err := sdb.ProcessTxs(false, true, l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
zki, _, err := sdb.ProcessTxs(l1Txs[0], coordinatorL1Txs[0], poolL2Txs[0])
require.Nil(t, err) require.Nil(t, err)
s, err := json.Marshal(zki) s, err := json.Marshal(zki)

+ 1
- 1
db/statedb/utils_test.go

@ -16,7 +16,7 @@ func TestGetIdx(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := NewStateDB(dir, false, 0)
sdb, err := NewStateDB(dir, TypeTxSelector, 0)
assert.Nil(t, err) assert.Nil(t, err)
var sk babyjub.PrivateKey var sk babyjub.PrivateKey

+ 1
- 1
node/node.go

@ -72,7 +72,7 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
historyDB := historydb.NewHistoryDB(db) historyDB := historydb.NewHistoryDB(db)
stateDB, err := statedb.NewStateDB(cfg.StateDB.Path, true, 32)
stateDB, err := statedb.NewStateDB(cfg.StateDB.Path, statedb.TypeSynchronizer, 32)
if err != nil { if err != nil {
return nil, err return nil, err
} }

+ 3
- 3
synchronizer/synchronizer.go

@ -58,7 +58,7 @@ type BatchData struct {
l1CoordinatorTxs []*common.L1Tx l1CoordinatorTxs []*common.L1Tx
l2Txs []*common.L2Tx l2Txs []*common.L2Tx
createdAccounts []*common.Account createdAccounts []*common.Account
exitTree []*common.ExitInfo
exitTree []common.ExitInfo
batch *common.Batch batch *common.Batch
} }
@ -69,7 +69,7 @@ func NewBatchData() *BatchData {
l1CoordinatorTxs: make([]*common.L1Tx, 0), l1CoordinatorTxs: make([]*common.L1Tx, 0),
l2Txs: make([]*common.L2Tx, 0), l2Txs: make([]*common.L2Tx, 0),
createdAccounts: make([]*common.Account, 0), createdAccounts: make([]*common.Account, 0),
exitTree: make([]*common.ExitInfo, 0),
exitTree: make([]common.ExitInfo, 0),
} }
} }
@ -435,7 +435,7 @@ func (s *Synchronizer) rollupSync(blockNum int64) (*rollupData, error) {
// TODO: Get createdAccounts from ProcessTxs() // TODO: Get createdAccounts from ProcessTxs()
// TODO: Get CollectedFees from ProcessTxs() // TODO: Get CollectedFees from ProcessTxs()
// TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs() // TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs()
_, exitInfo, err := s.stateDB.ProcessTxs(true, false, batchData.l1UserTxs, batchData.l1CoordinatorTxs, poolL2Txs)
_, exitInfo, err := s.stateDB.ProcessTxs(batchData.l1UserTxs, batchData.l1CoordinatorTxs, poolL2Txs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

+ 1
- 1
synchronizer/synchronizer_test.go

@ -19,7 +19,7 @@ func Test(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := statedb.NewStateDB(dir, true, 32)
sdb, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
assert.Nil(t, err) assert.Nil(t, err)
// Init History DB // Init History DB

+ 3
- 3
txselector/txselector.go

@ -43,7 +43,7 @@ type TxSelector struct {
// NewTxSelector returns a *TxSelector // NewTxSelector returns a *TxSelector
func NewTxSelector(dbpath string, synchronizerStateDB *statedb.StateDB, l2 *l2db.L2DB, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) (*TxSelector, error) { func NewTxSelector(dbpath string, synchronizerStateDB *statedb.StateDB, l2 *l2db.L2DB, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) (*TxSelector, error) {
localAccountsDB, err := statedb.NewLocalStateDB(dbpath, synchronizerStateDB, false, 0) // without merkletree
localAccountsDB, err := statedb.NewLocalStateDB(dbpath, synchronizerStateDB, statedb.TypeTxSelector, 0) // without merkletree
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +89,7 @@ func (txsel *TxSelector) GetL2TxSelection(batchNum common.BatchNum) ([]*common.P
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(false, false, nil, nil, txs)
_, _, err = txsel.localAccountsDB.ProcessTxs(nil, nil, txs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -238,7 +238,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(batchNum common.BatchNum, l1Txs []*c
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(false, false, l1Txs, l1CoordinatorTxs, l2Txs)
_, _, err = txsel.localAccountsDB.ProcessTxs(l1Txs, l1CoordinatorTxs, l2Txs)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

+ 1
- 1
txselector/txselector_test.go

@ -25,7 +25,7 @@ func initTest(t *testing.T, testSet string) *TxSelector {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
sdb, err := statedb.NewStateDB(dir, false, 0)
sdb, err := statedb.NewStateDB(dir, statedb.TypeTxSelector, 0)
require.Nil(t, err) require.Nil(t, err)
txselDir, err := ioutil.TempDir("", "tmpTxSelDB") txselDir, err := ioutil.TempDir("", "tmpTxSelDB")

Loading…
Cancel
Save