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.

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