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.

359 lines
9.4 KiB

  1. package statedb
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "os/exec"
  8. "strconv"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/iden3/go-merkletree"
  11. "github.com/iden3/go-merkletree/db"
  12. "github.com/iden3/go-merkletree/db/pebble"
  13. )
  14. // ErrStateDBWithoutMT is used when a method that requires a MerkleTree is 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 already exists
  17. var ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
  18. // KEYCURRENTBATCH is used as key in the db to store the current BatchNum
  19. var KEYCURRENTBATCH = []byte("currentbatch")
  20. // STATEDBPATH defines the subpath of the StateDB
  21. const STATEDBPATH = "/statedb"
  22. // StateDB represents the StateDB object
  23. type StateDB struct {
  24. path string
  25. currentBatch uint64
  26. db *pebble.PebbleStorage
  27. mt *merkletree.MerkleTree
  28. }
  29. // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
  30. // storage
  31. func NewStateDB(path string, withMT bool, nLevels int) (*StateDB, error) {
  32. var sto *pebble.PebbleStorage
  33. var err error
  34. sto, err = pebble.NewPebbleStorage(path+STATEDBPATH+"/current", false)
  35. if err != nil {
  36. return nil, err
  37. }
  38. var mt *merkletree.MerkleTree = nil
  39. if withMT {
  40. mt, err = merkletree.NewMerkleTree(sto, nLevels)
  41. if err != nil {
  42. return nil, err
  43. }
  44. }
  45. sdb := &StateDB{
  46. path: path + STATEDBPATH,
  47. db: sto,
  48. mt: mt,
  49. }
  50. // load currentBatch
  51. sdb.currentBatch, err = sdb.GetCurrentBatch()
  52. if err != nil {
  53. return nil, err
  54. }
  55. return sdb, nil
  56. }
  57. // DB returns the *pebble.PebbleStorage from the StateDB
  58. func (s *StateDB) DB() *pebble.PebbleStorage {
  59. return s.db
  60. }
  61. // GetCurrentBatch returns the current BatchNum stored in the StateDB
  62. func (s *StateDB) GetCurrentBatch() (uint64, error) {
  63. cbBytes, err := s.db.Get(KEYCURRENTBATCH)
  64. if err == db.ErrNotFound {
  65. return 0, nil
  66. }
  67. if err != nil {
  68. return 0, err
  69. }
  70. cb := binary.LittleEndian.Uint64(cbBytes[:8])
  71. return cb, nil
  72. }
  73. // setCurrentBatch stores the current BatchNum in the StateDB
  74. func (s *StateDB) setCurrentBatch() error {
  75. tx, err := s.db.NewTx()
  76. if err != nil {
  77. return err
  78. }
  79. var cbBytes [8]byte
  80. binary.LittleEndian.PutUint64(cbBytes[:], s.currentBatch)
  81. tx.Put(KEYCURRENTBATCH, cbBytes[:])
  82. if err := tx.Commit(); err != nil {
  83. return err
  84. }
  85. return nil
  86. }
  87. // CheckPointAt does a checkpoint at the given batchNum in the defined path
  88. func (s *StateDB) MakeCheckpoint() error {
  89. // advance currentBatch
  90. s.currentBatch++
  91. checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(s.currentBatch))
  92. s.setCurrentBatch()
  93. // if checkpoint BatchNum already exist in disk, delete it
  94. if _, err := os.Stat(checkpointPath); !os.IsNotExist(err) {
  95. err := os.RemoveAll(checkpointPath)
  96. if err != nil {
  97. return err
  98. }
  99. }
  100. // execute Checkpoint
  101. err := s.db.Pebble().Checkpoint(checkpointPath)
  102. if err != nil {
  103. return err
  104. }
  105. return nil
  106. }
  107. // DeleteCheckpoint removes if exist the checkpoint of the given batchNum
  108. func (s *StateDB) DeleteCheckpoint(batchNum uint64) error {
  109. checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(batchNum))
  110. if _, err := os.Stat(checkpointPath); os.IsNotExist(err) {
  111. return fmt.Errorf("Checkpoint with batchNum %d does not exist in DB", batchNum)
  112. }
  113. return os.RemoveAll(checkpointPath)
  114. }
  115. // Reset resets the StateDB to the checkpoint at the given batchNum. Reset
  116. // does not delete the checkpoints between old current and the new current,
  117. // those checkpoints will remain in the storage, and eventually will be
  118. // deleted when MakeCheckpoint overwrites them.
  119. func (s *StateDB) Reset(batchNum uint64) error {
  120. checkpointPath := s.path + "/BatchNum" + strconv.Itoa(int(batchNum))
  121. currentPath := s.path + "/current"
  122. // remove 'current'
  123. err := os.RemoveAll(currentPath)
  124. if err != nil {
  125. return err
  126. }
  127. // copy 'BatchNumX' to 'current'
  128. cmd := exec.Command("cp", "-r", checkpointPath, currentPath)
  129. err = cmd.Run()
  130. if err != nil {
  131. return err
  132. }
  133. // open the new 'current'
  134. sto, err := pebble.NewPebbleStorage(currentPath, false)
  135. if err != nil {
  136. return err
  137. }
  138. s.db = sto
  139. // get currentBatch num
  140. s.currentBatch, err = s.GetCurrentBatch()
  141. if err != nil {
  142. return err
  143. }
  144. return nil
  145. }
  146. // GetAccount returns the account for the given Idx
  147. func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
  148. vBytes, err := s.db.Get(idx.Bytes())
  149. if err != nil {
  150. return nil, err
  151. }
  152. accBytes, err := s.db.Get(vBytes)
  153. if err != nil {
  154. return nil, err
  155. }
  156. var b [32 * common.NLEAFELEMS]byte
  157. copy(b[:], accBytes)
  158. return common.AccountFromBytes(b)
  159. }
  160. // CreateAccount creates a new Account in the StateDB for the given Idx.
  161. // MerkleTree is not affected.
  162. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) error {
  163. // store at the DB the key: v, and value: leaf.Bytes()
  164. v, err := account.HashValue()
  165. if err != nil {
  166. return err
  167. }
  168. accountBytes, err := account.Bytes()
  169. if err != nil {
  170. return err
  171. }
  172. // store the Leaf value
  173. tx, err := s.db.NewTx()
  174. if err != nil {
  175. return err
  176. }
  177. _, err = tx.Get(idx.Bytes())
  178. if err != db.ErrNotFound {
  179. return ErrAccountAlreadyExists
  180. }
  181. tx.Put(v.Bytes(), accountBytes[:])
  182. tx.Put(idx.Bytes(), v.Bytes())
  183. return tx.Commit()
  184. }
  185. // UpdateAccount updates the Account in the StateDB for the given Idx.
  186. // MerkleTree is not affected.
  187. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) error {
  188. // store at the DB the key: v, and value: leaf.Bytes()
  189. v, err := account.HashValue()
  190. if err != nil {
  191. return err
  192. }
  193. accountBytes, err := account.Bytes()
  194. if err != nil {
  195. return err
  196. }
  197. tx, err := s.db.NewTx()
  198. if err != nil {
  199. return err
  200. }
  201. tx.Put(v.Bytes(), accountBytes[:])
  202. tx.Put(idx.Bytes(), v.Bytes())
  203. return tx.Commit()
  204. }
  205. // MTCreateAccount creates a new Account in the StateDB for the given Idx,
  206. // and updates the MerkleTree, returning a CircomProcessorProof
  207. func (s *StateDB) MTCreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  208. if s.mt == nil {
  209. return nil, ErrStateDBWithoutMT
  210. }
  211. err := s.CreateAccount(idx, account)
  212. if err != nil {
  213. return nil, err
  214. }
  215. v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
  216. if err != nil {
  217. return nil, err
  218. }
  219. // Add k & v into the MT
  220. return s.mt.AddAndGetCircomProof(idx.BigInt(), v)
  221. }
  222. // MTUpdateAccount updates the Account in the StateDB for the given Idx, and
  223. // updates the MerkleTree, returning a CircomProcessorProof
  224. func (s *StateDB) MTUpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  225. if s.mt == nil {
  226. return nil, ErrStateDBWithoutMT
  227. }
  228. err := s.UpdateAccount(idx, account)
  229. if err != nil {
  230. return nil, err
  231. }
  232. v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
  233. if err != nil {
  234. return nil, err
  235. }
  236. // Add k & v into the MT
  237. return s.mt.Update(idx.BigInt(), v)
  238. }
  239. // MTGetProof returns the CircomVerifierProof for a given Idx
  240. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  241. if s.mt == nil {
  242. return nil, ErrStateDBWithoutMT
  243. }
  244. return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
  245. }
  246. // LocalStateDB represents the local StateDB which allows to make copies from
  247. // the synchronizer StateDB, and is used by the tx-selector and the
  248. // batch-builder. LocalStateDB is an in-memory storage.
  249. type LocalStateDB struct {
  250. *StateDB
  251. synchronizerStateDB *StateDB
  252. }
  253. // NewLocalStateDB returns a new LocalStateDB connected to the given
  254. // synchronizerDB
  255. func NewLocalStateDB(path string, synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalStateDB, error) {
  256. s, err := NewStateDB(path, withMT, nLevels)
  257. if err != nil {
  258. return nil, err
  259. }
  260. return &LocalStateDB{
  261. s,
  262. synchronizerDB,
  263. }, nil
  264. }
  265. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  266. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum. If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  267. func (l *LocalStateDB) Reset(batchNum uint64, fromSynchronizer bool) error {
  268. synchronizerCheckpointPath := l.synchronizerStateDB.path + "/BatchNum" + strconv.Itoa(int(batchNum))
  269. checkpointPath := l.path + "/BatchNum" + strconv.Itoa(int(batchNum))
  270. currentPath := l.path + "/current"
  271. if fromSynchronizer {
  272. // use checkpoint from SynchronizerStateDB
  273. if _, err := os.Stat(synchronizerCheckpointPath); os.IsNotExist(err) {
  274. // if synchronizerStateDB does not have checkpoint at batchNum, return err
  275. return fmt.Errorf("Checkpoint not exist in Synchronizer")
  276. }
  277. // remove 'current'
  278. err := os.RemoveAll(currentPath)
  279. if err != nil {
  280. return err
  281. }
  282. // copy synchronizer'BatchNumX' to 'current'
  283. cmd := exec.Command("cp", "-r", synchronizerCheckpointPath, currentPath)
  284. err = cmd.Run()
  285. if err != nil {
  286. return err
  287. }
  288. // copy synchronizer-'BatchNumX' to 'BatchNumX'
  289. cmd = exec.Command("cp", "-r", synchronizerCheckpointPath, checkpointPath)
  290. err = cmd.Run()
  291. if err != nil {
  292. return err
  293. }
  294. // open the new 'current'
  295. sto, err := pebble.NewPebbleStorage(currentPath, false)
  296. if err != nil {
  297. return err
  298. }
  299. l.db = sto
  300. // get currentBatch num
  301. l.currentBatch, err = l.GetCurrentBatch()
  302. if err != nil {
  303. return err
  304. }
  305. return nil
  306. }
  307. // use checkpoint from LocalStateDB
  308. return l.StateDB.Reset(batchNum)
  309. }