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.

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