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.

600 lines
18 KiB

  1. package synchronizer
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "sync"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/db/historydb"
  9. "github.com/hermeznetwork/hermez-node/db/statedb"
  10. "github.com/hermeznetwork/hermez-node/eth"
  11. "github.com/hermeznetwork/hermez-node/log"
  12. )
  13. var (
  14. // ErrNotAbleToSync is used when there is not possible to find a valid block to sync
  15. ErrNotAbleToSync = errors.New("it has not been possible to synchronize any block")
  16. )
  17. // rollupData contains information returned by the Rollup SC
  18. type rollupData struct {
  19. l1UserTxs []common.L1Tx
  20. batches []historydb.BatchData
  21. // withdrawals []*common.ExitInfo
  22. registeredTokens []common.Token
  23. vars *common.RollupVars
  24. }
  25. // NewRollupData creates an empty rollupData with the slices initialized.
  26. func newRollupData() rollupData {
  27. return rollupData{
  28. l1UserTxs: make([]common.L1Tx, 0),
  29. batches: make([]historydb.BatchData, 0),
  30. // withdrawals: make([]*common.ExitInfo, 0),
  31. registeredTokens: make([]common.Token, 0),
  32. }
  33. }
  34. // auctionData contains information returned by the Action SC
  35. type auctionData struct {
  36. bids []common.Bid
  37. coordinators []common.Coordinator
  38. vars *common.AuctionVars
  39. }
  40. // newAuctionData creates an empty auctionData with the slices initialized.
  41. func newAuctionData() *auctionData {
  42. return &auctionData{
  43. bids: make([]common.Bid, 0),
  44. coordinators: make([]common.Coordinator, 0),
  45. }
  46. }
  47. type wdelayerData struct {
  48. vars *common.WithdrawDelayerVars
  49. }
  50. // BatchData contains information about Batches from the contracts
  51. // type BatchData struct {
  52. // l1UserTxs []*common.L1Tx
  53. // l1CoordinatorTxs []*common.L1Tx
  54. // l2Txs []*common.L2Tx
  55. // createdAccounts []*common.Account
  56. // exitTree []*common.ExitInfo
  57. // batch *common.Batch
  58. // }
  59. // NewBatchData creates an empty BatchData with the slices initialized.
  60. // func NewBatchData() *BatchData {
  61. // return &BatchData{
  62. // l1UserTxs: make([]*common.L1Tx, 0),
  63. // l1CoordinatorTxs: make([]*common.L1Tx, 0),
  64. // l2Txs: make([]*common.L2Tx, 0),
  65. // createdAccounts: make([]*common.Account, 0),
  66. // exitTree: make([]*common.ExitInfo, 0),
  67. // }
  68. // }
  69. // BlockData contains information about Blocks from the contracts
  70. // type blockData struct {
  71. // Block *common.Block
  72. // // Rollup
  73. // L1Txs []*common.L1Tx // TODO: Answer: User? Coordinator? Both?
  74. // Batches []*BatchData // TODO: Also contains L1Txs!
  75. // // withdrawals []*common.ExitInfo // TODO
  76. // RegisteredTokens []common.Token
  77. // RollupVars *common.RollupVars
  78. // // Auction
  79. // Bids []*common.Bid
  80. // Coordinators []*common.Coordinator
  81. // AuctionVars *common.AuctionVars
  82. // // WithdrawalDelayer
  83. // WithdrawalDelayerVars *common.WithdrawalDelayerVars
  84. // }
  85. // Synchronizer implements the Synchronizer type
  86. type Synchronizer struct {
  87. ethClient eth.ClientInterface
  88. auctionConstants eth.AuctionConstants
  89. historyDB *historydb.HistoryDB
  90. stateDB *statedb.StateDB
  91. firstSavedBlock *common.Block
  92. mux sync.Mutex
  93. }
  94. // NewSynchronizer creates a new Synchronizer
  95. func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) (*Synchronizer, error) {
  96. auctionConstants, err := ethClient.AuctionConstants()
  97. if err != nil {
  98. return nil, err
  99. }
  100. return &Synchronizer{
  101. ethClient: ethClient,
  102. auctionConstants: *auctionConstants,
  103. historyDB: historyDB,
  104. stateDB: stateDB,
  105. }, nil
  106. }
  107. // TODO: Be smart about locking: only lock during the read/write operations
  108. // Sync updates History and State DB with information from the blockchain
  109. // TODO: Return true if a new block was processed
  110. // TODO: Add argument: maximum number of blocks to process
  111. // TODO: Check reorgs in the middle of syncing a block. Probably make
  112. // rollupSync, auctionSync and withdrawalSync return the block hash.
  113. func (s *Synchronizer) Sync(ctx context.Context) error {
  114. // Avoid new sync while performing one
  115. s.mux.Lock()
  116. defer s.mux.Unlock()
  117. var nextBlockNum int64 // next block number to sync
  118. // Get lastSavedBlock from History DB
  119. lastSavedBlock, err := s.historyDB.GetLastBlock()
  120. if err != nil && err != sql.ErrNoRows {
  121. return err
  122. }
  123. // If we don't have any stored block, we must do a full sync starting from the rollup genesis block
  124. if err == sql.ErrNoRows {
  125. nextBlockNum = s.auctionConstants.GenesisBlockNum
  126. } else {
  127. // Get the latest block we have in History DB from blockchain to detect a reorg
  128. ethBlock, err := s.ethClient.EthBlockByNumber(ctx, lastSavedBlock.EthBlockNum)
  129. if err != nil {
  130. return err
  131. }
  132. if ethBlock.Hash != lastSavedBlock.Hash {
  133. // Reorg detected
  134. log.Debugf("Reorg Detected...")
  135. _, err := s.reorg(lastSavedBlock)
  136. if err != nil {
  137. return err
  138. }
  139. lastSavedBlock, err = s.historyDB.GetLastBlock()
  140. if err != nil {
  141. return err
  142. }
  143. }
  144. nextBlockNum = lastSavedBlock.EthBlockNum + 1
  145. }
  146. log.Debugf("Syncing...")
  147. // Get latest blockNum in blockchain
  148. latestBlockNum, err := s.ethClient.EthCurrentBlock()
  149. if err != nil {
  150. return err
  151. }
  152. log.Debugf("Blocks to sync: %v (firstBlockToSync: %v, latestBlock: %v)", latestBlockNum-nextBlockNum+1, nextBlockNum, latestBlockNum)
  153. for nextBlockNum <= latestBlockNum {
  154. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), nextBlockNum)
  155. if err != nil {
  156. return err
  157. }
  158. // TODO: Check that the obtianed ethBlock.ParentHash == prevEthBlock.Hash; if not, reorg!
  159. // TODO: Send the ethHash in rollupSync(), auctionSync() and
  160. // wdelayerSync() and make sure they all use the same block
  161. // hash.
  162. // Get data from the rollup contract
  163. rollupData, err := s.rollupSync(nextBlockNum)
  164. if err != nil {
  165. return err
  166. }
  167. // Get data from the auction contract
  168. auctionData, err := s.auctionSync(nextBlockNum)
  169. if err != nil {
  170. return err
  171. }
  172. // Get data from the WithdrawalDelayer contract
  173. wdelayerData, err := s.wdelayerSync(nextBlockNum)
  174. if err != nil {
  175. return err
  176. }
  177. // Group all the block data into the structs to save into HistoryDB
  178. var blockData historydb.BlockData
  179. blockData.Block = ethBlock
  180. if rollupData != nil {
  181. blockData.L1UserTxs = rollupData.l1UserTxs
  182. blockData.Batches = rollupData.batches
  183. // blockData.withdrawals = rollupData.withdrawals // TODO
  184. blockData.RegisteredTokens = rollupData.registeredTokens
  185. blockData.RollupVars = rollupData.vars
  186. }
  187. if auctionData != nil {
  188. blockData.Bids = auctionData.bids
  189. blockData.Coordinators = auctionData.coordinators
  190. blockData.AuctionVars = auctionData.vars
  191. }
  192. if wdelayerData != nil {
  193. blockData.WithdrawDelayerVars = wdelayerData.vars
  194. }
  195. // Add rollupData and auctionData once the method is updated
  196. // TODO: Save Whole Struct -> AddBlockSCData(blockData)
  197. log.Debugw("Sync()", "block", blockData)
  198. // err = s.historyDB.AddBlock(blockData.Block)
  199. // if err != nil {
  200. // return err
  201. // }
  202. err = s.historyDB.AddBlockSCData(&blockData)
  203. if err != nil {
  204. return err
  205. }
  206. nextBlockNum++
  207. }
  208. return nil
  209. }
  210. // reorg manages a reorg, updating History and State DB as needed. Keeps
  211. // checking previous blocks from the HistoryDB against the blockchain until a
  212. // block hash match is found. All future blocks in the HistoryDB and
  213. // corresponding batches in StateBD are discarded. Returns the last valid
  214. // blockNum from the HistoryDB.
  215. func (s *Synchronizer) reorg(uncleBlock *common.Block) (int64, error) {
  216. var block *common.Block
  217. blockNum := uncleBlock.EthBlockNum
  218. found := false
  219. log.Debugf("Reorg first uncle block: %v", blockNum)
  220. // Iterate History DB and the blokchain looking for the latest valid block
  221. for !found && blockNum > s.firstSavedBlock.EthBlockNum {
  222. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), blockNum)
  223. if err != nil {
  224. return 0, err
  225. }
  226. block, err = s.historyDB.GetBlock(blockNum)
  227. if err != nil {
  228. return 0, err
  229. }
  230. if block.Hash == ethBlock.Hash {
  231. found = true
  232. log.Debugf("Found valid block: %v", blockNum)
  233. } else {
  234. log.Debugf("Discarding block: %v", blockNum)
  235. }
  236. blockNum--
  237. }
  238. if found {
  239. // Set History DB and State DB to the correct state
  240. err := s.historyDB.Reorg(block.EthBlockNum)
  241. if err != nil {
  242. return 0, err
  243. }
  244. batchNum, err := s.historyDB.GetLastBatchNum()
  245. if err != nil && err != sql.ErrNoRows {
  246. return 0, err
  247. }
  248. if batchNum != 0 {
  249. err = s.stateDB.Reset(batchNum)
  250. if err != nil {
  251. return 0, err
  252. }
  253. }
  254. return block.EthBlockNum, nil
  255. }
  256. return 0, ErrNotAbleToSync
  257. }
  258. // Status returns current status values from the Synchronizer
  259. func (s *Synchronizer) Status() (*common.SyncStatus, error) {
  260. // Avoid possible inconsistencies
  261. s.mux.Lock()
  262. defer s.mux.Unlock()
  263. var status *common.SyncStatus
  264. // TODO: Join all queries to the DB into a single transaction so that
  265. // we can remove the mutex locking here:
  266. // - HistoryDB.GetLastBlock
  267. // - HistoryDB.GetLastBatchNum
  268. // - HistoryDB.GetCurrentForgerAddr
  269. // - HistoryDB.GetNextForgerAddr
  270. // Get latest block in History DB
  271. lastSavedBlock, err := s.historyDB.GetLastBlock()
  272. if err != nil {
  273. return nil, err
  274. }
  275. status.CurrentBlock = lastSavedBlock.EthBlockNum
  276. // Get latest batch in History DB
  277. lastSavedBatch, err := s.historyDB.GetLastBatchNum()
  278. if err != nil && err != sql.ErrNoRows {
  279. return nil, err
  280. }
  281. status.CurrentBatch = lastSavedBatch
  282. // Get latest blockNum in blockchain
  283. latestBlockNum, err := s.ethClient.EthCurrentBlock()
  284. if err != nil {
  285. return nil, err
  286. }
  287. // TODO: Get CurrentForgerAddr & NextForgerAddr from the Auction SC / Or from the HistoryDB
  288. // Check if Synchronizer is synchronized
  289. status.Synchronized = status.CurrentBlock == latestBlockNum
  290. return status, nil
  291. }
  292. // rollupSync gets information from the Rollup Contract
  293. func (s *Synchronizer) rollupSync(blockNum int64) (*rollupData, error) {
  294. var rollupData = newRollupData()
  295. // var forgeL1TxsNum int64
  296. var numAccounts int
  297. // Get rollup events in the block
  298. rollupEvents, _, err := s.ethClient.RollupEventsByBlock(blockNum)
  299. if err != nil {
  300. return nil, err
  301. }
  302. // TODO: Replace GetLastL1TxsNum by GetNextL1TxsNum
  303. var nextForgeL1TxsNum int64
  304. nextForgeL1TxsNumPtr, err := s.historyDB.GetLastL1TxsNum()
  305. if err != nil {
  306. return nil, err
  307. }
  308. if nextForgeL1TxsNumPtr != nil {
  309. nextForgeL1TxsNum = *nextForgeL1TxsNumPtr + 1
  310. } else {
  311. nextForgeL1TxsNum = 0
  312. }
  313. // Get newLastIdx that will be used to complete the accounts
  314. // idx, err := s.getIdx(rollupEvents)
  315. // if err != nil {
  316. // return nil, err
  317. // }
  318. // Get L1UserTX
  319. rollupData.l1UserTxs, err = getL1UserTx(rollupEvents.L1UserTx, blockNum)
  320. if err != nil {
  321. return nil, err
  322. }
  323. // Get ForgeBatch events to get the L1CoordinatorTxs
  324. for _, evtForgeBatch := range rollupEvents.ForgeBatch {
  325. batchData := historydb.NewBatchData()
  326. position := 0
  327. // Get the input for each Tx
  328. forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(evtForgeBatch.EthTxHash)
  329. if err != nil {
  330. return nil, err
  331. }
  332. forgeL1TxsNum := nextForgeL1TxsNum
  333. // Check if this is a L1Batch to get L1 Tx from it
  334. if forgeBatchArgs.L1Batch {
  335. // Get L1 User Txs from History DB
  336. // TODO: Get L1TX from HistoryDB filtered by toforgeL1txNum & fromidx = 0 and
  337. // update batch number and add accounts to createdAccounts updating idx
  338. // l1UserTxs, err := s.historyDB.GetL1UserTxs(nextForgeL1TxsNum)
  339. // If HistoryDB doesn't have L1UserTxs at
  340. // nextForgeL1TxsNum, check if they exist in
  341. // rollupData.l1Txs. This could happen because in a
  342. // block there could be multiple batches with L1Batch =
  343. // true (although it's a very rare case). If the
  344. // L1UserTxs are not in rollupData.l1Txs, use an empty
  345. // array (this happens when the L1UserTxs queue is
  346. // frozen but didn't store any tx).
  347. l1UserTxs := []common.L1Tx{}
  348. position = len(l1UserTxs)
  349. // Get L1 Coordinator Txs
  350. for i := 0; i < len(forgeBatchArgs.L1CoordinatorTxs); i++ {
  351. l1CoordinatorTx := forgeBatchArgs.L1CoordinatorTxs[i]
  352. l1CoordinatorTx.Position = position
  353. l1CoordinatorTx.ToForgeL1TxsNum = &forgeL1TxsNum
  354. l1CoordinatorTx.UserOrigin = false
  355. l1CoordinatorTx.EthBlockNum = blockNum
  356. bn := new(common.BatchNum)
  357. *bn = common.BatchNum(evtForgeBatch.BatchNum)
  358. l1CoordinatorTx.BatchNum = bn
  359. l1Tx, err := common.NewL1Tx(&l1CoordinatorTx)
  360. if err != nil {
  361. return nil, err
  362. }
  363. batchData.L1CoordinatorTxs = append(batchData.L1CoordinatorTxs, *l1Tx)
  364. // Check if we have to register an account
  365. // if l1CoordinatorTx.FromIdx == 0 {
  366. // account := common.Account{
  367. // // TODO: Uncommnent when common.account has IDx
  368. // // IDx: common.Idx(idx),
  369. // TokenID: l1CoordinatorTx.TokenID,
  370. // Nonce: 0,
  371. // Balance: l1CoordinatorTx.LoadAmount,
  372. // PublicKey: l1CoordinatorTx.FromBJJ,
  373. // EthAddr: l1CoordinatorTx.FromEthAddr,
  374. // }
  375. // idx++
  376. // batchData.createdAccounts = append(batchData.createdAccounts, &account)
  377. // numAccounts++
  378. // }
  379. position++
  380. }
  381. nextForgeL1TxsNum++
  382. }
  383. // Get L2Txs
  384. poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // TODO: This is a big uggly, find a better way
  385. // Get exitTree
  386. // TODO: Get createdAccounts from ProcessTxs()
  387. // TODO: Get CollectedFees from ProcessTxs()
  388. // TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs()
  389. _, exitInfo, err := s.stateDB.ProcessTxs(batchData.L1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs)
  390. if err != nil {
  391. return nil, err
  392. }
  393. l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // TODO: This is a big uggly, find a better way
  394. if err != nil {
  395. return nil, err
  396. }
  397. batchData.L2Txs = append(batchData.L2Txs, l2Txs...)
  398. batchData.ExitTree = exitInfo
  399. // Get Batch information
  400. batch := &common.Batch{
  401. BatchNum: common.BatchNum(evtForgeBatch.BatchNum),
  402. EthBlockNum: blockNum,
  403. // ForgerAddr: , TODO: Get it from ethClient -> Add ForgerAddr to RollupEventForgeBatch
  404. // CollectedFees: , TODO: Clarify where to get them if they are still needed
  405. StateRoot: common.Hash(forgeBatchArgs.NewStRoot.Bytes()),
  406. NumAccounts: numAccounts,
  407. ExitRoot: common.Hash(forgeBatchArgs.NewExitRoot.Bytes()),
  408. ForgeL1TxsNum: &forgeL1TxsNum,
  409. // SlotNum: TODO: Calculate once ethClient provides the info // calculate from blockNum + ethClient Constants
  410. }
  411. batchData.Batch = batch
  412. rollupData.batches = append(rollupData.batches, *batchData)
  413. }
  414. // Get Registered Tokens
  415. for _, evtAddToken := range rollupEvents.AddToken {
  416. var token common.Token
  417. token.TokenID = common.TokenID(evtAddToken.TokenID)
  418. token.EthAddr = evtAddToken.TokenAddress
  419. token.EthBlockNum = blockNum
  420. // TODO: Add external information consulting SC about it using Address
  421. token.Name = "TODO"
  422. token.Symbol = "TODO"
  423. token.Decimals = 8 // TODO
  424. rollupData.registeredTokens = append(rollupData.registeredTokens, token)
  425. }
  426. // TODO: rollupEvents.UpdateForgeL1L2BatchTimeout
  427. // TODO: rollupEvents.UpdateFeeAddToken
  428. // TODO: rollupEvents.WithdrawEvent
  429. // TODO: Emergency Mechanism
  430. // TODO: Variables
  431. // TODO: Constants
  432. return &rollupData, nil
  433. }
  434. // auctionSync gets information from the Auction Contract
  435. func (s *Synchronizer) auctionSync(blockNum int64) (*auctionData, error) {
  436. var auctionData = newAuctionData()
  437. // Get auction events in the block
  438. auctionEvents, _, err := s.ethClient.AuctionEventsByBlock(blockNum)
  439. if err != nil {
  440. return nil, err
  441. }
  442. // Get bids
  443. for _, evtNewBid := range auctionEvents.NewBid {
  444. bid := common.Bid{
  445. SlotNum: common.SlotNum(evtNewBid.Slot),
  446. BidValue: evtNewBid.BidAmount,
  447. Bidder: evtNewBid.Bidder,
  448. EthBlockNum: blockNum,
  449. }
  450. auctionData.bids = append(auctionData.bids, bid)
  451. }
  452. // Get Coordinators
  453. for _, evtSetCoordinator := range auctionEvents.SetCoordinator {
  454. coordinator := common.Coordinator{
  455. Bidder: evtSetCoordinator.BidderAddress,
  456. Forger: evtSetCoordinator.ForgerAddress,
  457. URL: evtSetCoordinator.CoordinatorURL,
  458. }
  459. auctionData.coordinators = append(auctionData.coordinators, coordinator)
  460. }
  461. // TODO: NewSlotDeadline
  462. // TODO: NewClosedAuctionSlots
  463. // TODO: NewOutbidding
  464. // TODO: NewDonationAddress
  465. // TODO: NewBootCoordinator
  466. // TODO: NewOpenAuctionSlots
  467. // TODO: NewAllocationRatio
  468. // TODO: NewForgeAllocated
  469. // TODO: NewDefaultSlotSetBid
  470. // TODO: NewForge
  471. // TODO: HEZClaimed
  472. // TODO: VARS
  473. // TODO: CONSTANTS
  474. return auctionData, nil
  475. }
  476. // wdelayerSync gets information from the Withdrawal Delayer Contract
  477. func (s *Synchronizer) wdelayerSync(blockNum int64) (*wdelayerData, error) {
  478. // TODO: VARS
  479. // TODO: CONSTANTS
  480. return nil, nil
  481. }
  482. // func (s *Synchronizer) getIdx(rollupEvents *eth.RollupEvents) (int64, error) {
  483. // // TODO: FIXME: There will be an error here when `len(rollupEvents.ForgeBatch) == 0`
  484. // lastForgeBatch := rollupEvents.ForgeBatch[len(rollupEvents.ForgeBatch)-1]
  485. //
  486. // // TODO: RollupForgeBatchArgs is already called in `rollupSync`.
  487. // // Ideally it should not need to be called twice for the same batch.
  488. // // Get the input for forgeBatch
  489. // forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(lastForgeBatch.EthTxHash)
  490. // if err != nil {
  491. // return 0, err
  492. // }
  493. //
  494. // return forgeBatchArgs.NewLastIdx + 1, nil
  495. // }
  496. func getL1UserTx(eventsL1UserTx []eth.RollupEventL1UserTx, blockNum int64) ([]common.L1Tx, error) {
  497. l1Txs := make([]common.L1Tx, 0)
  498. for _, evtL1UserTx := range eventsL1UserTx {
  499. // Fill aditional Tx fields
  500. toForge := evtL1UserTx.ToForgeL1TxsNum
  501. evtL1UserTx.L1UserTx.ToForgeL1TxsNum = &toForge
  502. evtL1UserTx.L1UserTx.Position = evtL1UserTx.Position
  503. evtL1UserTx.L1UserTx.UserOrigin = true
  504. evtL1UserTx.L1UserTx.EthBlockNum = blockNum
  505. nL1Tx, err := common.NewL1Tx(&evtL1UserTx.L1UserTx)
  506. if err != nil {
  507. return nil, err
  508. }
  509. evtL1UserTx.L1UserTx = *nL1Tx
  510. l1Txs = append(l1Txs, evtL1UserTx.L1UserTx)
  511. }
  512. return l1Txs, nil
  513. }