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.

522 lines
14 KiB

  1. package statedb
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "strconv"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/log"
  9. "github.com/iden3/go-merkletree"
  10. "github.com/iden3/go-merkletree/db"
  11. "github.com/iden3/go-merkletree/db/pebble"
  12. )
  13. // TODO(Edu): Document here how StateDB is kept consistent
  14. var (
  15. // ErrStateDBWithoutMT is used when a method that requires a MerkleTree
  16. // is called in a StateDB that does not have a MerkleTree defined
  17. ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
  18. // ErrAccountAlreadyExists is used when CreateAccount is called and the
  19. // Account already exists
  20. ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
  21. // ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr
  22. // or ToEthAddr&ToBJJ
  23. ErrToIdxNotFound = errors.New("ToIdx can not be found")
  24. // KeyCurrentBatch is used as key in the db to store the current BatchNum
  25. KeyCurrentBatch = []byte("currentbatch")
  26. )
  27. const (
  28. // PathStateDB defines the subpath of the StateDB
  29. PathStateDB = "/statedb"
  30. // PathBatchNum defines the subpath of the Batch Checkpoint in the
  31. // subpath of the StateDB
  32. PathBatchNum = "/BatchNum"
  33. // PathCurrent defines the subpath of the current Batch in the subpath
  34. // of the StateDB
  35. PathCurrent = "/current"
  36. // TypeSynchronizer defines a StateDB used by the Synchronizer, that
  37. // generates the ExitTree when processing the txs
  38. TypeSynchronizer = "synchronizer"
  39. // TypeTxSelector defines a StateDB used by the TxSelector, without
  40. // computing ExitTree neither the ZKInputs
  41. TypeTxSelector = "txselector"
  42. // TypeBatchBuilder defines a StateDB used by the BatchBuilder, that
  43. // generates the ExitTree and the ZKInput when processing the txs
  44. TypeBatchBuilder = "batchbuilder"
  45. )
  46. // TypeStateDB determines the type of StateDB
  47. type TypeStateDB string
  48. // StateDB represents the StateDB object
  49. type StateDB struct {
  50. path string
  51. currentBatch common.BatchNum
  52. db *pebble.PebbleStorage
  53. mt *merkletree.MerkleTree
  54. typ TypeStateDB
  55. // idx holds the current Idx that the BatchBuilder is using
  56. idx common.Idx
  57. zki *common.ZKInputs
  58. i int // i is the current transaction index in the ZKInputs generation (zki)
  59. }
  60. // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
  61. // storage
  62. func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
  63. var sto *pebble.PebbleStorage
  64. var err error
  65. sto, err = pebble.NewPebbleStorage(path+PathStateDB+PathCurrent, false)
  66. if err != nil {
  67. return nil, err
  68. }
  69. var mt *merkletree.MerkleTree = nil
  70. if typ == TypeSynchronizer || typ == TypeBatchBuilder {
  71. mt, err = merkletree.NewMerkleTree(sto, nLevels)
  72. if err != nil {
  73. return nil, err
  74. }
  75. }
  76. if typ == TypeTxSelector && nLevels != 0 {
  77. return nil, fmt.Errorf("invalid StateDB parameters: StateDB type==TypeStateDB can not have nLevels!=0")
  78. }
  79. sdb := &StateDB{
  80. path: path + PathStateDB,
  81. db: sto,
  82. mt: mt,
  83. typ: typ,
  84. }
  85. // load currentBatch
  86. sdb.currentBatch, err = sdb.GetCurrentBatch()
  87. if err != nil {
  88. return nil, err
  89. }
  90. // make reset (get checkpoint) at currentBatch
  91. err = sdb.reset(sdb.currentBatch, false)
  92. if err != nil {
  93. return nil, err
  94. }
  95. return sdb, nil
  96. }
  97. // DB returns the *pebble.PebbleStorage from the StateDB
  98. func (s *StateDB) DB() *pebble.PebbleStorage {
  99. return s.db
  100. }
  101. // GetCurrentBatch returns the current BatchNum stored in the StateDB
  102. func (s *StateDB) GetCurrentBatch() (common.BatchNum, error) {
  103. cbBytes, err := s.db.Get(KeyCurrentBatch)
  104. if err == db.ErrNotFound {
  105. return 0, nil
  106. }
  107. if err != nil {
  108. return 0, err
  109. }
  110. return common.BatchNumFromBytes(cbBytes)
  111. }
  112. // setCurrentBatch stores the current BatchNum in the StateDB
  113. func (s *StateDB) setCurrentBatch() error {
  114. tx, err := s.db.NewTx()
  115. if err != nil {
  116. return err
  117. }
  118. err = tx.Put(KeyCurrentBatch, s.currentBatch.Bytes())
  119. if err != nil {
  120. return err
  121. }
  122. if err := tx.Commit(); err != nil {
  123. return err
  124. }
  125. return nil
  126. }
  127. // 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.
  128. func (s *StateDB) MakeCheckpoint() error {
  129. // advance currentBatch
  130. s.currentBatch++
  131. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(s.currentBatch))
  132. err := s.setCurrentBatch()
  133. if err != nil {
  134. return err
  135. }
  136. // if checkpoint BatchNum already exist in disk, delete it
  137. if _, err := os.Stat(checkpointPath); !os.IsNotExist(err) {
  138. err := os.RemoveAll(checkpointPath)
  139. if err != nil {
  140. return err
  141. }
  142. } else if err != nil && !os.IsNotExist(err) {
  143. return err
  144. }
  145. // execute Checkpoint
  146. err = s.db.Pebble().Checkpoint(checkpointPath)
  147. if err != nil {
  148. return err
  149. }
  150. return nil
  151. }
  152. // DeleteCheckpoint removes if exist the checkpoint of the given batchNum
  153. func (s *StateDB) DeleteCheckpoint(batchNum common.BatchNum) error {
  154. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  155. if _, err := os.Stat(checkpointPath); os.IsNotExist(err) {
  156. return fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum)
  157. }
  158. return os.RemoveAll(checkpointPath)
  159. }
  160. func pebbleMakeCheckpoint(source, dest string) error {
  161. // Remove dest folder (if it exists) before doing the checkpoint
  162. if _, err := os.Stat(dest); !os.IsNotExist(err) {
  163. err := os.RemoveAll(dest)
  164. if err != nil {
  165. return err
  166. }
  167. } else if err != nil && !os.IsNotExist(err) {
  168. return err
  169. }
  170. sto, err := pebble.NewPebbleStorage(source, false)
  171. if err != nil {
  172. return err
  173. }
  174. defer func() {
  175. errClose := sto.Pebble().Close()
  176. if errClose != nil {
  177. log.Errorw("Pebble.Close", "err", errClose)
  178. }
  179. }()
  180. // execute Checkpoint
  181. err = sto.Pebble().Checkpoint(dest)
  182. if err != nil {
  183. return err
  184. }
  185. return nil
  186. }
  187. // Reset resets the StateDB to the checkpoint at the given batchNum. Reset
  188. // does not delete the checkpoints between old current and the new current,
  189. // those checkpoints will remain in the storage, and eventually will be
  190. // deleted when MakeCheckpoint overwrites them.
  191. func (s *StateDB) Reset(batchNum common.BatchNum) error {
  192. return s.reset(batchNum, true)
  193. }
  194. // reset resets the StateDB to the checkpoint at the given batchNum. Reset
  195. // does not delete the checkpoints between old current and the new current,
  196. // those checkpoints will remain in the storage, and eventually will be
  197. // deleted when MakeCheckpoint overwrites them. `closeCurrent` will close the
  198. // currently opened db before doing the reset.
  199. func (s *StateDB) reset(batchNum common.BatchNum, closeCurrent bool) error {
  200. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  201. currentPath := s.path + PathCurrent
  202. if closeCurrent {
  203. if err := s.db.Pebble().Close(); err != nil {
  204. return err
  205. }
  206. }
  207. // remove 'current'
  208. err := os.RemoveAll(currentPath)
  209. if err != nil {
  210. return err
  211. }
  212. if batchNum == 0 {
  213. // if batchNum == 0, open the new fresh 'current'
  214. sto, err := pebble.NewPebbleStorage(currentPath, false)
  215. if err != nil {
  216. return err
  217. }
  218. s.db = sto
  219. s.idx = 255
  220. s.currentBatch = batchNum
  221. return nil
  222. }
  223. // copy 'BatchNumX' to 'current'
  224. err = pebbleMakeCheckpoint(checkpointPath, currentPath)
  225. if err != nil {
  226. return err
  227. }
  228. // open the new 'current'
  229. sto, err := pebble.NewPebbleStorage(currentPath, false)
  230. if err != nil {
  231. return err
  232. }
  233. s.db = sto
  234. // get currentBatch num
  235. s.currentBatch, err = s.GetCurrentBatch()
  236. if err != nil {
  237. return err
  238. }
  239. // idx is obtained from the statedb reset
  240. s.idx, err = s.getIdx()
  241. if err != nil {
  242. return err
  243. }
  244. if s.mt != nil {
  245. // open the MT for the current s.db
  246. mt, err := merkletree.NewMerkleTree(s.db, s.mt.MaxLevels())
  247. if err != nil {
  248. return err
  249. }
  250. s.mt = mt
  251. }
  252. return nil
  253. }
  254. // GetAccount returns the account for the given Idx
  255. func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
  256. return getAccountInTreeDB(s.db, idx)
  257. }
  258. // getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  259. // from ExitTree. GetAccount returns the account for the given Idx
  260. func getAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
  261. idxBytes, err := idx.Bytes()
  262. if err != nil {
  263. return nil, err
  264. }
  265. vBytes, err := sto.Get(idxBytes[:])
  266. if err != nil {
  267. return nil, err
  268. }
  269. accBytes, err := sto.Get(vBytes)
  270. if err != nil {
  271. return nil, err
  272. }
  273. var b [32 * common.NLeafElems]byte
  274. copy(b[:], accBytes)
  275. return common.AccountFromBytes(b)
  276. }
  277. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  278. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  279. // MerkleTree, returning a CircomProcessorProof.
  280. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  281. cpp, err := createAccountInTreeDB(s.db, s.mt, idx, account)
  282. if err != nil {
  283. return cpp, err
  284. }
  285. // store idx by EthAddr & BJJ
  286. err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey)
  287. return cpp, err
  288. }
  289. // createAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  290. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  291. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  292. // MerkleTree, returning a CircomProcessorProof.
  293. func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  294. // store at the DB the key: v, and value: leaf.Bytes()
  295. v, err := account.HashValue()
  296. if err != nil {
  297. return nil, err
  298. }
  299. accountBytes, err := account.Bytes()
  300. if err != nil {
  301. return nil, err
  302. }
  303. // store the Leaf value
  304. tx, err := sto.NewTx()
  305. if err != nil {
  306. return nil, err
  307. }
  308. idxBytes, err := idx.Bytes()
  309. if err != nil {
  310. return nil, err
  311. }
  312. _, err = tx.Get(idxBytes[:])
  313. if err != db.ErrNotFound {
  314. return nil, ErrAccountAlreadyExists
  315. }
  316. err = tx.Put(v.Bytes(), accountBytes[:])
  317. if err != nil {
  318. return nil, err
  319. }
  320. err = tx.Put(idxBytes[:], v.Bytes())
  321. if err != nil {
  322. return nil, err
  323. }
  324. if err := tx.Commit(); err != nil {
  325. return nil, err
  326. }
  327. if mt != nil {
  328. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  329. }
  330. return nil, nil
  331. }
  332. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  333. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  334. // MerkleTree, returning a CircomProcessorProof.
  335. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  336. return updateAccountInTreeDB(s.db, s.mt, idx, account)
  337. }
  338. // updateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  339. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  340. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  341. // MerkleTree, returning a CircomProcessorProof.
  342. func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  343. // store at the DB the key: v, and value: account.Bytes()
  344. v, err := account.HashValue()
  345. if err != nil {
  346. return nil, err
  347. }
  348. accountBytes, err := account.Bytes()
  349. if err != nil {
  350. return nil, err
  351. }
  352. tx, err := sto.NewTx()
  353. if err != nil {
  354. return nil, err
  355. }
  356. err = tx.Put(v.Bytes(), accountBytes[:])
  357. if err != nil {
  358. return nil, err
  359. }
  360. idxBytes, err := idx.Bytes()
  361. if err != nil {
  362. return nil, err
  363. }
  364. err = tx.Put(idxBytes[:], v.Bytes())
  365. if err != nil {
  366. return nil, err
  367. }
  368. if err := tx.Commit(); err != nil {
  369. return nil, err
  370. }
  371. if mt != nil {
  372. return mt.Update(idx.BigInt(), v)
  373. }
  374. return nil, nil
  375. }
  376. // MTGetProof returns the CircomVerifierProof for a given Idx
  377. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  378. if s.mt == nil {
  379. return nil, ErrStateDBWithoutMT
  380. }
  381. return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
  382. }
  383. // LocalStateDB represents the local StateDB which allows to make copies from
  384. // the synchronizer StateDB, and is used by the tx-selector and the
  385. // batch-builder. LocalStateDB is an in-memory storage.
  386. type LocalStateDB struct {
  387. *StateDB
  388. synchronizerStateDB *StateDB
  389. }
  390. // NewLocalStateDB returns a new LocalStateDB connected to the given
  391. // synchronizerDB
  392. func NewLocalStateDB(path string, synchronizerDB *StateDB, typ TypeStateDB, nLevels int) (*LocalStateDB, error) {
  393. s, err := NewStateDB(path, typ, nLevels)
  394. if err != nil {
  395. return nil, err
  396. }
  397. return &LocalStateDB{
  398. s,
  399. synchronizerDB,
  400. }, nil
  401. }
  402. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  403. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  404. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  405. if batchNum == 0 {
  406. l.idx = 0
  407. return nil
  408. }
  409. synchronizerCheckpointPath := l.synchronizerStateDB.path + PathBatchNum + strconv.Itoa(int(batchNum))
  410. checkpointPath := l.path + PathBatchNum + strconv.Itoa(int(batchNum))
  411. currentPath := l.path + PathCurrent
  412. if fromSynchronizer {
  413. // use checkpoint from SynchronizerStateDB
  414. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  415. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  416. return fmt.Errorf("Checkpoint not exist in Synchronizer")
  417. }
  418. if err := l.db.Pebble().Close(); err != nil {
  419. return err
  420. }
  421. // remove 'current'
  422. err := os.RemoveAll(currentPath)
  423. if err != nil {
  424. return err
  425. }
  426. // copy synchronizer'BatchNumX' to 'current'
  427. err = pebbleMakeCheckpoint(synchronizerCheckpointPath, currentPath)
  428. if err != nil {
  429. return err
  430. }
  431. // copy synchronizer'BatchNumX' to 'BatchNumX'
  432. err = pebbleMakeCheckpoint(synchronizerCheckpointPath, checkpointPath)
  433. if err != nil {
  434. return err
  435. }
  436. // open the new 'current'
  437. sto, err := pebble.NewPebbleStorage(currentPath, false)
  438. if err != nil {
  439. return err
  440. }
  441. l.db = sto
  442. // get currentBatch num
  443. l.currentBatch, err = l.GetCurrentBatch()
  444. if err != nil {
  445. return err
  446. }
  447. // open the MT for the current s.db
  448. mt, err := merkletree.NewMerkleTree(l.db, l.mt.MaxLevels())
  449. if err != nil {
  450. return err
  451. }
  452. l.mt = mt
  453. return nil
  454. }
  455. // use checkpoint from LocalStateDB
  456. return l.StateDB.reset(batchNum, true)
  457. }