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.

475 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. return getAccountInTreeDB(s.db, idx)
  216. }
  217. // getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  218. // from ExitTree. GetAccount returns the account for the given Idx
  219. func getAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
  220. idxBytes, err := idx.Bytes()
  221. if err != nil {
  222. return nil, err
  223. }
  224. vBytes, err := sto.Get(idxBytes[:])
  225. if err != nil {
  226. return nil, err
  227. }
  228. accBytes, err := sto.Get(vBytes)
  229. if err != nil {
  230. return nil, err
  231. }
  232. var b [32 * common.NLeafElems]byte
  233. copy(b[:], accBytes)
  234. return common.AccountFromBytes(b)
  235. }
  236. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  237. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  238. // MerkleTree, returning a CircomProcessorProof.
  239. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  240. cpp, err := createAccountInTreeDB(s.db, s.mt, idx, account)
  241. if err != nil {
  242. return cpp, err
  243. }
  244. // store idx by EthAddr & BJJ
  245. err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey)
  246. return cpp, err
  247. }
  248. // createAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  249. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  250. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  251. // MerkleTree, returning a CircomProcessorProof.
  252. func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  253. // store at the DB the key: v, and value: leaf.Bytes()
  254. v, err := account.HashValue()
  255. if err != nil {
  256. return nil, err
  257. }
  258. accountBytes, err := account.Bytes()
  259. if err != nil {
  260. return nil, err
  261. }
  262. // store the Leaf value
  263. tx, err := sto.NewTx()
  264. if err != nil {
  265. return nil, err
  266. }
  267. idxBytes, err := idx.Bytes()
  268. if err != nil {
  269. return nil, err
  270. }
  271. _, err = tx.Get(idxBytes[:])
  272. if err != db.ErrNotFound {
  273. return nil, ErrAccountAlreadyExists
  274. }
  275. err = tx.Put(v.Bytes(), accountBytes[:])
  276. if err != nil {
  277. return nil, err
  278. }
  279. err = tx.Put(idxBytes[:], v.Bytes())
  280. if err != nil {
  281. return nil, err
  282. }
  283. if err := tx.Commit(); err != nil {
  284. return nil, err
  285. }
  286. if mt != nil {
  287. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  288. }
  289. return nil, nil
  290. }
  291. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  292. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  293. // MerkleTree, returning a CircomProcessorProof.
  294. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  295. return updateAccountInTreeDB(s.db, s.mt, idx, account)
  296. }
  297. // updateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  298. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  299. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  300. // MerkleTree, returning a CircomProcessorProof.
  301. func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  302. // store at the DB the key: v, and value: account.Bytes()
  303. v, err := account.HashValue()
  304. if err != nil {
  305. return nil, err
  306. }
  307. accountBytes, err := account.Bytes()
  308. if err != nil {
  309. return nil, err
  310. }
  311. tx, err := sto.NewTx()
  312. if err != nil {
  313. return nil, err
  314. }
  315. err = tx.Put(v.Bytes(), accountBytes[:])
  316. if err != nil {
  317. return nil, err
  318. }
  319. idxBytes, err := idx.Bytes()
  320. if err != nil {
  321. return nil, err
  322. }
  323. err = tx.Put(idxBytes[:], v.Bytes())
  324. if err != nil {
  325. return nil, err
  326. }
  327. if err := tx.Commit(); err != nil {
  328. return nil, err
  329. }
  330. if mt != nil {
  331. return mt.Update(idx.BigInt(), v)
  332. }
  333. return nil, nil
  334. }
  335. // MTGetProof returns the CircomVerifierProof for a given Idx
  336. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  337. if s.mt == nil {
  338. return nil, ErrStateDBWithoutMT
  339. }
  340. return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
  341. }
  342. // LocalStateDB represents the local StateDB which allows to make copies from
  343. // the synchronizer StateDB, and is used by the tx-selector and the
  344. // batch-builder. LocalStateDB is an in-memory storage.
  345. type LocalStateDB struct {
  346. *StateDB
  347. synchronizerStateDB *StateDB
  348. }
  349. // NewLocalStateDB returns a new LocalStateDB connected to the given
  350. // synchronizerDB
  351. func NewLocalStateDB(path string, synchronizerDB *StateDB, typ TypeStateDB, nLevels int) (*LocalStateDB, error) {
  352. s, err := NewStateDB(path, typ, nLevels)
  353. if err != nil {
  354. return nil, err
  355. }
  356. return &LocalStateDB{
  357. s,
  358. synchronizerDB,
  359. }, nil
  360. }
  361. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  362. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  363. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  364. if batchNum == 0 {
  365. l.idx = 0
  366. return nil
  367. }
  368. synchronizerCheckpointPath := l.synchronizerStateDB.path + PathBatchNum + strconv.Itoa(int(batchNum))
  369. checkpointPath := l.path + PathBatchNum + strconv.Itoa(int(batchNum))
  370. currentPath := l.path + PathCurrent
  371. if fromSynchronizer {
  372. // use checkpoint from SynchronizerStateDB
  373. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  374. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  375. return fmt.Errorf("Checkpoint not exist in Synchronizer")
  376. }
  377. // remove 'current'
  378. err := os.RemoveAll(currentPath)
  379. if err != nil {
  380. return err
  381. }
  382. // copy synchronizer'BatchNumX' to 'current'
  383. cmd := exec.Command("cp", "-r", synchronizerCheckpointPath, currentPath) //nolint:gosec
  384. err = cmd.Run()
  385. if err != nil {
  386. return err
  387. }
  388. // copy synchronizer-'BatchNumX' to 'BatchNumX'
  389. cmd = exec.Command("cp", "-r", synchronizerCheckpointPath, checkpointPath) //nolint:gosec
  390. err = cmd.Run()
  391. if err != nil {
  392. return err
  393. }
  394. // open the new 'current'
  395. sto, err := pebble.NewPebbleStorage(currentPath, false)
  396. if err != nil {
  397. return err
  398. }
  399. l.db = sto
  400. // get currentBatch num
  401. l.currentBatch, err = l.GetCurrentBatch()
  402. if err != nil {
  403. return err
  404. }
  405. // open the MT for the current s.db
  406. mt, err := merkletree.NewMerkleTree(l.db, l.mt.MaxLevels())
  407. if err != nil {
  408. return err
  409. }
  410. l.mt = mt
  411. return nil
  412. }
  413. // use checkpoint from LocalStateDB
  414. return l.StateDB.Reset(batchNum)
  415. }