arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/statedb/statedb.go
db/statedb/statedb.goRaw
  1package statedb
  2
  3import (
  4	"errors"
  5
  6	"github.com/hermeznetwork/hermez-node/common"
  7	"github.com/iden3/go-merkletree"
  8	"github.com/iden3/go-merkletree/db"
  9	"github.com/iden3/go-merkletree/db/leveldb"
 10	"github.com/iden3/go-merkletree/db/memory"
 11)
 12
 13// ErrStateDBWithoutMT is used when a method that requires a MerkleTree is called in a StateDB that does not have a MerkleTree defined
 14var ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
 15
 16// ErrAccountAlreadyExists is used when CreateAccount is called and the Account already exists
 17var ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
 18
 19// StateDB represents the StateDB object
 20type StateDB struct {
 21	db db.Storage
 22	mt *merkletree.MerkleTree
 23}
 24
 25// NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
 26// storage
 27func NewStateDB(path string, inDisk bool, withMT bool, nLevels int) (*StateDB, error) {
 28	var sto db.Storage
 29	var err error
 30	if inDisk {
 31		sto, err = leveldb.NewLevelDbStorage(path, false)
 32		if err != nil {
 33			return nil, err
 34		}
 35	} else {
 36		sto = memory.NewMemoryStorage()
 37	}
 38	var mt *merkletree.MerkleTree = nil
 39	if withMT {
 40		mt, err = merkletree.NewMerkleTree(sto, nLevels)
 41		if err != nil {
 42			return nil, err
 43		}
 44	}
 45
 46	return &StateDB{
 47		db: sto,
 48		mt: mt,
 49	}, nil
 50}
 51
 52// CheckPointAt does a checkpoint at the given batchNum in the defined path
 53func (s *StateDB) CheckPointAt(batchNum uint64, path string) error {
 54	// TODO
 55
 56	return nil
 57}
 58
 59// Reset resets the StateDB to the checkpoint at the given batchNum
 60func (s *StateDB) Reset(batchNum uint64) error {
 61	// TODO
 62
 63	return nil
 64}
 65
 66// Checkpoints returns a list of the checkpoints (batchNums)
 67func (s *StateDB) Checkpoints() ([]uint64, error) {
 68	// TODO
 69
 70	//batchnums, err
 71	return nil, nil
 72}
 73
 74// GetAccount returns the account for the given Idx
 75func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
 76	vBytes, err := s.db.Get(idx.Bytes())
 77	if err != nil {
 78		return nil, err
 79	}
 80	accBytes, err := s.db.Get(vBytes)
 81	if err != nil {
 82		return nil, err
 83	}
 84	var b [32 * common.NLEAFELEMS]byte
 85	copy(b[:], accBytes)
 86	return common.AccountFromBytes(b)
 87}
 88
 89// CreateAccount creates a new Account in the StateDB for the given Idx.
 90// MerkleTree is not affected.
 91func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) error {
 92	// store at the DB the key: v, and value: leaf.Bytes()
 93	v, err := account.HashValue()
 94	if err != nil {
 95		return err
 96	}
 97	accountBytes, err := account.Bytes()
 98	if err != nil {
 99		return err
100	}
101
102	// store the Leaf value
103	tx, err := s.db.NewTx()
104	if err != nil {
105		return err
106	}
107
108	_, err = tx.Get(idx.Bytes())
109	if err != db.ErrNotFound {
110		return ErrAccountAlreadyExists
111	}
112
113	tx.Put(v.Bytes(), accountBytes[:])
114	tx.Put(idx.Bytes(), v.Bytes())
115
116	return tx.Commit()
117}
118
119// UpdateAccount updates the Account in the StateDB for the given Idx.
120// MerkleTree is not affected.
121func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) error {
122	// store at the DB the key: v, and value: leaf.Bytes()
123	v, err := account.HashValue()
124	if err != nil {
125		return err
126	}
127	accountBytes, err := account.Bytes()
128	if err != nil {
129		return err
130	}
131
132	tx, err := s.db.NewTx()
133	if err != nil {
134		return err
135	}
136	tx.Put(v.Bytes(), accountBytes[:])
137	tx.Put(idx.Bytes(), v.Bytes())
138
139	return tx.Commit()
140}
141
142// MTCreateAccount creates a new Account in the StateDB for the given Idx,
143// and updates the MerkleTree, returning a CircomProcessorProof
144func (s *StateDB) MTCreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
145	if s.mt == nil {
146		return nil, ErrStateDBWithoutMT
147	}
148	err := s.CreateAccount(idx, account)
149	if err != nil {
150		return nil, err
151	}
152
153	v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
154	if err != nil {
155		return nil, err
156	}
157	// Add k & v into the MT
158	return s.mt.AddAndGetCircomProof(idx.BigInt(), v)
159}
160
161// MTUpdateAccount updates the Account in the StateDB for the given Idx, and
162// updates the MerkleTree, returning a CircomProcessorProof
163func (s *StateDB) MTUpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
164	if s.mt == nil {
165		return nil, ErrStateDBWithoutMT
166	}
167	err := s.UpdateAccount(idx, account)
168	if err != nil {
169		return nil, err
170	}
171
172	v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
173	if err != nil {
174		return nil, err
175	}
176	// Add k & v into the MT
177	return s.mt.Update(idx.BigInt(), v)
178}
179
180// MTGetProof returns the CircomVerifierProof for a given Idx
181func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
182	if s.mt == nil {
183		return nil, ErrStateDBWithoutMT
184	}
185	return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
186}
187
188// LocalStateDB represents the local StateDB which allows to make copies from
189// the synchronizer StateDB, and is used by the tx-selector and the
190// batch-builder. LocalStateDB is an in-memory storage.
191type LocalStateDB struct {
192	*StateDB
193	synchronizerStateDB *StateDB
194}
195
196// NewLocalStateDB returns a new LocalStateDB connected to the given
197// synchronizerDB
198func NewLocalStateDB(synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalStateDB, error) {
199	s, err := NewStateDB("", false, withMT, nLevels)
200	if err != nil {
201		return nil, err
202	}
203	return &LocalStateDB{
204		s,
205		synchronizerDB,
206	}, nil
207}
208
209// Reset performs a reset, getting the state from
210// LocalStateDB.synchronizerStateDB for the given batchNum
211func (l *LocalStateDB) Reset(batchNum uint64, fromSynchronizer bool) error {
212	// TODO
213	// if fromSynchronizer==true:
214	// 	make copy from l.synchronizerStateDB at the batchNum to the localStateDB
215	// 		if synchronizerStateDB does not have batchNum, return err
216	// 	the localStateDB checkpoint is set to batchNum
217	// else fromSynchronizer==false:
218	// 	the localStateDB checkpoint is set to batchNum
219	// 		if localStateDB does not have batchNum, return err
220	return nil
221}