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.

490 lines
13 KiB

  1. package statedb
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "strconv"
  8. "github.com/hermeznetwork/hermez-node/common"
  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)
  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. }
  143. // execute Checkpoint
  144. err = s.db.Pebble().Checkpoint(checkpointPath)
  145. if err != nil {
  146. return err
  147. }
  148. return nil
  149. }
  150. // DeleteCheckpoint removes if exist the checkpoint of the given batchNum
  151. func (s *StateDB) DeleteCheckpoint(batchNum common.BatchNum) error {
  152. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  153. if _, err := os.Stat(checkpointPath); os.IsNotExist(err) {
  154. return fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum)
  155. }
  156. return os.RemoveAll(checkpointPath)
  157. }
  158. // Reset resets the StateDB to the checkpoint at the given batchNum. Reset
  159. // does not delete the checkpoints between old current and the new current,
  160. // those checkpoints will remain in the storage, and eventually will be
  161. // deleted when MakeCheckpoint overwrites them.
  162. func (s *StateDB) Reset(batchNum common.BatchNum) error {
  163. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  164. currentPath := s.path + PathCurrent
  165. // remove 'current'
  166. err := os.RemoveAll(currentPath)
  167. if err != nil {
  168. return err
  169. }
  170. if batchNum == 0 {
  171. // if batchNum == 0, open the new fresh 'current'
  172. sto, err := pebble.NewPebbleStorage(currentPath, false)
  173. if err != nil {
  174. return err
  175. }
  176. s.db = sto
  177. s.idx = 255
  178. s.currentBatch = batchNum
  179. return nil
  180. }
  181. // copy 'BatchNumX' to 'current'
  182. cmd := exec.Command("cp", "-r", checkpointPath, currentPath) //nolint:gosec
  183. err = cmd.Run()
  184. if err != nil {
  185. return err
  186. }
  187. // open the new 'current'
  188. sto, err := pebble.NewPebbleStorage(currentPath, false)
  189. if err != nil {
  190. return err
  191. }
  192. s.db = sto
  193. // get currentBatch num
  194. s.currentBatch, err = s.GetCurrentBatch()
  195. if err != nil {
  196. return err
  197. }
  198. // idx is obtained from the statedb reset
  199. s.idx, err = s.getIdx()
  200. if err != nil {
  201. return err
  202. }
  203. if s.mt != nil {
  204. // open the MT for the current s.db
  205. mt, err := merkletree.NewMerkleTree(s.db, s.mt.MaxLevels())
  206. if err != nil {
  207. return err
  208. }
  209. s.mt = mt
  210. }
  211. return nil
  212. }
  213. // GetAccount returns the account for the given Idx
  214. func (s *StateDB) GetAccount(idx *common.Idx) (*common.Account, error) {
  215. if idx == nil {
  216. return nil, errors.New("idx cannot be nil")
  217. }
  218. return getAccountInTreeDB(s.db, idx)
  219. }
  220. // getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  221. // from ExitTree. GetAccount returns the account for the given Idx
  222. func getAccountInTreeDB(sto db.Storage, idx *common.Idx) (*common.Account, error) {
  223. if idx == nil {
  224. return nil, errors.New("idx cannot be nil")
  225. }
  226. idxBytes, err := idx.Bytes()
  227. if err != nil {
  228. return nil, err
  229. }
  230. vBytes, err := sto.Get(idxBytes[:])
  231. if err != nil {
  232. return nil, err
  233. }
  234. accBytes, err := sto.Get(vBytes)
  235. if err != nil {
  236. return nil, err
  237. }
  238. var b [32 * common.NLeafElems]byte
  239. copy(b[:], accBytes)
  240. return common.AccountFromBytes(b)
  241. }
  242. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  243. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  244. // MerkleTree, returning a CircomProcessorProof.
  245. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  246. cpp, err := createAccountInTreeDB(s.db, s.mt, &idx, account)
  247. if err != nil {
  248. return cpp, err
  249. }
  250. // store idx by EthAddr & BJJ
  251. err = s.setIdxByEthAddrBJJ(idx, &account.EthAddr, account.PublicKey)
  252. return cpp, err
  253. }
  254. // createAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  255. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  256. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  257. // MerkleTree, returning a CircomProcessorProof.
  258. func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  259. if idx == nil {
  260. return nil, errors.New("idx cannot be nil")
  261. }
  262. // store at the DB the key: v, and value: leaf.Bytes()
  263. v, err := account.HashValue()
  264. if err != nil {
  265. return nil, err
  266. }
  267. accountBytes, err := account.Bytes()
  268. if err != nil {
  269. return nil, err
  270. }
  271. // store the Leaf value
  272. tx, err := sto.NewTx()
  273. if err != nil {
  274. return nil, err
  275. }
  276. idxBytes, err := idx.Bytes()
  277. if err != nil {
  278. return nil, err
  279. }
  280. _, err = tx.Get(idxBytes[:])
  281. if err != db.ErrNotFound {
  282. return nil, ErrAccountAlreadyExists
  283. }
  284. err = tx.Put(v.Bytes(), accountBytes[:])
  285. if err != nil {
  286. return nil, err
  287. }
  288. err = tx.Put(idxBytes[:], v.Bytes())
  289. if err != nil {
  290. return nil, err
  291. }
  292. if err := tx.Commit(); err != nil {
  293. return nil, err
  294. }
  295. if mt != nil {
  296. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  297. }
  298. return nil, nil
  299. }
  300. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  301. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  302. // MerkleTree, returning a CircomProcessorProof.
  303. func (s *StateDB) UpdateAccount(idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  304. if idx == nil {
  305. return nil, errors.New("idx cannot be nil")
  306. }
  307. return updateAccountInTreeDB(s.db, s.mt, idx, account)
  308. }
  309. // updateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  310. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  311. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  312. // MerkleTree, returning a CircomProcessorProof.
  313. func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx *common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  314. if idx == nil {
  315. return nil, errors.New("idx cannot be nil")
  316. }
  317. // store at the DB the key: v, and value: account.Bytes()
  318. v, err := account.HashValue()
  319. if err != nil {
  320. return nil, err
  321. }
  322. accountBytes, err := account.Bytes()
  323. if err != nil {
  324. return nil, err
  325. }
  326. tx, err := sto.NewTx()
  327. if err != nil {
  328. return nil, err
  329. }
  330. err = tx.Put(v.Bytes(), accountBytes[:])
  331. if err != nil {
  332. return nil, err
  333. }
  334. idxBytes, err := idx.Bytes()
  335. if err != nil {
  336. return nil, err
  337. }
  338. err = tx.Put(idxBytes[:], v.Bytes())
  339. if err != nil {
  340. return nil, err
  341. }
  342. if err := tx.Commit(); err != nil {
  343. return nil, err
  344. }
  345. if mt != nil {
  346. return mt.Update(idx.BigInt(), v)
  347. }
  348. return nil, nil
  349. }
  350. // MTGetProof returns the CircomVerifierProof for a given Idx
  351. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  352. if s.mt == nil {
  353. return nil, ErrStateDBWithoutMT
  354. }
  355. return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
  356. }
  357. // LocalStateDB represents the local StateDB which allows to make copies from
  358. // the synchronizer StateDB, and is used by the tx-selector and the
  359. // batch-builder. LocalStateDB is an in-memory storage.
  360. type LocalStateDB struct {
  361. *StateDB
  362. synchronizerStateDB *StateDB
  363. }
  364. // NewLocalStateDB returns a new LocalStateDB connected to the given
  365. // synchronizerDB
  366. func NewLocalStateDB(path string, synchronizerDB *StateDB, typ TypeStateDB, nLevels int) (*LocalStateDB, error) {
  367. s, err := NewStateDB(path, typ, nLevels)
  368. if err != nil {
  369. return nil, err
  370. }
  371. return &LocalStateDB{
  372. s,
  373. synchronizerDB,
  374. }, nil
  375. }
  376. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  377. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  378. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  379. if batchNum == 0 {
  380. l.idx = 0
  381. return nil
  382. }
  383. synchronizerCheckpointPath := l.synchronizerStateDB.path + PathBatchNum + strconv.Itoa(int(batchNum))
  384. checkpointPath := l.path + PathBatchNum + strconv.Itoa(int(batchNum))
  385. currentPath := l.path + PathCurrent
  386. if fromSynchronizer {
  387. // use checkpoint from SynchronizerStateDB
  388. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  389. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  390. return fmt.Errorf("Checkpoint not exist in Synchronizer")
  391. }
  392. // remove 'current'
  393. err := os.RemoveAll(currentPath)
  394. if err != nil {
  395. return err
  396. }
  397. // copy synchronizer'BatchNumX' to 'current'
  398. cmd := exec.Command("cp", "-r", synchronizerCheckpointPath, currentPath) //nolint:gosec
  399. err = cmd.Run()
  400. if err != nil {
  401. return err
  402. }
  403. // copy synchronizer-'BatchNumX' to 'BatchNumX'
  404. cmd = exec.Command("cp", "-r", synchronizerCheckpointPath, checkpointPath) //nolint:gosec
  405. err = cmd.Run()
  406. if err != nil {
  407. return err
  408. }
  409. // open the new 'current'
  410. sto, err := pebble.NewPebbleStorage(currentPath, false)
  411. if err != nil {
  412. return err
  413. }
  414. l.db = sto
  415. // get currentBatch num
  416. l.currentBatch, err = l.GetCurrentBatch()
  417. if err != nil {
  418. return err
  419. }
  420. // open the MT for the current s.db
  421. mt, err := merkletree.NewMerkleTree(l.db, l.mt.MaxLevels())
  422. if err != nil {
  423. return err
  424. }
  425. l.mt = mt
  426. return nil
  427. }
  428. // use checkpoint from LocalStateDB
  429. return l.StateDB.Reset(batchNum)
  430. }