@ -3,6 +3,7 @@ package statedb
import (
"errors"
"fmt"
"math/big"
"os"
"os/exec"
"strconv"
@ -29,7 +30,18 @@ var (
ErrToIdxNotFound = errors . New ( "ToIdx can not be found" )
// KeyCurrentBatch is used as key in the db to store the current BatchNum
KeyCurrentBatch = [ ] byte ( "currentbatch" )
KeyCurrentBatch = [ ] byte ( "k:currentbatch" )
// PrefixKeyIdx is the key prefix for idx in the db
PrefixKeyIdx = [ ] byte ( "i:" )
// PrefixKeyAccHash is the key prefix for account hash in the db
PrefixKeyAccHash = [ ] byte ( "h:" )
// PrefixKeyMT is the key prefix for merkle tree in the db
PrefixKeyMT = [ ] byte ( "m:" )
// PrefixKeyAddr is the key prefix for address in the db
PrefixKeyAddr = [ ] byte ( "a:" )
// PrefixKeyAddrBJJ is the key prefix for address-babyjubjub in the db
PrefixKeyAddrBJJ = [ ] byte ( "ab:" )
)
const (
@ -80,7 +92,7 @@ func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
var mt * merkletree . MerkleTree = nil
if typ == TypeSynchronizer || typ == TypeBatchBuilder {
mt , err = merkletree . NewMerkleTree ( sto , nLevels )
mt , err = merkletree . NewMerkleTree ( sto . WithPrefix ( PrefixKeyMT ) , nLevels )
if err != nil {
return nil , err
}
@ -236,7 +248,7 @@ func (s *StateDB) Reset(batchNum common.BatchNum) error {
if s . mt != nil {
// open the MT for the current s.db
mt , err := merkletree . NewMerkleTree ( s . db , s . mt . MaxLevels ( ) )
mt , err := merkletree . NewMerkleTree ( s . db . WithPrefix ( PrefixKeyMT ) , s . mt . MaxLevels ( ) )
if err != nil {
return err
}
@ -251,6 +263,35 @@ func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
return getAccountInTreeDB ( s . db , idx )
}
// GetAccounts returns all the accounts in the db. Use for debugging pruposes
// only.
func ( s * StateDB ) GetAccounts ( ) ( [ ] common . Account , error ) {
idxDB := s . db . WithPrefix ( PrefixKeyIdx )
idxs := [ ] common . Idx { }
// NOTE: Current implementation of Iterate in the pebble interface is
// not efficient, as it iterates over all keys. Improve it following
// this example: https://github.com/cockroachdb/pebble/pull/923/files
if err := idxDB . Iterate ( func ( k [ ] byte , v [ ] byte ) ( bool , error ) {
idx , err := common . IdxFromBytes ( k )
if err != nil {
return false , err
}
idxs = append ( idxs , idx )
return true , nil
} ) ; err != nil {
return nil , err
}
accs := [ ] common . Account { }
for i := range idxs {
acc , err := s . GetAccount ( idxs [ i ] )
if err != nil {
return nil , err
}
accs = append ( accs , * acc )
}
return accs , nil
}
// getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
// from ExitTree. GetAccount returns the account for the given Idx
func getAccountInTreeDB ( sto db . Storage , idx common . Idx ) ( * common . Account , error ) {
@ -258,17 +299,22 @@ func getAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error)
if err != nil {
return nil , err
}
vBytes , err := sto . Get ( idxBytes [ : ] )
vBytes , err := sto . Get ( append ( PrefixKeyIdx , idxBytes [ : ] ... ) )
if err != nil {
return nil , err
}
accBytes , err := sto . Get ( vBytes )
accBytes , err := sto . Get ( append ( PrefixKeyAccHash , vBytes ... ) )
if err != nil {
return nil , err
}
var b [ 32 * common . NLeafElems ] byte
copy ( b [ : ] , accBytes )
return common . AccountFromBytes ( b )
account , err := common . AccountFromBytes ( b )
if err != nil {
return nil , err
}
account . Idx = idx
return account , nil
}
// CreateAccount creates a new Account in the StateDB for the given Idx. If
@ -309,16 +355,16 @@ func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common
if err != nil {
return nil , err
}
_ , err = tx . Get ( idxBytes [ : ] )
_ , err = tx . Get ( append ( PrefixKeyIdx , idxBytes [ : ] ... ) )
if err != db . ErrNotFound {
return nil , ErrAccountAlreadyExists
}
err = tx . Put ( v . Bytes ( ) , accountBytes [ : ] )
err = tx . Put ( append ( PrefixKeyAccHash , v . Bytes ( ) ... ) , accountBytes [ : ] )
if err != nil {
return nil , err
}
err = tx . Put ( idxBytes [ : ] , v . Bytes ( ) )
err = tx . Put ( append ( PrefixKeyIdx , idxBytes [ : ] ... ) , v . Bytes ( ) )
if err != nil {
return nil , err
}
@ -360,7 +406,7 @@ func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common
if err != nil {
return nil , err
}
err = tx . Put ( v . Bytes ( ) , accountBytes [ : ] )
err = tx . Put ( append ( PrefixKeyAccHash , v . Bytes ( ) ... ) , accountBytes [ : ] )
if err != nil {
return nil , err
}
@ -368,7 +414,7 @@ func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common
if err != nil {
return nil , err
}
err = tx . Put ( idxBytes [ : ] , v . Bytes ( ) )
err = tx . Put ( append ( PrefixKeyIdx , idxBytes [ : ] ... ) , v . Bytes ( ) )
if err != nil {
return nil , err
}
@ -391,6 +437,11 @@ func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, e
return s . mt . GenerateCircomVerifierProof ( idx . BigInt ( ) , s . mt . Root ( ) )
}
// MTGetRoot returns the current root of the underlying Merkle Tree
func ( s * StateDB ) MTGetRoot ( ) * big . Int {
return s . mt . Root ( ) . BigInt ( )
}
// LocalStateDB represents the local StateDB which allows to make copies from
// the synchronizer StateDB, and is used by the tx-selector and the
// batch-builder. LocalStateDB is an in-memory storage.
@ -462,7 +513,7 @@ func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) er
return err
}
// open the MT for the current s.db
mt , err := merkletree . NewMerkleTree ( l . db , l . mt . MaxLevels ( ) )
mt , err := merkletree . NewMerkleTree ( l . db . WithPrefix ( PrefixKeyMT ) , l . mt . MaxLevels ( ) )
if err != nil {
return err
}