Update BatchBuilder & TxSelector to new StateDB
arnaucube root@arnaucube.com
Mon, 17 Aug 2020 11:39:51 +0200
7 files changed,
81 insertions(+),
31 deletions(-)
M
batchbuilder/batchbuilder.go
→
batchbuilder/batchbuilder.go
@@ -1,12 +1,17 @@
package batchbuilder import ( + "encoding/binary" "math/big" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/db/statedb" + "github.com/iden3/go-merkletree/db" ) + +// KEYIDX is used as key in the db to store the current Idx +var KEYIDX = []byte("idx") // ConfigCircuit contains the circuit configuration type ConfigCircuit struct {@@ -31,14 +36,13 @@ }
// NewBatchBuilder constructs a new BatchBuilder, and executes the bb.Reset // method -func NewBatchBuilder(synchronizerStateDB *statedb.StateDB, configCircuits []ConfigCircuit, batchNum uint64, idx, nLevels uint64) (*BatchBuilder, error) { - localStateDB, err := statedb.NewLocalStateDB(synchronizerStateDB, true, int(nLevels)) +func NewBatchBuilder(dbpath string, synchronizerStateDB *statedb.StateDB, configCircuits []ConfigCircuit, batchNum uint64, nLevels uint64) (*BatchBuilder, error) { + localStateDB, err := statedb.NewLocalStateDB(dbpath, synchronizerStateDB, true, int(nLevels)) if err != nil { return nil, err } bb := BatchBuilder{ - idx: idx, localStateDB: localStateDB, configCircuits: configCircuits, }@@ -52,12 +56,17 @@ // `batchNum`. If `fromSynchronizer` is true, the BatchBuilder must take a
// copy of the rollup state from the Synchronizer at that `batchNum`, otherwise // it can just roll back the internal copy. func (bb *BatchBuilder) Reset(batchNum uint64, fromSynchronizer bool) error { + if batchNum == 0 { + bb.idx = 0 + return nil + } err := bb.localStateDB.Reset(batchNum, fromSynchronizer) if err != nil { return err } - // bb.idx = idx // TODO idx will be obtained from the statedb reset - return nil + // idx is obtained from the statedb reset + bb.idx, err = bb.getIdx() + return err } // BuildBatch takes the transactions and returns the common.ZKInputs of the next batch@@ -139,8 +148,8 @@
return nil } -// applyCreateAccount creates a new account in the account of the depositer, it stores -// the deposit value +// applyCreateAccount creates a new account in the account of the depositer, it +// stores the deposit value func (bb *BatchBuilder) applyCreateAccount(tx common.L1Tx) error { account := &common.Account{ TokenID: tx.TokenID,@@ -156,7 +165,7 @@ return err
} bb.idx = bb.idx + 1 - return nil + return bb.setIdx(bb.idx) } // applyDeposit updates the balance in the account of the depositer, if@@ -225,3 +234,31 @@ }
return nil } + +// getIdx returns the stored Idx from the localStateDB, which is the last Idx used for an Account in the localStateDB. +func (bb *BatchBuilder) getIdx() (uint64, error) { + idxBytes, err := bb.localStateDB.DB().Get(KEYIDX) + if err == db.ErrNotFound { + return 0, nil + } + if err != nil { + return 0, err + } + idx := binary.LittleEndian.Uint64(idxBytes[:8]) + return idx, nil +} + +// setIdx stores Idx in the localStateDB +func (bb *BatchBuilder) setIdx(idx uint64) error { + tx, err := bb.localStateDB.DB().NewTx() + if err != nil { + return err + } + var idxBytes [8]byte + binary.LittleEndian.PutUint64(idxBytes[:], idx) + tx.Put(KEYIDX, idxBytes[:]) + if err := tx.Commit(); err != nil { + return err + } + return nil +}
M
batchbuilder/batchbuilder_test.go
→
batchbuilder/batchbuilder_test.go
@@ -14,10 +14,12 @@ func TestBatchBuilder(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") require.Nil(t, err) - synchDB, err := statedb.NewStateDB(dir, false, false, 0) + synchDB, err := statedb.NewStateDB(dir, false, 0) assert.Nil(t, err) - bb, err := NewBatchBuilder(synchDB, nil, 0, 0, 32) + bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB") + require.Nil(t, err) + bb, err := NewBatchBuilder(bbDir, synchDB, nil, 0, 32) assert.Nil(t, err) fmt.Println(bb) }
M
db/statedb/statedb.go
→
db/statedb/statedb.go
@@ -23,8 +23,10 @@
// KEYCURRENTBATCH is used as key in the db to store the current BatchNum var KEYCURRENTBATCH = []byte("currentbatch") -// STATEDBPATH defines the subpath of the StateDB -const STATEDBPATH = "/statedb" +// PATHSTATEDB defines the subpath of the StateDB +const PATHSTATEDB = "/statedb" +const PATHBATCHNUM = "/BatchNum" +const PATHCURRENT = "/current" // StateDB represents the StateDB object type StateDB struct {@@ -39,7 +41,7 @@ // storage
func NewStateDB(path string, withMT bool, nLevels int) (*StateDB, error) { var sto *pebble.PebbleStorage var err error - sto, err = pebble.NewPebbleStorage(path+STATEDBPATH+"/current", false) + sto, err = pebble.NewPebbleStorage(path+PATHSTATEDB+PATHCURRENT, false) if err != nil { return nil, err }@@ -53,7 +55,7 @@ }
} sdb := &StateDB{ - path: path + STATEDBPATH, + path: path + PATHSTATEDB, db: sto, mt: mt, }@@ -100,14 +102,17 @@ }
return nil } -// CheckPointAt does a checkpoint at the given batchNum in the defined path +// MakeCheckpoint does a checkpoint at the given batchNum in the defined path. Internally this advances & stores the current BatchNum, and then stores a Checkpoint of the current state of the StateDB. func (s *StateDB) MakeCheckpoint() error { // advance currentBatch s.currentBatch++ - checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(s.currentBatch)) + checkpointPath := s.path + PATHBATCHNUM + strconv.Itoa(int(s.currentBatch)) - s.setCurrentBatch() + err := s.setCurrentBatch() + if err != nil { + return err + } // if checkpoint BatchNum already exist in disk, delete it if _, err := os.Stat(checkpointPath); !os.IsNotExist(err) {@@ -118,7 +123,7 @@ }
} // execute Checkpoint - err := s.db.Pebble().Checkpoint(checkpointPath) + err = s.db.Pebble().Checkpoint(checkpointPath) if err != nil { return err }@@ -128,7 +133,7 @@ }
// DeleteCheckpoint removes if exist the checkpoint of the given batchNum func (s *StateDB) DeleteCheckpoint(batchNum uint64) error { - checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(batchNum)) + checkpointPath := s.path + PATHBATCHNUM + strconv.Itoa(int(batchNum)) if _, err := os.Stat(checkpointPath); os.IsNotExist(err) { return fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum)@@ -142,8 +147,8 @@ // does not delete the checkpoints between old current and the new current,
// those checkpoints will remain in the storage, and eventually will be // deleted when MakeCheckpoint overwrites them. func (s *StateDB) Reset(batchNum uint64) error { - checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(batchNum)) - currentPath := s.path + "/current" + checkpointPath := s.path + PATHBATCHNUM + strconv.Itoa(int(batchNum)) + currentPath := s.path + PATHCURRENT // remove 'current' err := os.RemoveAll(currentPath)@@ -311,9 +316,9 @@ // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
// gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints. func (l *LocalStateDB) Reset(batchNum uint64, fromSynchronizer bool) error { - synchronizerCheckpointPath := l.synchronizerStateDB.path + "/BatchNum" + strconv.Itoa(int(batchNum)) - checkpointPath := l.path + "/BatchNum" + strconv.Itoa(int(batchNum)) - currentPath := l.path + "/current" + synchronizerCheckpointPath := l.synchronizerStateDB.path + PATHBATCHNUM + strconv.Itoa(int(batchNum)) + checkpointPath := l.path + PATHBATCHNUM + strconv.Itoa(int(batchNum)) + currentPath := l.path + PATHCURRENT if fromSynchronizer { // use checkpoint from SynchronizerStateDB
M
db/statedb/statedb_test.go
→
db/statedb/statedb_test.go
@@ -251,9 +251,12 @@ cb, err = ldb2.GetCurrentBatch()
assert.Nil(t, err) assert.Equal(t, uint64(5), cb) - // printCheckpoints(t, sdb.path) - // printCheckpoints(t, ldb.path) - // printCheckpoints(t, ldb2.path) + debug := false + if debug { + printCheckpoints(t, sdb.path) + printCheckpoints(t, ldb.path) + printCheckpoints(t, ldb2.path) + } } func printCheckpoints(t *testing.T, path string) {
M
go.mod
→
go.mod
@@ -6,6 +6,7 @@ require (
github.com/dghubble/sling v1.3.0 github.com/ethereum/go-ethereum v1.9.17 github.com/gobuffalo/packr/v2 v2.8.0 + github.com/iden3/go-iden3-core v0.0.8 github.com/iden3/go-iden3-crypto v0.0.6-0.20200806115047-327a8175d6eb github.com/iden3/go-merkletree v0.0.0-20200815144208-1f1bd54b93ae github.com/jinzhu/gorm v1.9.15
M
txselector/txselector.go
→
txselector/txselector.go
@@ -35,8 +35,8 @@ localAccountsDB *statedb.LocalStateDB
} // NewTxSelector returns a *TxSelector -func NewTxSelector(synchronizerStateDB *statedb.StateDB, l2 *l2db.L2DB, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) (*TxSelector, error) { - localAccountsDB, err := statedb.NewLocalStateDB(synchronizerStateDB, false, 0) // without merkletree +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 if err != nil { return nil, err }
M
txselector/txselector_test.go
→
txselector/txselector_test.go
@@ -104,12 +104,14 @@
func TestGetL2TxSelection(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.Nil(t, err) - sdb, err := statedb.NewStateDB(dir, false, false, 0) + sdb, err := statedb.NewStateDB(dir, false, 0) assert.Nil(t, err) testL2DB := &l2db.L2DB{} // initTestDB(testL2DB, sdb) - txsel, err := NewTxSelector(sdb, testL2DB, 3, 3, 3) + txselDir, err := ioutil.TempDir("", "tmpTxSelDB") + require.Nil(t, err) + txsel, err := NewTxSelector(txselDir, sdb, testL2DB, 3, 3, 3) assert.Nil(t, err) fmt.Println(txsel)