arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/statedb/statedb.go
db/statedb/statedb.goRaw
  1package statedb
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"math/big"
  7
  8	"github.com/hermeznetwork/hermez-node/common"
  9	"github.com/hermeznetwork/hermez-node/db/kvdb"
 10	"github.com/hermeznetwork/hermez-node/log"
 11	"github.com/hermeznetwork/tracerr"
 12	"github.com/iden3/go-merkletree"
 13	"github.com/iden3/go-merkletree/db"
 14	"github.com/iden3/go-merkletree/db/pebble"
 15)
 16
 17var (
 18	// ErrStateDBWithoutMT is used when a method that requires a MerkleTree
 19	// is called in a StateDB that does not have a MerkleTree defined
 20	ErrStateDBWithoutMT = errors.New(
 21		"Can not call method to use MerkleTree in a StateDB without MerkleTree")
 22
 23	// ErrAccountAlreadyExists is used when CreateAccount is called and the
 24	// Account already exists
 25	ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
 26
 27	// ErrIdxNotFound is used when trying to get the Idx from EthAddr or
 28	// EthAddr&ToBJJ
 29	ErrIdxNotFound = errors.New("Idx can not be found")
 30	// ErrGetIdxNoCase is used when trying to get the Idx from EthAddr &
 31	// BJJ with not compatible combination
 32	ErrGetIdxNoCase = errors.New(
 33		"Can not get Idx due unexpected combination of ethereum Address & BabyJubJub PublicKey")
 34
 35	// PrefixKeyIdx is the key prefix for idx in the db
 36	PrefixKeyIdx = []byte("i:")
 37	// PrefixKeyAccHash is the key prefix for account hash in the db
 38	PrefixKeyAccHash = []byte("h:")
 39	// PrefixKeyMT is the key prefix for merkle tree in the db
 40	PrefixKeyMT = []byte("m:")
 41	// PrefixKeyAddr is the key prefix for address in the db
 42	PrefixKeyAddr = []byte("a:")
 43	// PrefixKeyAddrBJJ is the key prefix for address-babyjubjub in the db
 44	PrefixKeyAddrBJJ = []byte("ab:")
 45)
 46
 47const (
 48	// TypeSynchronizer defines a StateDB used by the Synchronizer, that
 49	// generates the ExitTree when processing the txs
 50	TypeSynchronizer = "synchronizer"
 51	// TypeTxSelector defines a StateDB used by the TxSelector, without
 52	// computing ExitTree neither the ZKInputs
 53	TypeTxSelector = "txselector"
 54	// TypeBatchBuilder defines a StateDB used by the BatchBuilder, that
 55	// generates the ExitTree and the ZKInput when processing the txs
 56	TypeBatchBuilder = "batchbuilder"
 57	// MaxNLevels is the maximum value of NLevels for the merkle tree,
 58	// which comes from the fact that AccountIdx has 48 bits.
 59	MaxNLevels = 48
 60)
 61
 62// TypeStateDB determines the type of StateDB
 63type TypeStateDB string
 64
 65// Config of the StateDB
 66type Config struct {
 67	// Path where the checkpoints will be stored
 68	Path string
 69	// Keep is the number of old checkpoints to keep.  If 0, all
 70	// checkpoints are kept.
 71	Keep int
 72	// NoLast skips having an opened DB with a checkpoint to the last
 73	// batchNum for thread-safe reads.
 74	NoLast bool
 75	// Type of StateDB (
 76	Type TypeStateDB
 77	// NLevels is the number of merkle tree levels in case the Type uses a
 78	// merkle tree.  If the Type doesn't use a merkle tree, NLevels should
 79	// be 0.
 80	NLevels int
 81	// At every checkpoint, check that there are no gaps between the
 82	// checkpoints
 83	noGapsCheck bool
 84}
 85
 86// StateDB represents the StateDB object
 87type StateDB struct {
 88	cfg Config
 89	db  *kvdb.KVDB
 90	MT  *merkletree.MerkleTree
 91}
 92
 93// Last offers a subset of view methods of the StateDB that can be
 94// called via the LastRead method of StateDB in a thread-safe manner to obtain
 95// a consistent view to the last batch of the StateDB.
 96type Last struct {
 97	db db.Storage
 98}
 99
100// GetAccount returns the account for the given Idx
101func (s *Last) GetAccount(idx common.Idx) (*common.Account, error) {
102	return GetAccountInTreeDB(s.db, idx)
103}
104
105// GetCurrentBatch returns the current BatchNum stored in Last.db
106func (s *Last) GetCurrentBatch() (common.BatchNum, error) {
107	cbBytes, err := s.db.Get(kvdb.KeyCurrentBatch)
108	if tracerr.Unwrap(err) == db.ErrNotFound {
109		return 0, nil
110	} else if err != nil {
111		return 0, tracerr.Wrap(err)
112	}
113	return common.BatchNumFromBytes(cbBytes)
114}
115
116// DB returns the underlying storage of Last
117func (s *Last) DB() db.Storage {
118	return s.db
119}
120
121// GetAccounts returns all the accounts in the db.  Use for debugging pruposes
122// only.
123func (s *Last) GetAccounts() ([]common.Account, error) {
124	return getAccounts(s.db)
125}
126
127// NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
128// storage.  Checkpoints older than the value defined by `keep` will be
129// deleted.
130// func NewStateDB(pathDB string, keep int, typ TypeStateDB, nLevels int) (*StateDB, error) {
131func NewStateDB(cfg Config) (*StateDB, error) {
132	var kv *kvdb.KVDB
133	var err error
134
135	kv, err = kvdb.NewKVDB(kvdb.Config{Path: cfg.Path, Keep: cfg.Keep,
136		NoGapsCheck: cfg.noGapsCheck, NoLast: cfg.NoLast})
137	if err != nil {
138		return nil, tracerr.Wrap(err)
139	}
140
141	var mt *merkletree.MerkleTree = nil
142	if cfg.Type == TypeSynchronizer || cfg.Type == TypeBatchBuilder {
143		mt, err = merkletree.NewMerkleTree(kv.StorageWithPrefix(PrefixKeyMT), cfg.NLevels)
144		if err != nil {
145			return nil, tracerr.Wrap(err)
146		}
147	}
148	if cfg.Type == TypeTxSelector && cfg.NLevels != 0 {
149		return nil, tracerr.Wrap(
150			fmt.Errorf("invalid StateDB parameters: StateDB type==TypeStateDB can not have nLevels!=0"))
151	}
152
153	return &StateDB{
154		cfg: cfg,
155		db:  kv,
156		MT:  mt,
157	}, nil
158}
159
160// Type returns the StateDB configured Type
161func (s *StateDB) Type() TypeStateDB {
162	return s.cfg.Type
163}
164
165// LastRead is a thread-safe method to query the last checkpoint of the StateDB
166// via the Last type methods
167func (s *StateDB) LastRead(fn func(sdbLast *Last) error) error {
168	return s.db.LastRead(
169		func(db *pebble.Storage) error {
170			return fn(&Last{
171				db: db,
172			})
173		},
174	)
175}
176
177// LastGetAccount is a thread-safe method to query an account in the last
178// checkpoint of the StateDB.
179func (s *StateDB) LastGetAccount(idx common.Idx) (*common.Account, error) {
180	var account *common.Account
181	if err := s.LastRead(func(sdb *Last) error {
182		var err error
183		account, err = sdb.GetAccount(idx)
184		return err
185	}); err != nil {
186		return nil, tracerr.Wrap(err)
187	}
188	return account, nil
189}
190
191// LastGetCurrentBatch is a thread-safe method to get the current BatchNum in
192// the last checkpoint of the StateDB.
193func (s *StateDB) LastGetCurrentBatch() (common.BatchNum, error) {
194	var batchNum common.BatchNum
195	if err := s.LastRead(func(sdb *Last) error {
196		var err error
197		batchNum, err = sdb.GetCurrentBatch()
198		return err
199	}); err != nil {
200		return 0, tracerr.Wrap(err)
201	}
202	return batchNum, nil
203}
204
205// LastMTGetRoot returns the root of the underlying Merkle Tree in the last
206// checkpoint of the StateDB.
207func (s *StateDB) LastMTGetRoot() (*big.Int, error) {
208	var root *big.Int
209	if err := s.LastRead(func(sdb *Last) error {
210		mt, err := merkletree.NewMerkleTree(sdb.DB().WithPrefix(PrefixKeyMT), s.cfg.NLevels)
211		if err != nil {
212			return tracerr.Wrap(err)
213		}
214		root = mt.Root().BigInt()
215		return nil
216	}); err != nil {
217		return nil, tracerr.Wrap(err)
218	}
219	return root, nil
220}
221
222// MakeCheckpoint does a checkpoint at the given batchNum in the defined path.
223// Internally this advances & stores the current BatchNum, and then stores a
224// Checkpoint of the current state of the StateDB.
225func (s *StateDB) MakeCheckpoint() error {
226	log.Debugw("Making StateDB checkpoint", "batch", s.CurrentBatch()+1, "type", s.cfg.Type)
227	return s.db.MakeCheckpoint()
228}
229
230// CurrentBatch returns the current in-memory CurrentBatch of the StateDB.db
231func (s *StateDB) CurrentBatch() common.BatchNum {
232	return s.db.CurrentBatch
233}
234
235// CurrentIdx returns the current in-memory CurrentIdx of the StateDB.db
236func (s *StateDB) CurrentIdx() common.Idx {
237	return s.db.CurrentIdx
238}
239
240// getCurrentBatch returns the current BatchNum stored in the StateDB.db
241func (s *StateDB) getCurrentBatch() (common.BatchNum, error) {
242	return s.db.GetCurrentBatch()
243}
244
245// GetCurrentIdx returns the stored Idx from the localStateDB, which is the
246// last Idx used for an Account in the localStateDB.
247func (s *StateDB) GetCurrentIdx() (common.Idx, error) {
248	return s.db.GetCurrentIdx()
249}
250
251// SetCurrentIdx stores Idx in the StateDB
252func (s *StateDB) SetCurrentIdx(idx common.Idx) error {
253	return s.db.SetCurrentIdx(idx)
254}
255
256// Reset resets the StateDB to the checkpoint at the given batchNum. Reset
257// does not delete the checkpoints between old current and the new current,
258// those checkpoints will remain in the storage, and eventually will be
259// deleted when MakeCheckpoint overwrites them.
260func (s *StateDB) Reset(batchNum common.BatchNum) error {
261	log.Debugw("Making StateDB Reset", "batch", batchNum, "type", s.cfg.Type)
262	if err := s.db.Reset(batchNum); err != nil {
263		return tracerr.Wrap(err)
264	}
265	if s.MT != nil {
266		// open the MT for the current s.db
267		mt, err := merkletree.NewMerkleTree(s.db.StorageWithPrefix(PrefixKeyMT), s.MT.MaxLevels())
268		if err != nil {
269			return tracerr.Wrap(err)
270		}
271		s.MT = mt
272	}
273	return nil
274}
275
276// GetAccount returns the account for the given Idx
277func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
278	return GetAccountInTreeDB(s.db.DB(), idx)
279}
280
281func accountsIter(db db.Storage, fn func(a *common.Account) (bool, error)) error {
282	idxDB := db.WithPrefix(PrefixKeyIdx)
283	if err := idxDB.Iterate(func(k []byte, v []byte) (bool, error) {
284		idx, err := common.IdxFromBytes(k)
285		if err != nil {
286			return false, tracerr.Wrap(err)
287		}
288		acc, err := GetAccountInTreeDB(db, idx)
289		if err != nil {
290			return false, tracerr.Wrap(err)
291		}
292		ok, err := fn(acc)
293		if err != nil {
294			return false, tracerr.Wrap(err)
295		}
296		return ok, nil
297	}); err != nil {
298		return tracerr.Wrap(err)
299	}
300	return nil
301}
302
303func getAccounts(db db.Storage) ([]common.Account, error) {
304	accs := []common.Account{}
305	if err := accountsIter(
306		db,
307		func(a *common.Account) (bool, error) {
308			accs = append(accs, *a)
309			return true, nil
310		},
311	); err != nil {
312		return nil, tracerr.Wrap(err)
313	}
314	return accs, nil
315}
316
317// TestGetAccounts returns all the accounts in the db.  Use only in tests.
318// Outside tests getting all the accounts is discouraged because it's an
319// expensive operation, but if you must do it, use `LastRead()` method to get a
320// thread-safe and consistent view of the stateDB.
321func (s *StateDB) TestGetAccounts() ([]common.Account, error) {
322	return getAccounts(s.db.DB())
323}
324
325// GetAccountInTreeDB is abstracted from StateDB to be used from StateDB and
326// from ExitTree.  GetAccount returns the account for the given Idx
327func GetAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
328	idxBytes, err := idx.Bytes()
329	if err != nil {
330		return nil, tracerr.Wrap(err)
331	}
332	vBytes, err := sto.Get(append(PrefixKeyIdx, idxBytes[:]...))
333	if err != nil {
334		return nil, tracerr.Wrap(err)
335	}
336	accBytes, err := sto.Get(append(PrefixKeyAccHash, vBytes...))
337	if err != nil {
338		return nil, tracerr.Wrap(err)
339	}
340	var b [32 * common.NLeafElems]byte
341	copy(b[:], accBytes)
342	account, err := common.AccountFromBytes(b)
343	if err != nil {
344		return nil, tracerr.Wrap(err)
345	}
346	account.Idx = idx
347	return account, nil
348}
349
350// CreateAccount creates a new Account in the StateDB for the given Idx.  If
351// StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
352// MerkleTree, returning a CircomProcessorProof.
353func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (
354	*merkletree.CircomProcessorProof, error) {
355	cpp, err := CreateAccountInTreeDB(s.db.DB(), s.MT, idx, account)
356	if err != nil {
357		return cpp, tracerr.Wrap(err)
358	}
359	// store idx by EthAddr & BJJ
360	err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.BJJ, account.TokenID)
361	return cpp, tracerr.Wrap(err)
362}
363
364// CreateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
365// from ExitTree.  Creates a new Account in the StateDB for the given Idx.  If
366// StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
367// MerkleTree, returning a CircomProcessorProof.
368func CreateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx,
369	account *common.Account) (*merkletree.CircomProcessorProof, error) {
370	// store at the DB the key: v, and value: leaf.Bytes()
371	v, err := account.HashValue()
372	if err != nil {
373		return nil, tracerr.Wrap(err)
374	}
375	accountBytes, err := account.Bytes()
376	if err != nil {
377		return nil, tracerr.Wrap(err)
378	}
379
380	// store the Leaf value
381	tx, err := sto.NewTx()
382	if err != nil {
383		return nil, tracerr.Wrap(err)
384	}
385
386	idxBytes, err := idx.Bytes()
387	if err != nil {
388		return nil, tracerr.Wrap(err)
389	}
390	_, err = tx.Get(append(PrefixKeyIdx, idxBytes[:]...))
391	if tracerr.Unwrap(err) != db.ErrNotFound {
392		return nil, tracerr.Wrap(ErrAccountAlreadyExists)
393	}
394
395	err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
396	if err != nil {
397		return nil, tracerr.Wrap(err)
398	}
399	err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
400	if err != nil {
401		return nil, tracerr.Wrap(err)
402	}
403
404	if err := tx.Commit(); err != nil {
405		return nil, tracerr.Wrap(err)
406	}
407
408	if mt != nil {
409		return mt.AddAndGetCircomProof(idx.BigInt(), v)
410	}
411
412	return nil, nil
413}
414
415// UpdateAccount updates the Account in the StateDB for the given Idx.  If
416// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
417// MerkleTree, returning a CircomProcessorProof.
418func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (
419	*merkletree.CircomProcessorProof, error) {
420	return UpdateAccountInTreeDB(s.db.DB(), s.MT, idx, account)
421}
422
423// UpdateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
424// from ExitTree.  Updates the Account in the StateDB for the given Idx.  If
425// StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
426// MerkleTree, returning a CircomProcessorProof.
427func UpdateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx,
428	account *common.Account) (*merkletree.CircomProcessorProof, error) {
429	// store at the DB the key: v, and value: account.Bytes()
430	v, err := account.HashValue()
431	if err != nil {
432		return nil, tracerr.Wrap(err)
433	}
434	accountBytes, err := account.Bytes()
435	if err != nil {
436		return nil, tracerr.Wrap(err)
437	}
438
439	tx, err := sto.NewTx()
440	if err != nil {
441		return nil, tracerr.Wrap(err)
442	}
443	err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
444	if err != nil {
445		return nil, tracerr.Wrap(err)
446	}
447	idxBytes, err := idx.Bytes()
448	if err != nil {
449		return nil, tracerr.Wrap(err)
450	}
451	err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
452	if err != nil {
453		return nil, tracerr.Wrap(err)
454	}
455
456	if err := tx.Commit(); err != nil {
457		return nil, tracerr.Wrap(err)
458	}
459
460	if mt != nil {
461		proof, err := mt.Update(idx.BigInt(), v)
462		return proof, tracerr.Wrap(err)
463	}
464	return nil, nil
465}
466
467// MTGetProof returns the CircomVerifierProof for a given Idx
468func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
469	if s.MT == nil {
470		return nil, tracerr.Wrap(ErrStateDBWithoutMT)
471	}
472	p, err := s.MT.GenerateSCVerifierProof(idx.BigInt(), s.MT.Root())
473	if err != nil {
474		return nil, tracerr.Wrap(err)
475	}
476	return p, nil
477}
478
479// Close the StateDB
480func (s *StateDB) Close() {
481	s.db.Close()
482}
483
484// LocalStateDB represents the local StateDB which allows to make copies from
485// the synchronizer StateDB, and is used by the tx-selector and the
486// batch-builder. LocalStateDB is an in-memory storage.
487type LocalStateDB struct {
488	*StateDB
489	synchronizerStateDB *StateDB
490}
491
492// NewLocalStateDB returns a new LocalStateDB connected to the given
493// synchronizerDB.  Checkpoints older than the value defined by `keep` will be
494// deleted.
495func NewLocalStateDB(cfg Config, synchronizerDB *StateDB) (*LocalStateDB, error) {
496	cfg.noGapsCheck = true
497	cfg.NoLast = true
498	s, err := NewStateDB(cfg)
499	if err != nil {
500		return nil, tracerr.Wrap(err)
501	}
502	return &LocalStateDB{
503		s,
504		synchronizerDB,
505	}, nil
506}
507
508// CheckpointExists returns true if the checkpoint exists
509func (l *LocalStateDB) CheckpointExists(batchNum common.BatchNum) (bool, error) {
510	return l.db.CheckpointExists(batchNum)
511}
512
513// Reset performs a reset in the LocalStateDB. If fromSynchronizer is true, it
514// gets the state from LocalStateDB.synchronizerStateDB for the given batchNum.
515// If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
516func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
517	if fromSynchronizer {
518		log.Debugw("Making StateDB ResetFromSynchronizer", "batch", batchNum, "type", l.cfg.Type)
519		if err := l.db.ResetFromSynchronizer(batchNum, l.synchronizerStateDB.db); err != nil {
520			return tracerr.Wrap(err)
521		}
522		// open the MT for the current s.db
523		if l.MT != nil {
524			mt, err := merkletree.NewMerkleTree(l.db.StorageWithPrefix(PrefixKeyMT),
525				l.MT.MaxLevels())
526			if err != nil {
527				return tracerr.Wrap(err)
528			}
529			l.MT = mt
530		}
531		return nil
532	}
533	// use checkpoint from LocalStateDB
534	return l.StateDB.Reset(batchNum)
535}