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.

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