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.

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