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.

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