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.

496 lines
15 KiB

Fix eth events query and sync inconsistent state - kvdb - Fix path in Last when doing `setNew` - Only close if db != nil, and after closing, always set db to nil - This will avoid a panic in the case where the db is closed but there's an error soon after, and a future call tries to close again. This is because pebble.Close() will panic if the db is already closed. - Avoid calling pebble methods when a the Storage interface already implements that method (like Close). - statedb - In test, avoid calling KVDB method if the same method is available for the StateDB (like MakeCheckpoint, CurrentBatch). - eth - In *EventByBlock methods, take blockHash as input argument and use it when querying the event logs. Previously the blockHash was only taken from the logs results *only if* there was any log. This caused the following issue: if there was no logs, it was not possible to know if the result was from the expected block or an uncle block! By querying logs by blockHash we make sure that even if there are no logs, they are from the right block. - Note that now the function can either be called with a blockNum or blockHash, but not both at the same time. - sync - If there's an error during call to Sync call resetState, which internally resets the stateDB to avoid stale checkpoints (and a corresponding invalid increase in the StateDB batchNum). - During a Sync, after very batch processed, make sure that the StateDB currentBatch corresponds to the batchNum in the smart contract log/event.
3 years ago
Fix eth events query and sync inconsistent state - kvdb - Fix path in Last when doing `setNew` - Only close if db != nil, and after closing, always set db to nil - This will avoid a panic in the case where the db is closed but there's an error soon after, and a future call tries to close again. This is because pebble.Close() will panic if the db is already closed. - Avoid calling pebble methods when a the Storage interface already implements that method (like Close). - statedb - In test, avoid calling KVDB method if the same method is available for the StateDB (like MakeCheckpoint, CurrentBatch). - eth - In *EventByBlock methods, take blockHash as input argument and use it when querying the event logs. Previously the blockHash was only taken from the logs results *only if* there was any log. This caused the following issue: if there was no logs, it was not possible to know if the result was from the expected block or an uncle block! By querying logs by blockHash we make sure that even if there are no logs, they are from the right block. - Note that now the function can either be called with a blockNum or blockHash, but not both at the same time. - sync - If there's an error during call to Sync call resetState, which internally resets the stateDB to avoid stale checkpoints (and a corresponding invalid increase in the StateDB batchNum). - During a Sync, after very batch processed, make sure that the StateDB currentBatch corresponds to the batchNum in the smart contract log/event.
3 years ago
Fix eth events query and sync inconsistent state - kvdb - Fix path in Last when doing `setNew` - Only close if db != nil, and after closing, always set db to nil - This will avoid a panic in the case where the db is closed but there's an error soon after, and a future call tries to close again. This is because pebble.Close() will panic if the db is already closed. - Avoid calling pebble methods when a the Storage interface already implements that method (like Close). - statedb - In test, avoid calling KVDB method if the same method is available for the StateDB (like MakeCheckpoint, CurrentBatch). - eth - In *EventByBlock methods, take blockHash as input argument and use it when querying the event logs. Previously the blockHash was only taken from the logs results *only if* there was any log. This caused the following issue: if there was no logs, it was not possible to know if the result was from the expected block or an uncle block! By querying logs by blockHash we make sure that even if there are no logs, they are from the right block. - Note that now the function can either be called with a blockNum or blockHash, but not both at the same time. - sync - If there's an error during call to Sync call resetState, which internally resets the stateDB to avoid stale checkpoints (and a corresponding invalid increase in the StateDB batchNum). - During a Sync, after very batch processed, make sure that the StateDB currentBatch corresponds to the batchNum in the smart contract log/event.
3 years ago
  1. package statedb
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "github.com/hermeznetwork/hermez-node/common"
  7. "github.com/hermeznetwork/hermez-node/db/kvdb"
  8. "github.com/hermeznetwork/hermez-node/log"
  9. "github.com/hermeznetwork/tracerr"
  10. "github.com/iden3/go-merkletree"
  11. "github.com/iden3/go-merkletree/db"
  12. "github.com/iden3/go-merkletree/db/pebble"
  13. )
  14. var (
  15. // ErrStateDBWithoutMT is used when a method that requires a MerkleTree
  16. // is called in a StateDB that does not have a MerkleTree defined
  17. ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
  18. // ErrAccountAlreadyExists is used when CreateAccount is called and the
  19. // Account already exists
  20. ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
  21. // ErrIdxNotFound is used when trying to get the Idx from EthAddr or
  22. // EthAddr&ToBJJ
  23. ErrIdxNotFound = errors.New("Idx can not be found")
  24. // ErrGetIdxNoCase is used when trying to get the Idx from EthAddr &
  25. // BJJ with not compatible combination
  26. ErrGetIdxNoCase = errors.New("Can not get Idx due unexpected combination of ethereum Address & BabyJubJub PublicKey")
  27. // PrefixKeyIdx is the key prefix for idx in the db
  28. PrefixKeyIdx = []byte("i:")
  29. // PrefixKeyAccHash is the key prefix for account hash in the db
  30. PrefixKeyAccHash = []byte("h:")
  31. // PrefixKeyMT is the key prefix for merkle tree in the db
  32. PrefixKeyMT = []byte("m:")
  33. // PrefixKeyAddr is the key prefix for address in the db
  34. PrefixKeyAddr = []byte("a:")
  35. // PrefixKeyAddrBJJ is the key prefix for address-babyjubjub in the db
  36. PrefixKeyAddrBJJ = []byte("ab:")
  37. )
  38. const (
  39. // TypeSynchronizer defines a StateDB used by the Synchronizer, that
  40. // generates the ExitTree when processing the txs
  41. TypeSynchronizer = "synchronizer"
  42. // TypeTxSelector defines a StateDB used by the TxSelector, without
  43. // computing ExitTree neither the ZKInputs
  44. TypeTxSelector = "txselector"
  45. // TypeBatchBuilder defines a StateDB used by the BatchBuilder, that
  46. // generates the ExitTree and the ZKInput when processing the txs
  47. TypeBatchBuilder = "batchbuilder"
  48. )
  49. // TypeStateDB determines the type of StateDB
  50. type TypeStateDB string
  51. // StateDB represents the StateDB object
  52. type StateDB struct {
  53. path string
  54. Typ TypeStateDB
  55. db *kvdb.KVDB
  56. nLevels int
  57. MT *merkletree.MerkleTree
  58. keep int
  59. }
  60. // Last offers a subset of view methods of the StateDB that can be
  61. // called via the LastRead method of StateDB in a thread-safe manner to obtain
  62. // a consistent view to the last batch of the StateDB.
  63. type Last struct {
  64. db db.Storage
  65. }
  66. // GetAccount returns the account for the given Idx
  67. func (s *Last) GetAccount(idx common.Idx) (*common.Account, error) {
  68. return GetAccountInTreeDB(s.db, idx)
  69. }
  70. // GetCurrentBatch returns the current BatchNum stored in Last.db
  71. func (s *Last) GetCurrentBatch() (common.BatchNum, error) {
  72. cbBytes, err := s.db.Get(kvdb.KeyCurrentBatch)
  73. if tracerr.Unwrap(err) == db.ErrNotFound {
  74. return 0, nil
  75. } else if err != nil {
  76. return 0, tracerr.Wrap(err)
  77. }
  78. return common.BatchNumFromBytes(cbBytes)
  79. }
  80. // DB returns the underlying storage of Last
  81. func (s *Last) DB() db.Storage {
  82. return s.db
  83. }
  84. // GetAccounts returns all the accounts in the db. Use for debugging pruposes
  85. // only.
  86. func (s *Last) GetAccounts() ([]common.Account, error) {
  87. return getAccounts(s.db)
  88. }
  89. // NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
  90. // storage. Checkpoints older than the value defined by `keep` will be
  91. // deleted.
  92. func NewStateDB(pathDB string, keep int, typ TypeStateDB, nLevels int) (*StateDB, error) {
  93. var kv *kvdb.KVDB
  94. var err error
  95. kv, err = kvdb.NewKVDB(pathDB, keep)
  96. if err != nil {
  97. return nil, tracerr.Wrap(err)
  98. }
  99. var mt *merkletree.MerkleTree = nil
  100. if typ == TypeSynchronizer || typ == TypeBatchBuilder {
  101. mt, err = merkletree.NewMerkleTree(kv.StorageWithPrefix(PrefixKeyMT), nLevels)
  102. if err != nil {
  103. return nil, tracerr.Wrap(err)
  104. }
  105. }
  106. if typ == TypeTxSelector && nLevels != 0 {
  107. return nil, tracerr.Wrap(fmt.Errorf("invalid StateDB parameters: StateDB type==TypeStateDB can not have nLevels!=0"))
  108. }
  109. return &StateDB{
  110. path: pathDB,
  111. db: kv,
  112. nLevels: nLevels,
  113. MT: mt,
  114. Typ: typ,
  115. keep: keep,
  116. }, nil
  117. }
  118. // LastRead is a thread-safe method to query the last checkpoint of the StateDB
  119. // via the Last type methods
  120. func (s *StateDB) LastRead(fn func(sdbLast *Last) error) error {
  121. return s.db.LastRead(
  122. func(db *pebble.Storage) error {
  123. return fn(&Last{
  124. db: db,
  125. })
  126. },
  127. )
  128. }
  129. // LastGetAccount is a thread-safe method to query an account in the last
  130. // checkpoint of the StateDB.
  131. func (s *StateDB) LastGetAccount(idx common.Idx) (*common.Account, error) {
  132. var account *common.Account
  133. if err := s.LastRead(func(sdb *Last) error {
  134. var err error
  135. account, err = sdb.GetAccount(idx)
  136. return err
  137. }); err != nil {
  138. return nil, tracerr.Wrap(err)
  139. }
  140. return account, nil
  141. }
  142. // LastGetCurrentBatch is a thread-safe method to get the current BatchNum in
  143. // the last checkpoint of the StateDB.
  144. func (s *StateDB) LastGetCurrentBatch() (common.BatchNum, error) {
  145. var batchNum common.BatchNum
  146. if err := s.LastRead(func(sdb *Last) error {
  147. var err error
  148. batchNum, err = sdb.GetCurrentBatch()
  149. return err
  150. }); err != nil {
  151. return 0, tracerr.Wrap(err)
  152. }
  153. return batchNum, nil
  154. }
  155. // LastMTGetRoot returns the root of the underlying Merkle Tree in the last
  156. // checkpoint of the StateDB.
  157. func (s *StateDB) LastMTGetRoot() (*big.Int, error) {
  158. var root *big.Int
  159. if err := s.LastRead(func(sdb *Last) error {
  160. mt, err := merkletree.NewMerkleTree(sdb.DB().WithPrefix(PrefixKeyMT), s.nLevels)
  161. if err != nil {
  162. return tracerr.Wrap(err)
  163. }
  164. root = mt.Root().BigInt()
  165. return nil
  166. }); err != nil {
  167. return nil, tracerr.Wrap(err)
  168. }
  169. return root, nil
  170. }
  171. // MakeCheckpoint does a checkpoint at the given batchNum in the defined path.
  172. // Internally this advances & stores the current BatchNum, and then stores a
  173. // Checkpoint of the current state of the StateDB.
  174. func (s *StateDB) MakeCheckpoint() error {
  175. log.Debugw("Making StateDB checkpoint", "batch", s.CurrentBatch()+1, "type", s.Typ)
  176. return s.db.MakeCheckpoint()
  177. }
  178. // CurrentBatch returns the current in-memory CurrentBatch of the StateDB.db
  179. func (s *StateDB) CurrentBatch() common.BatchNum {
  180. return s.db.CurrentBatch
  181. }
  182. // CurrentIdx returns the current in-memory CurrentIdx of the StateDB.db
  183. func (s *StateDB) CurrentIdx() common.Idx {
  184. return s.db.CurrentIdx
  185. }
  186. // getCurrentBatch returns the current BatchNum stored in the StateDB.db
  187. func (s *StateDB) getCurrentBatch() (common.BatchNum, error) {
  188. return s.db.GetCurrentBatch()
  189. }
  190. // GetCurrentIdx returns the stored Idx from the localStateDB, which is the
  191. // last Idx used for an Account in the localStateDB.
  192. func (s *StateDB) GetCurrentIdx() (common.Idx, error) {
  193. return s.db.GetCurrentIdx()
  194. }
  195. // SetCurrentIdx stores Idx in the StateDB
  196. func (s *StateDB) SetCurrentIdx(idx common.Idx) error {
  197. return s.db.SetCurrentIdx(idx)
  198. }
  199. // Reset resets the StateDB to the checkpoint at the given batchNum. Reset
  200. // does not delete the checkpoints between old current and the new current,
  201. // those checkpoints will remain in the storage, and eventually will be
  202. // deleted when MakeCheckpoint overwrites them.
  203. func (s *StateDB) Reset(batchNum common.BatchNum) error {
  204. log.Debugw("Making StateDB Reset", "batch", batchNum, "type", s.Typ)
  205. if err := s.db.Reset(batchNum); err != nil {
  206. return tracerr.Wrap(err)
  207. }
  208. if s.MT != nil {
  209. // open the MT for the current s.db
  210. mt, err := merkletree.NewMerkleTree(s.db.StorageWithPrefix(PrefixKeyMT), s.MT.MaxLevels())
  211. if err != nil {
  212. return tracerr.Wrap(err)
  213. }
  214. s.MT = mt
  215. }
  216. return nil
  217. }
  218. // GetAccount returns the account for the given Idx
  219. func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
  220. return GetAccountInTreeDB(s.db.DB(), idx)
  221. }
  222. func accountsIter(db db.Storage, fn func(a *common.Account) (bool, error)) error {
  223. idxDB := db.WithPrefix(PrefixKeyIdx)
  224. if err := idxDB.Iterate(func(k []byte, v []byte) (bool, error) {
  225. idx, err := common.IdxFromBytes(k)
  226. if err != nil {
  227. return false, tracerr.Wrap(err)
  228. }
  229. acc, err := GetAccountInTreeDB(db, idx)
  230. if err != nil {
  231. return false, tracerr.Wrap(err)
  232. }
  233. ok, err := fn(acc)
  234. if err != nil {
  235. return false, tracerr.Wrap(err)
  236. }
  237. return ok, nil
  238. }); err != nil {
  239. return tracerr.Wrap(err)
  240. }
  241. return nil
  242. }
  243. func getAccounts(db db.Storage) ([]common.Account, error) {
  244. accs := []common.Account{}
  245. if err := accountsIter(
  246. db,
  247. func(a *common.Account) (bool, error) {
  248. accs = append(accs, *a)
  249. return true, nil
  250. },
  251. ); err != nil {
  252. return nil, tracerr.Wrap(err)
  253. }
  254. return accs, nil
  255. }
  256. // TestGetAccounts returns all the accounts in the db. Use only in tests.
  257. // Outside tests getting all the accounts is discouraged because it's an
  258. // expensive operation, but if you must do it, use `LastRead()` method to get a
  259. // thread-safe and consistent view of the stateDB.
  260. func (s *StateDB) TestGetAccounts() ([]common.Account, error) {
  261. return getAccounts(s.db.DB())
  262. }
  263. // GetAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  264. // from ExitTree. GetAccount returns the account for the given Idx
  265. func GetAccountInTreeDB(sto db.Storage, idx common.Idx) (*common.Account, error) {
  266. idxBytes, err := idx.Bytes()
  267. if err != nil {
  268. return nil, tracerr.Wrap(err)
  269. }
  270. vBytes, err := sto.Get(append(PrefixKeyIdx, idxBytes[:]...))
  271. if err != nil {
  272. return nil, tracerr.Wrap(err)
  273. }
  274. accBytes, err := sto.Get(append(PrefixKeyAccHash, vBytes...))
  275. if err != nil {
  276. return nil, tracerr.Wrap(err)
  277. }
  278. var b [32 * common.NLeafElems]byte
  279. copy(b[:], accBytes)
  280. account, err := common.AccountFromBytes(b)
  281. if err != nil {
  282. return nil, tracerr.Wrap(err)
  283. }
  284. account.Idx = idx
  285. return account, nil
  286. }
  287. // CreateAccount creates a new Account in the StateDB for the given Idx. If
  288. // StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
  289. // MerkleTree, returning a CircomProcessorProof.
  290. func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  291. cpp, err := CreateAccountInTreeDB(s.db.DB(), s.MT, idx, account)
  292. if err != nil {
  293. return cpp, tracerr.Wrap(err)
  294. }
  295. // store idx by EthAddr & BJJ
  296. err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.BJJ, account.TokenID)
  297. return cpp, tracerr.Wrap(err)
  298. }
  299. // CreateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  300. // from ExitTree. Creates a new Account in the StateDB for the given Idx. If
  301. // StateDB.MT==nil, MerkleTree is not affected, otherwise updates the
  302. // MerkleTree, returning a CircomProcessorProof.
  303. func CreateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  304. // store at the DB the key: v, and value: leaf.Bytes()
  305. v, err := account.HashValue()
  306. if err != nil {
  307. return nil, tracerr.Wrap(err)
  308. }
  309. accountBytes, err := account.Bytes()
  310. if err != nil {
  311. return nil, tracerr.Wrap(err)
  312. }
  313. // store the Leaf value
  314. tx, err := sto.NewTx()
  315. if err != nil {
  316. return nil, tracerr.Wrap(err)
  317. }
  318. idxBytes, err := idx.Bytes()
  319. if err != nil {
  320. return nil, tracerr.Wrap(err)
  321. }
  322. _, err = tx.Get(append(PrefixKeyIdx, idxBytes[:]...))
  323. if tracerr.Unwrap(err) != db.ErrNotFound {
  324. return nil, tracerr.Wrap(ErrAccountAlreadyExists)
  325. }
  326. err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
  327. if err != nil {
  328. return nil, tracerr.Wrap(err)
  329. }
  330. err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
  331. if err != nil {
  332. return nil, tracerr.Wrap(err)
  333. }
  334. if err := tx.Commit(); err != nil {
  335. return nil, tracerr.Wrap(err)
  336. }
  337. if mt != nil {
  338. return mt.AddAndGetCircomProof(idx.BigInt(), v)
  339. }
  340. return nil, nil
  341. }
  342. // UpdateAccount updates the Account in the StateDB for the given Idx. If
  343. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  344. // MerkleTree, returning a CircomProcessorProof.
  345. func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  346. return UpdateAccountInTreeDB(s.db.DB(), s.MT, idx, account)
  347. }
  348. // UpdateAccountInTreeDB is abstracted from StateDB to be used from StateDB and
  349. // from ExitTree. Updates the Account in the StateDB for the given Idx. If
  350. // StateDB.mt==nil, MerkleTree is not affected, otherwise updates the
  351. // MerkleTree, returning a CircomProcessorProof.
  352. func UpdateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
  353. // store at the DB the key: v, and value: account.Bytes()
  354. v, err := account.HashValue()
  355. if err != nil {
  356. return nil, tracerr.Wrap(err)
  357. }
  358. accountBytes, err := account.Bytes()
  359. if err != nil {
  360. return nil, tracerr.Wrap(err)
  361. }
  362. tx, err := sto.NewTx()
  363. if err != nil {
  364. return nil, tracerr.Wrap(err)
  365. }
  366. err = tx.Put(append(PrefixKeyAccHash, v.Bytes()...), accountBytes[:])
  367. if err != nil {
  368. return nil, tracerr.Wrap(err)
  369. }
  370. idxBytes, err := idx.Bytes()
  371. if err != nil {
  372. return nil, tracerr.Wrap(err)
  373. }
  374. err = tx.Put(append(PrefixKeyIdx, idxBytes[:]...), v.Bytes())
  375. if err != nil {
  376. return nil, tracerr.Wrap(err)
  377. }
  378. if err := tx.Commit(); err != nil {
  379. return nil, tracerr.Wrap(err)
  380. }
  381. if mt != nil {
  382. proof, err := mt.Update(idx.BigInt(), v)
  383. return proof, tracerr.Wrap(err)
  384. }
  385. return nil, nil
  386. }
  387. // MTGetProof returns the CircomVerifierProof for a given Idx
  388. func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
  389. if s.MT == nil {
  390. return nil, tracerr.Wrap(ErrStateDBWithoutMT)
  391. }
  392. p, err := s.MT.GenerateSCVerifierProof(idx.BigInt(), s.MT.Root())
  393. if err != nil {
  394. return nil, tracerr.Wrap(err)
  395. }
  396. return p, nil
  397. }
  398. // Close the StateDB
  399. func (s *StateDB) Close() {
  400. s.db.Close()
  401. }
  402. // LocalStateDB represents the local StateDB which allows to make copies from
  403. // the synchronizer StateDB, and is used by the tx-selector and the
  404. // batch-builder. LocalStateDB is an in-memory storage.
  405. type LocalStateDB struct {
  406. *StateDB
  407. synchronizerStateDB *StateDB
  408. }
  409. // NewLocalStateDB returns a new LocalStateDB connected to the given
  410. // synchronizerDB. Checkpoints older than the value defined by `keep` will be
  411. // deleted.
  412. func NewLocalStateDB(path string, keep int, synchronizerDB *StateDB, typ TypeStateDB,
  413. nLevels int) (*LocalStateDB, error) {
  414. s, err := NewStateDB(path, keep, typ, nLevels)
  415. if err != nil {
  416. return nil, tracerr.Wrap(err)
  417. }
  418. return &LocalStateDB{
  419. s,
  420. synchronizerDB,
  421. }, nil
  422. }
  423. // Reset performs a reset in the LocaStateDB. If fromSynchronizer is true, it
  424. // gets the state from LocalStateDB.synchronizerStateDB for the given batchNum.
  425. // If fromSynchronizer is false, get the state from LocalStateDB checkpoints.
  426. func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) error {
  427. if fromSynchronizer {
  428. if err := l.db.ResetFromSynchronizer(batchNum, l.synchronizerStateDB.db); err != nil {
  429. return tracerr.Wrap(err)
  430. }
  431. // open the MT for the current s.db
  432. if l.MT != nil {
  433. mt, err := merkletree.NewMerkleTree(l.db.StorageWithPrefix(PrefixKeyMT),
  434. l.MT.MaxLevels())
  435. if err != nil {
  436. return tracerr.Wrap(err)
  437. }
  438. l.MT = mt
  439. }
  440. return nil
  441. }
  442. // use checkpoint from LocalStateDB
  443. return l.StateDB.Reset(batchNum)
  444. }