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.

434 lines
12 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. // ErrStateDBWithoutMT is used when a method that requires a MerkleTree is
  15. // called in a StateDB that does not have a MerkleTree defined
  16. var ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
  17. // ErrAccountAlreadyExists is used when CreateAccount is called and the Account
  18. // already exists
  19. var ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
  20. // KeyCurrentBatch is used as key in the db to store the current BatchNum
  21. var KeyCurrentBatch = []byte("currentbatch")
  22. // PathStateDB defines the subpath of the StateDB
  23. const PathStateDB = "/statedb"
  24. // PathBatchNum defines the subpath of the Batch Checkpoint in the subpath of
  25. // the StateDB
  26. const PathBatchNum = "/BatchNum"
  27. // PathCurrent defines the subpath of the current Batch in the subpath of the
  28. // StateDB
  29. const PathCurrent = "/current"
  30. // StateDB represents the StateDB object
  31. type StateDB struct {
  32. path string
  33. currentBatch common.BatchNum
  34. db *pebble.PebbleStorage
  35. mt *merkletree.MerkleTree
  36. // idx holds the current Idx that the BatchBuilder is using
  37. idx common.Idx
  38. zki *common.ZKInputs
  39. i int // i is the current transaction index in the ZKInputs generation (zki)
  40. }
  41. // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
  42. // storage
  43. func NewStateDB(path string, withMT bool, nLevels int) (*StateDB, error) {
  44. var sto *pebble.PebbleStorage
  45. var err error
  46. sto, err = pebble.NewPebbleStorage(path+PathStateDB+PathCurrent, false)
  47. if err != nil {
  48. return nil, err
  49. }
  50. var mt *merkletree.MerkleTree = nil
  51. if withMT {
  52. mt, err = merkletree.NewMerkleTree(sto, nLevels)
  53. if err != nil {
  54. return nil, err
  55. }
  56. }
  57. sdb := &StateDB{
  58. path: path + PathStateDB,
  59. db: sto,
  60. mt: mt,
  61. }
  62. // load currentBatch
  63. sdb.currentBatch, err = sdb.GetCurrentBatch()
  64. if err != nil {
  65. return nil, err
  66. }
  67. // make reset (get checkpoint) at currentBatch
  68. err = sdb.Reset(sdb.currentBatch)
  69. if err != nil {
  70. return nil, err
  71. }
  72. return sdb, nil
  73. }
  74. // DB returns the *pebble.PebbleStorage from the StateDB
  75. func (s *StateDB) DB() *pebble.PebbleStorage {
  76. return s.db
  77. }
  78. // GetCurrentBatch returns the current BatchNum stored in the StateDB
  79. func (s *StateDB) GetCurrentBatch() (common.BatchNum, error) {
  80. cbBytes, err := s.db.Get(KeyCurrentBatch)
  81. if err == db.ErrNotFound {
  82. return 0, nil
  83. }
  84. if err != nil {
  85. return 0, err
  86. }
  87. return common.BatchNumFromBytes(cbBytes)
  88. }
  89. // setCurrentBatch stores the current BatchNum in the StateDB
  90. func (s *StateDB) setCurrentBatch() error {
  91. tx, err := s.db.NewTx()
  92. if err != nil {
  93. return err
  94. }
  95. err = tx.Put(KeyCurrentBatch, s.currentBatch.Bytes())
  96. if err != nil {
  97. return err
  98. }
  99. if err := tx.Commit(); err != nil {
  100. return err
  101. }
  102. return nil
  103. }
  104. // 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.
  105. func (s *StateDB) MakeCheckpoint() error {
  106. // advance currentBatch
  107. s.currentBatch++
  108. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(s.currentBatch))
  109. err := s.setCurrentBatch()
  110. if err != nil {
  111. return err
  112. }
  113. // if checkpoint BatchNum already exist in disk, delete it
  114. if _, err := os.Stat(checkpointPath); !os.IsNotExist(err) {
  115. err := os.RemoveAll(checkpointPath)
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. // execute Checkpoint
  121. err = s.db.Pebble().Checkpoint(checkpointPath)
  122. if err != nil {
  123. return err
  124. }
  125. return nil
  126. }
  127. // DeleteCheckpoint removes if exist the checkpoint of the given batchNum
  128. func (s *StateDB) DeleteCheckpoint(batchNum common.BatchNum) error {
  129. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  130. if _, err := os.Stat(checkpointPath); os.IsNotExist(err) {
  131. return fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum)
  132. }
  133. return os.RemoveAll(checkpointPath)
  134. }
  135. // Reset resets the StateDB to the checkpoint at the given batchNum. Reset
  136. // does not delete the checkpoints between old current and the new current,
  137. // those checkpoints will remain in the storage, and eventually will be
  138. // deleted when MakeCheckpoint overwrites them.
  139. func (s *StateDB) Reset(batchNum common.BatchNum) error {
  140. checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum))
  141. currentPath := s.path + PathCurrent
  142. // remove 'current'
  143. err := os.RemoveAll(currentPath)
  144. if err != nil {
  145. return err
  146. }
  147. if batchNum == 0 {
  148. // if batchNum == 0, open the new fresh 'current'
  149. sto, err := pebble.NewPebbleStorage(currentPath, false)
  150. if err != nil {
  151. return err
  152. }
  153. s.db = sto
  154. s.idx = 0
  155. s.currentBatch = batchNum
  156. return nil
  157. }
  158. // copy 'BatchNumX' to 'current'
  159. cmd := exec.Command("cp", "-r", checkpointPath, currentPath) //nolint:gosec
  160. err = cmd.Run()
  161. if err != nil {
  162. return err
  163. }
  164. // open the new 'current'
  165. sto, err := pebble.NewPebbleStorage(currentPath, false)
  166. if err != nil {
  167. return err
  168. }
  169. s.db = sto
  170. // get currentBatch num
  171. s.currentBatch, err = s.GetCurrentBatch()
  172. if err != nil {
  173. return err
  174. }
  175. // idx is obtained from the statedb reset
  176. s.idx, err = s.getIdx()
  177. if err != nil {
  178. return err
  179. }
  180. if s.mt != nil {
  181. // open the MT for the current s.db
  182. mt, err := merkletree.NewMerkleTree(s.db, s.mt.MaxLevels())
  183. if err != nil {
  184. return err
  185. }
  186. s.mt = mt
  187. }
  188. return nil
  189. }
  190. // GetAccount returns the account for the given Idx
  191. func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
  192. return getAccountInTreeDB(s.db, idx)
  193. }
  194. // getAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  195. // from ExitTree. GetAccount returns the account for the given Idx
  196. func getAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
  197. vBytes, err := sto.Get(idx.Bytes())
  198. if err != nil {
  199. return nil, err
  200. }
  201. accBytes, err := sto.Get(vBytes)
  202. if err != nil {
  203. return nil, err
  204. }
  205. var b [32 * common.NLeafElems]byte
  206. copy(b[:], accBytes)
  207. return common.AccountFromBytes(b)
  208. }
  209. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  210. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  211. // MerkleTree, returning a CircomProcessorProof.
  212. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  213. return createAccountInTreeDB(s.db, s.mt, idx, account)
  214. }
  215. // createAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  216. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  217. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  218. // MerkleTree, returning a CircomProcessorProof.
  219. func createAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  220. // store at the DB the key: v, and value: leaf.Bytes()
  221. v, err := account.HashValue()
  222. if err != nil {
  223. return nil, err
  224. }
  225. accountBytes, err := account.Bytes()
  226. if err != nil {
  227. return nil, err
  228. }
  229. // store the Leaf value
  230. tx, err := sto.NewTx()
  231. if err != nil {
  232. return nil, err
  233. }
  234. _, err = tx.Get(idx.Bytes())
  235. if err != db.ErrNotFound {
  236. return nil, ErrAccountAlreadyExists
  237. }
  238. err = tx.Put(v.Bytes(), accountBytes[:])
  239. if err != nil {
  240. return nil, err
  241. }
  242. err = tx.Put(idx.Bytes(), v.Bytes())
  243. if err != nil {
  244. return nil, err
  245. }
  246. if err := tx.Commit(); err != nil {
  247. return nil, err
  248. }
  249. if mt != nil {
  250. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  251. }
  252. return nil, nil
  253. }
  254. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  255. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  256. // MerkleTree, returning a CircomProcessorProof.
  257. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  258. return updateAccountInTreeDB(s.db, s.mt, idx, account)
  259. }
  260. // updateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  261. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  262. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  263. // MerkleTree, returning a CircomProcessorProof.
  264. func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  265. // store at the DB the key: v, and value: account.Bytes()
  266. v, err := account.HashValue()
  267. if err != nil {
  268. return nil, err
  269. }
  270. accountBytes, err := account.Bytes()
  271. if err != nil {
  272. return nil, err
  273. }
  274. tx, err := sto.NewTx()
  275. if err != nil {
  276. return nil, err
  277. }
  278. err = tx.Put(v.Bytes(), accountBytes[:])
  279. if err != nil {
  280. return nil, err
  281. }
  282. err = tx.Put(idx.Bytes(), v.Bytes())
  283. if err != nil {
  284. return nil, err
  285. }
  286. if err := tx.Commit(); err != nil {
  287. return nil, err
  288. }
  289. if mt != nil {
  290. return mt.Update(idx.BigInt(), v)
  291. }
  292. return nil, nil
  293. }
  294. // MTGetProof returns the CircomVerifierProof for a given Idx
  295. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  296. if s.mt == nil {
  297. return nil, ErrStateDBWithoutMT
  298. }
  299. return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
  300. }
  301. // LocalStateDB represents the local StateDB which allows to make copies from
  302. // the synchronizer StateDB, and is used by the tx-selector and the
  303. // batch-builder. LocalStateDB is an in-memory storage.
  304. type LocalStateDB struct {
  305. *StateDB
  306. synchronizerStateDB *StateDB
  307. }
  308. // NewLocalStateDB returns a new LocalStateDB connected to the given
  309. // synchronizerDB
  310. func NewLocalStateDB(path string, synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalStateDB, error) {
  311. s, err := NewStateDB(path, withMT, nLevels)
  312. if err != nil {
  313. return nil, err
  314. }
  315. return &LocalStateDB{
  316. s,
  317. synchronizerDB,
  318. }, nil
  319. }
  320. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  321. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  322. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  323. if batchNum == 0 {
  324. l.idx = 0
  325. return nil
  326. }
  327. synchronizerCheckpointPath := l.synchronizerStateDB.path + PathBatchNum + strconv.Itoa(int(batchNum))
  328. checkpointPath := l.path + PathBatchNum + strconv.Itoa(int(batchNum))
  329. currentPath := l.path + PathCurrent
  330. if fromSynchronizer {
  331. // use checkpoint from SynchronizerStateDB
  332. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  333. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  334. return fmt.Errorf("Checkpoint not exist in Synchronizer")
  335. }
  336. // remove 'current'
  337. err := os.RemoveAll(currentPath)
  338. if err != nil {
  339. return err
  340. }
  341. // copy synchronizer'BatchNumX' to 'current'
  342. cmd := exec.Command("cp", "-r", synchronizerCheckpointPath, currentPath) //nolint:gosec
  343. err = cmd.Run()
  344. if err != nil {
  345. return err
  346. }
  347. // copy synchronizer-'BatchNumX' to 'BatchNumX'
  348. cmd = exec.Command("cp", "-r", synchronizerCheckpointPath, checkpointPath) //nolint:gosec
  349. err = cmd.Run()
  350. if err != nil {
  351. return err
  352. }
  353. // open the new 'current'
  354. sto, err := pebble.NewPebbleStorage(currentPath, false)
  355. if err != nil {
  356. return err
  357. }
  358. l.db = sto
  359. // get currentBatch num
  360. l.currentBatch, err = l.GetCurrentBatch()
  361. if err != nil {
  362. return err
  363. }
  364. // open the MT for the current s.db
  365. mt, err := merkletree.NewMerkleTree(l.db, l.mt.MaxLevels())
  366. if err != nil {
  367. return err
  368. }
  369. l.mt = mt
  370. return nil
  371. }
  372. // use checkpoint from LocalStateDB
  373. return l.StateDB.Reset(batchNum)
  374. }