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.

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