You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

690 lines
20 KiB

  1. package statedb
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "math/big"
  7. "os"
  8. "path"
  9. "sort"
  10. "strings"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. "github.com/hermeznetwork/tracerr"
  14. "github.com/iden3/go-merkletree"
  15. "github.com/iden3/go-merkletree/db"
  16. "github.com/iden3/go-merkletree/db/pebble"
  17. )
  18. // TODO(Edu): Document here how StateDB is kept consistent
  19. var (
  20. // ErrStateDBWithoutMT is used when a method that requires a MerkleTree
  21. // is called in a StateDB that does not have a MerkleTree defined
  22. ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
  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. // ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr
  27. // or ToEthAddr&ToBJJ
  28. ErrToIdxNotFound = errors.New("ToIdx can not be found")
  29. // ErrGetIdxNoCase is used when trying to get the Idx from EthAddr &
  30. // BJJ with not compatible combination
  31. ErrGetIdxNoCase = errors.New("Can not get Idx due unexpected combination of ethereum Address & BabyJubJub PublicKey")
  32. // KeyCurrentBatch is used as key in the db to store the current BatchNum
  33. KeyCurrentBatch = []byte("k:currentbatch")
  34. // PrefixKeyIdx is the key prefix for idx in the db
  35. PrefixKeyIdx = []byte("i:")
  36. // PrefixKeyAccHash is the key prefix for account hash in the db
  37. PrefixKeyAccHash = []byte("h:")
  38. // PrefixKeyMT is the key prefix for merkle tree in the db
  39. PrefixKeyMT = []byte("m:")
  40. // PrefixKeyAddr is the key prefix for address in the db
  41. PrefixKeyAddr = []byte("a:")
  42. // PrefixKeyAddrBJJ is the key prefix for address-babyjubjub in the db
  43. PrefixKeyAddrBJJ = []byte("ab:")
  44. // keyidx is used as key in the db to store the current Idx
  45. keyidx = []byte("k:idx")
  46. )
  47. const (
  48. // PathBatchNum defines the subpath of the Batch Checkpoint in the
  49. // subpath of the StateDB
  50. PathBatchNum = "BatchNum"
  51. // PathCurrent defines the subpath of the current Batch in the subpath
  52. // of the StateDB
  53. PathCurrent = "current"
  54. // TypeSynchronizer defines a StateDB used by the Synchronizer, that
  55. // generates the ExitTree when processing the txs
  56. TypeSynchronizer = "synchronizer"
  57. // TypeTxSelector defines a StateDB used by the TxSelector, without
  58. // computing ExitTree neither the ZKInputs
  59. TypeTxSelector = "txselector"
  60. // TypeBatchBuilder defines a StateDB used by the BatchBuilder, that
  61. // generates the ExitTree and the ZKInput when processing the txs
  62. TypeBatchBuilder = "batchbuilder"
  63. )
  64. // TypeStateDB determines the type of StateDB
  65. type TypeStateDB string
  66. // StateDB represents the StateDB object
  67. type StateDB struct {
  68. path string
  69. Typ TypeStateDB
  70. // CurrentIdx holds the current Idx that the BatchBuilder is using
  71. CurrentIdx common.Idx
  72. CurrentBatch common.BatchNum
  73. db *pebble.Storage
  74. MT *merkletree.MerkleTree
  75. keep int
  76. }
  77. // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
  78. // storage. Checkpoints older than the value defined by `keep` will be
  79. // deleted.
  80. func NewStateDB(pathDB string, keep int, typ TypeStateDB, nLevels int) (*StateDB, error) {
  81. var sto *pebble.Storage
  82. var err error
  83. sto, err = pebble.NewPebbleStorage(path.Join(pathDB, PathCurrent), false)
  84. if err != nil {
  85. return nil, tracerr.Wrap(err)
  86. }
  87. var mt *merkletree.MerkleTree = nil
  88. if typ == TypeSynchronizer || typ == TypeBatchBuilder {
  89. mt, err = merkletree.NewMerkleTree(sto.WithPrefix(PrefixKeyMT), nLevels)
  90. if err != nil {
  91. return nil, tracerr.Wrap(err)
  92. }
  93. }
  94. if typ == TypeTxSelector && nLevels != 0 {
  95. return nil, tracerr.Wrap(fmt.Errorf("invalid StateDB parameters: StateDB type==TypeStateDB can not have nLevels!=0"))
  96. }
  97. sdb := &StateDB{
  98. path: pathDB,
  99. db: sto,
  100. MT: mt,
  101. Typ: typ,
  102. keep: keep,
  103. }
  104. // load currentBatch
  105. sdb.CurrentBatch, err = sdb.GetCurrentBatch()
  106. if err != nil {
  107. return nil, tracerr.Wrap(err)
  108. }
  109. // make reset (get checkpoint) at currentBatch
  110. err = sdb.reset(sdb.CurrentBatch, false)
  111. if err != nil {
  112. return nil, tracerr.Wrap(err)
  113. }
  114. return sdb, nil
  115. }
  116. // DB returns the *pebble.Storage from the StateDB
  117. func (s *StateDB) DB() *pebble.Storage {
  118. return s.db
  119. }
  120. // GetCurrentBatch returns the current BatchNum stored in the StateDB
  121. func (s *StateDB) GetCurrentBatch() (common.BatchNum, error) {
  122. cbBytes, err := s.db.Get(KeyCurrentBatch)
  123. if tracerr.Unwrap(err) == db.ErrNotFound {
  124. return 0, nil
  125. }
  126. if err != nil {
  127. return 0, tracerr.Wrap(err)
  128. }
  129. return common.BatchNumFromBytes(cbBytes)
  130. }
  131. // setCurrentBatch stores the current BatchNum in the StateDB
  132. func (s *StateDB) setCurrentBatch() error {
  133. tx, err := s.db.NewTx()
  134. if err != nil {
  135. return tracerr.Wrap(err)
  136. }
  137. err = tx.Put(KeyCurrentBatch, s.CurrentBatch.Bytes())
  138. if err != nil {
  139. return tracerr.Wrap(err)
  140. }
  141. if err := tx.Commit(); err != nil {
  142. return tracerr.Wrap(err)
  143. }
  144. return nil
  145. }
  146. // 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.
  147. func (s *StateDB) MakeCheckpoint() error {
  148. // advance currentBatch
  149. s.CurrentBatch++
  150. log.Debugw("Making StateDB checkpoint", "batch", s.CurrentBatch, "type", s.Typ)
  151. checkpointPath := path.Join(s.path, fmt.Sprintf("%s%d", PathBatchNum, s.CurrentBatch))
  152. if err := s.setCurrentBatch(); err != nil {
  153. return tracerr.Wrap(err)
  154. }
  155. // if checkpoint BatchNum already exist in disk, delete it
  156. if _, err := os.Stat(checkpointPath); !os.IsNotExist(err) {
  157. err := os.RemoveAll(checkpointPath)
  158. if err != nil {
  159. return tracerr.Wrap(err)
  160. }
  161. } else if err != nil && !os.IsNotExist(err) {
  162. return tracerr.Wrap(err)
  163. }
  164. // execute Checkpoint
  165. if err := s.db.Pebble().Checkpoint(checkpointPath); err != nil {
  166. return tracerr.Wrap(err)
  167. }
  168. // delete old checkpoints
  169. if err := s.deleteOldCheckpoints(); err != nil {
  170. return tracerr.Wrap(err)
  171. }
  172. return nil
  173. }
  174. // DeleteCheckpoint removes if exist the checkpoint of the given batchNum
  175. func (s *StateDB) DeleteCheckpoint(batchNum common.BatchNum) error {
  176. checkpointPath := path.Join(s.path, fmt.Sprintf("%s%d", PathBatchNum, batchNum))
  177. if _, err := os.Stat(checkpointPath); os.IsNotExist(err) {
  178. return tracerr.Wrap(fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum))
  179. }
  180. return os.RemoveAll(checkpointPath)
  181. }
  182. // listCheckpoints returns the list of batchNums of the checkpoints, sorted.
  183. // If there's a gap between the list of checkpoints, an error is returned.
  184. func (s *StateDB) listCheckpoints() ([]int, error) {
  185. files, err := ioutil.ReadDir(s.path)
  186. if err != nil {
  187. return nil, tracerr.Wrap(err)
  188. }
  189. checkpoints := []int{}
  190. var checkpoint int
  191. pattern := fmt.Sprintf("%s%%d", PathBatchNum)
  192. for _, file := range files {
  193. fileName := file.Name()
  194. if file.IsDir() && strings.HasPrefix(fileName, PathBatchNum) {
  195. if _, err := fmt.Sscanf(fileName, pattern, &checkpoint); err != nil {
  196. return nil, tracerr.Wrap(err)
  197. }
  198. checkpoints = append(checkpoints, checkpoint)
  199. }
  200. }
  201. sort.Ints(checkpoints)
  202. if len(checkpoints) > 0 {
  203. first := checkpoints[0]
  204. for _, checkpoint := range checkpoints[1:] {
  205. first++
  206. if checkpoint != first {
  207. return nil, tracerr.Wrap(fmt.Errorf("checkpoint gap at %v", checkpoint))
  208. }
  209. }
  210. }
  211. return checkpoints, nil
  212. }
  213. // deleteOldCheckpoints deletes old checkpoints when there are more than
  214. // `s.keep` checkpoints
  215. func (s *StateDB) deleteOldCheckpoints() error {
  216. list, err := s.listCheckpoints()
  217. if err != nil {
  218. return tracerr.Wrap(err)
  219. }
  220. if len(list) > s.keep {
  221. for _, checkpoint := range list[:len(list)-s.keep] {
  222. if err := s.DeleteCheckpoint(common.BatchNum(checkpoint)); err != nil {
  223. return tracerr.Wrap(err)
  224. }
  225. }
  226. }
  227. return nil
  228. }
  229. func pebbleMakeCheckpoint(source, dest string) error {
  230. // Remove dest folder (if it exists) before doing the checkpoint
  231. if _, err := os.Stat(dest); !os.IsNotExist(err) {
  232. err := os.RemoveAll(dest)
  233. if err != nil {
  234. return tracerr.Wrap(err)
  235. }
  236. } else if err != nil && !os.IsNotExist(err) {
  237. return tracerr.Wrap(err)
  238. }
  239. sto, err := pebble.NewPebbleStorage(source, false)
  240. if err != nil {
  241. return tracerr.Wrap(err)
  242. }
  243. defer func() {
  244. errClose := sto.Pebble().Close()
  245. if errClose != nil {
  246. log.Errorw("Pebble.Close", "err", errClose)
  247. }
  248. }()
  249. // execute Checkpoint
  250. err = sto.Pebble().Checkpoint(dest)
  251. if err != nil {
  252. return tracerr.Wrap(err)
  253. }
  254. return nil
  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.
  260. func (s *StateDB) Reset(batchNum common.BatchNum) error {
  261. return s.reset(batchNum, true)
  262. }
  263. // reset resets the StateDB to the checkpoint at the given batchNum. Reset
  264. // does not delete the checkpoints between old current and the new current,
  265. // those checkpoints will remain in the storage, and eventually will be
  266. // deleted when MakeCheckpoint overwrites them. `closeCurrent` will close the
  267. // currently opened db before doing the reset.
  268. func (s *StateDB) reset(batchNum common.BatchNum, closeCurrent bool) error {
  269. currentPath := path.Join(s.path, PathCurrent)
  270. if closeCurrent {
  271. if err := s.db.Pebble().Close(); err != nil {
  272. return tracerr.Wrap(err)
  273. }
  274. }
  275. // remove 'current'
  276. err := os.RemoveAll(currentPath)
  277. if err != nil {
  278. return tracerr.Wrap(err)
  279. }
  280. // remove all checkpoints > batchNum
  281. for i := batchNum + 1; i <= s.CurrentBatch; i++ {
  282. if err := s.DeleteCheckpoint(i); err != nil {
  283. return tracerr.Wrap(err)
  284. }
  285. }
  286. if batchNum == 0 {
  287. // if batchNum == 0, open the new fresh 'current'
  288. sto, err := pebble.NewPebbleStorage(currentPath, false)
  289. if err != nil {
  290. return tracerr.Wrap(err)
  291. }
  292. s.db = sto
  293. s.CurrentIdx = 255
  294. s.CurrentBatch = batchNum
  295. if s.MT != nil {
  296. // open the MT for the current s.db
  297. mt, err := merkletree.NewMerkleTree(s.db.WithPrefix(PrefixKeyMT), s.MT.MaxLevels())
  298. if err != nil {
  299. return tracerr.Wrap(err)
  300. }
  301. s.MT = mt
  302. }
  303. return nil
  304. }
  305. checkpointPath := path.Join(s.path, fmt.Sprintf("%s%d", PathBatchNum, batchNum))
  306. // copy 'BatchNumX' to 'current'
  307. err = pebbleMakeCheckpoint(checkpointPath, currentPath)
  308. if err != nil {
  309. return tracerr.Wrap(err)
  310. }
  311. // open the new 'current'
  312. sto, err := pebble.NewPebbleStorage(currentPath, false)
  313. if err != nil {
  314. return tracerr.Wrap(err)
  315. }
  316. s.db = sto
  317. // get currentBatch num
  318. s.CurrentBatch, err = s.GetCurrentBatch()
  319. if err != nil {
  320. return tracerr.Wrap(err)
  321. }
  322. // idx is obtained from the statedb reset
  323. s.CurrentIdx, err = s.GetIdx()
  324. if err != nil {
  325. return tracerr.Wrap(err)
  326. }
  327. if s.MT != nil {
  328. // open the MT for the current s.db
  329. mt, err := merkletree.NewMerkleTree(s.db.WithPrefix(PrefixKeyMT), s.MT.MaxLevels())
  330. if err != nil {
  331. return tracerr.Wrap(err)
  332. }
  333. s.MT = mt
  334. }
  335. return nil
  336. }
  337. // GetIdx returns the stored Idx from the localStateDB, which is the last Idx
  338. // used for an Account in the localStateDB.
  339. func (s *StateDB) GetIdx() (common.Idx, error) {
  340. idxBytes, err := s.DB().Get(keyidx)
  341. if tracerr.Unwrap(err) == db.ErrNotFound {
  342. return 0, nil
  343. }
  344. if err != nil {
  345. return 0, tracerr.Wrap(err)
  346. }
  347. return common.IdxFromBytes(idxBytes[:])
  348. }
  349. // SetIdx stores Idx in the localStateDB
  350. func (s *StateDB) SetIdx(idx common.Idx) error {
  351. s.CurrentIdx = idx
  352. tx, err := s.DB().NewTx()
  353. if err != nil {
  354. return tracerr.Wrap(err)
  355. }
  356. idxBytes, err := idx.Bytes()
  357. if err != nil {
  358. return tracerr.Wrap(err)
  359. }
  360. err = tx.Put(keyidx, idxBytes[:])
  361. if err != nil {
  362. return tracerr.Wrap(err)
  363. }
  364. if err := tx.Commit(); err != nil {
  365. return tracerr.Wrap(err)
  366. }
  367. return nil
  368. }
  369. // GetAccount returns the account for the given Idx
  370. func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
  371. return GetAccountInTreeDB(s.db, idx)
  372. }
  373. // GetAccounts returns all the accounts in the db. Use for debugging pruposes
  374. // only.
  375. func (s *StateDB) GetAccounts() ([]common.Account, error) {
  376. idxDB := s.db.WithPrefix(PrefixKeyIdx)
  377. idxs := []common.Idx{}
  378. // NOTE: Current implementation of Iterate in the pebble interface is
  379. // not efficient, as it iterates over all keys. Improve it following
  380. // this example: https://github.com/cockroachdb/pebble/pull/923/files
  381. if err := idxDB.Iterate(func(k []byte, v []byte) (bool, error) {
  382. idx, err := common.IdxFromBytes(k)
  383. if err != nil {
  384. return false, tracerr.Wrap(err)
  385. }
  386. idxs = append(idxs, idx)
  387. return true, nil
  388. }); err != nil {
  389. return nil, tracerr.Wrap(err)
  390. }
  391. accs := []common.Account{}
  392. for i := range idxs {
  393. acc, err := s.GetAccount(idxs[i])
  394. if err != nil {
  395. return nil, tracerr.Wrap(err)
  396. }
  397. accs = append(accs, *acc)
  398. }
  399. return accs, nil
  400. }
  401. // GetAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  402. // from ExitTree. GetAccount returns the account for the given Idx
  403. func GetAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
  404. idxBytes, err := idx.Bytes()
  405. if err != nil {
  406. return nil, tracerr.Wrap(err)
  407. }
  408. vBytes, err := sto.Get(append(PrefixKeyIdx, idxBytes[:]...))
  409. if err != nil {
  410. return nil, tracerr.Wrap(err)
  411. }
  412. accBytes, err := sto.Get(append(PrefixKeyAccHash, vBytes...))
  413. if err != nil {
  414. return nil, tracerr.Wrap(err)
  415. }
  416. var b [32 * common.NLeafElems]byte
  417. copy(b[:], accBytes)
  418. account, err := common.AccountFromBytes(b)
  419. if err != nil {
  420. return nil, tracerr.Wrap(err)
  421. }
  422. account.Idx = idx
  423. return account, nil
  424. }
  425. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  426. // StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
  427. // MerkleTree, returning a CircomProcessorProof.
  428. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  429. cpp, err := CreateAccountInTreeDB(s.db, s.MT, idx, account)
  430. if err != nil {
  431. return cpp, tracerr.Wrap(err)
  432. }
  433. // store idx by EthAddr & BJJ
  434. err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey, account.TokenID)
  435. return cpp, tracerr.Wrap(err)
  436. }
  437. // CreateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  438. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  439. // StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
  440. // MerkleTree, returning a CircomProcessorProof.
  441. func CreateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  442. // store at the DB the key: v, and value: leaf.Bytes()
  443. v, err := account.HashValue()
  444. if err != nil {
  445. return nil, tracerr.Wrap(err)
  446. }
  447. accountBytes, err := account.Bytes()
  448. if err != nil {
  449. return nil, tracerr.Wrap(err)
  450. }
  451. // store the Leaf value
  452. tx, err := sto.NewTx()
  453. if err != nil {
  454. return nil, tracerr.Wrap(err)
  455. }
  456. idxBytes, err := idx.Bytes()
  457. if err != nil {
  458. return nil, tracerr.Wrap(err)
  459. }
  460. _, err = tx.Get(append(PrefixKeyIdx, idxBytes[:]...))
  461. if tracerr.Unwrap(err) != db.ErrNotFound {
  462. return nil, tracerr.Wrap(ErrAccountAlreadyExists)
  463. }
  464. err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
  465. if err != nil {
  466. return nil, tracerr.Wrap(err)
  467. }
  468. err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
  469. if err != nil {
  470. return nil, tracerr.Wrap(err)
  471. }
  472. if err := tx.Commit(); err != nil {
  473. return nil, tracerr.Wrap(err)
  474. }
  475. if mt != nil {
  476. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  477. }
  478. return nil, nil
  479. }
  480. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  481. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  482. // MerkleTree, returning a CircomProcessorProof.
  483. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  484. return UpdateAccountInTreeDB(s.db, s.MT, idx, account)
  485. }
  486. // UpdateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  487. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  488. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  489. // MerkleTree, returning a CircomProcessorProof.
  490. func UpdateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  491. // store at the DB the key: v, and value: account.Bytes()
  492. v, err := account.HashValue()
  493. if err != nil {
  494. return nil, tracerr.Wrap(err)
  495. }
  496. accountBytes, err := account.Bytes()
  497. if err != nil {
  498. return nil, tracerr.Wrap(err)
  499. }
  500. tx, err := sto.NewTx()
  501. if err != nil {
  502. return nil, tracerr.Wrap(err)
  503. }
  504. err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
  505. if err != nil {
  506. return nil, tracerr.Wrap(err)
  507. }
  508. idxBytes, err := idx.Bytes()
  509. if err != nil {
  510. return nil, tracerr.Wrap(err)
  511. }
  512. err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
  513. if err != nil {
  514. return nil, tracerr.Wrap(err)
  515. }
  516. if err := tx.Commit(); err != nil {
  517. return nil, tracerr.Wrap(err)
  518. }
  519. if mt != nil {
  520. proof, err := mt.Update(idx.BigInt(), v)
  521. return proof, tracerr.Wrap(err)
  522. }
  523. return nil, nil
  524. }
  525. // MTGetProof returns the CircomVerifierProof for a given Idx
  526. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  527. if s.MT == nil {
  528. return nil, tracerr.Wrap(ErrStateDBWithoutMT)
  529. }
  530. return s.MT.GenerateCircomVerifierProof(idx.BigInt(), s.MT.Root())
  531. }
  532. // MTGetRoot returns the current root of the underlying Merkle Tree
  533. func (s *StateDB) MTGetRoot() *big.Int {
  534. return s.MT.Root().BigInt()
  535. }
  536. // LocalStateDB represents the local StateDB which allows to make copies from
  537. // the synchronizer StateDB, and is used by the tx-selector and the
  538. // batch-builder. LocalStateDB is an in-memory storage.
  539. type LocalStateDB struct {
  540. *StateDB
  541. synchronizerStateDB *StateDB
  542. }
  543. // NewLocalStateDB returns a new LocalStateDB connected to the given
  544. // synchronizerDB. Checkpoints older than the value defined by `keep` will be
  545. // deleted.
  546. func NewLocalStateDB(path string, keep int, synchronizerDB *StateDB, typ TypeStateDB,
  547. nLevels int) (*LocalStateDB, error) {
  548. s, err := NewStateDB(path, keep, typ, nLevels)
  549. if err != nil {
  550. return nil, tracerr.Wrap(err)
  551. }
  552. return &LocalStateDB{
  553. s,
  554. synchronizerDB,
  555. }, nil
  556. }
  557. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  558. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  559. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  560. if batchNum == 0 {
  561. l.CurrentIdx = 0
  562. return nil
  563. }
  564. synchronizerCheckpointPath := path.Join(l.synchronizerStateDB.path,
  565. fmt.Sprintf("%s%d", PathBatchNum, batchNum))
  566. checkpointPath := path.Join(l.path, fmt.Sprintf("%s%d", PathBatchNum, batchNum))
  567. currentPath := path.Join(l.path, PathCurrent)
  568. if fromSynchronizer {
  569. // use checkpoint from SynchronizerStateDB
  570. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  571. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  572. return tracerr.Wrap(fmt.Errorf("Checkpoint \"%v\" not exist in Synchronizer",
  573. synchronizerCheckpointPath))
  574. }
  575. if err := l.db.Pebble().Close(); err != nil {
  576. return tracerr.Wrap(err)
  577. }
  578. // remove 'current'
  579. err := os.RemoveAll(currentPath)
  580. if err != nil {
  581. return tracerr.Wrap(err)
  582. }
  583. // copy synchronizer'BatchNumX' to 'current'
  584. err = pebbleMakeCheckpoint(synchronizerCheckpointPath, currentPath)
  585. if err != nil {
  586. return tracerr.Wrap(err)
  587. }
  588. // copy synchronizer'BatchNumX' to 'BatchNumX'
  589. err = pebbleMakeCheckpoint(synchronizerCheckpointPath, checkpointPath)
  590. if err != nil {
  591. return tracerr.Wrap(err)
  592. }
  593. // open the new 'current'
  594. sto, err := pebble.NewPebbleStorage(currentPath, false)
  595. if err != nil {
  596. return tracerr.Wrap(err)
  597. }
  598. l.db = sto
  599. // get currentBatch num
  600. l.CurrentBatch, err = l.GetCurrentBatch()
  601. if err != nil {
  602. return tracerr.Wrap(err)
  603. }
  604. // open the MT for the current s.db
  605. if l.MT != nil {
  606. mt, err := merkletree.NewMerkleTree(l.db.WithPrefix(PrefixKeyMT), l.MT.MaxLevels())
  607. if err != nil {
  608. return tracerr.Wrap(err)
  609. }
  610. l.MT = mt
  611. }
  612. return nil
  613. }
  614. // use checkpoint from LocalStateDB
  615. return l.StateDB.reset(batchNum, true)
  616. }