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.

589 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. nextForgeL1TxsNum := int64(0)
  291. nextForgeL1TxsNumPtr, err := s.historyDB.GetLastL1TxsNum()
  292. if err != nil {
  293. return nil, err
  294. }
  295. if nextForgeL1TxsNumPtr != nil {
  296. nextForgeL1TxsNum = *nextForgeL1TxsNumPtr + 1
  297. }
  298. // Get newLastIdx that will be used to complete the accounts
  299. // idx, err := s.getIdx(rollupEvents)
  300. // if err != nil {
  301. // return nil, err
  302. // }
  303. // Get L1UserTX
  304. rollupData.l1Txs, err = getL1UserTx(rollupEvents.L1UserTx, blockNum)
  305. if err != nil {
  306. return nil, err
  307. }
  308. // Get ForgeBatch events to get the L1CoordinatorTxs
  309. for _, fbEvent := range rollupEvents.ForgeBatch {
  310. batchData := NewBatchData()
  311. position := 0
  312. // Get the input for each Tx
  313. forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(fbEvent.EthTxHash)
  314. if err != nil {
  315. return nil, err
  316. }
  317. forgeL1TxsNum := int64(0)
  318. // Check if this is a L1Batch to get L1 Tx from it
  319. if forgeBatchArgs.L1Batch {
  320. forgeL1TxsNum = nextForgeL1TxsNum
  321. // Get L1 User Txs from History DB
  322. // TODO: Get L1TX from HistoryDB filtered by toforgeL1txNum & fromidx = 0 and
  323. // update batch number and add accounts to createdAccounts updating idx
  324. // l1UserTxs, err := s.historyDB.GetL1UserTxs(nextForgeL1TxsNum)
  325. // If HistoryDB doesn't have L1UserTxs at
  326. // nextForgeL1TxsNum, check if they exist in
  327. // rollupData.l1Txs. This could happen because in a
  328. // block there could be multiple batches with L1Batch =
  329. // true (although it's a very rare case). If the
  330. // L1UserTxs are not in rollupData.l1Txs, use an empty
  331. // array (this happens when the L1UserTxs queue is
  332. // frozen but didn't store any tx).
  333. l1UserTxs := []common.L1Tx{}
  334. position = len(l1UserTxs)
  335. // Get L1 Coordinator Txs
  336. for _, l1CoordinatorTx := range forgeBatchArgs.L1CoordinatorTxs {
  337. l1CoordinatorTx.Position = position
  338. l1CoordinatorTx.ToForgeL1TxsNum = nextForgeL1TxsNum
  339. l1CoordinatorTx.UserOrigin = false
  340. l1CoordinatorTx.EthBlockNum = blockNum
  341. bn := new(common.BatchNum)
  342. *bn = common.BatchNum(fbEvent.BatchNum)
  343. l1CoordinatorTx.BatchNum = bn
  344. l1CoordinatorTx, err = common.NewL1Tx(l1CoordinatorTx)
  345. if err != nil {
  346. return nil, err
  347. }
  348. batchData.l1CoordinatorTxs = append(batchData.l1CoordinatorTxs, l1CoordinatorTx)
  349. // Check if we have to register an account
  350. // if l1CoordinatorTx.FromIdx == 0 {
  351. // account := common.Account{
  352. // // TODO: Uncommnent when common.account has IDx
  353. // // IDx: common.Idx(idx),
  354. // TokenID: l1CoordinatorTx.TokenID,
  355. // Nonce: 0,
  356. // Balance: l1CoordinatorTx.LoadAmount,
  357. // PublicKey: l1CoordinatorTx.FromBJJ,
  358. // EthAddr: l1CoordinatorTx.FromEthAddr,
  359. // }
  360. // idx++
  361. // batchData.createdAccounts = append(batchData.createdAccounts, &account)
  362. // numAccounts++
  363. // }
  364. position++
  365. }
  366. nextForgeL1TxsNum++
  367. }
  368. // Get L2Txs
  369. poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2Txs) // TODO: This is a big uggly, find a better way
  370. // Get exitTree
  371. // TODO: Get createdAccounts from ProcessTxs()
  372. // TODO: Get CollectedFees from ProcessTxs()
  373. // TODO: Pass forgeBatchArgs.FeeIdxCoordinator to ProcessTxs()
  374. _, exitInfo, err := s.stateDB.ProcessTxs(true, false, batchData.l1UserTxs, batchData.l1CoordinatorTxs, poolL2Txs)
  375. if err != nil {
  376. return nil, err
  377. }
  378. l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs) // TODO: This is a big uggly, find a better way
  379. batchData.l2Txs = append(batchData.l2Txs, l2Txs...)
  380. batchData.exitTree = exitInfo
  381. // Get Batch information
  382. batch := &common.Batch{
  383. BatchNum: common.BatchNum(fbEvent.BatchNum),
  384. EthBlockNum: blockNum,
  385. // ForgerAddr: , TODO: Get it from ethClient -> Add ForgerAddr to RollupEventForgeBatch
  386. // CollectedFees: , TODO: Clarify where to get them if they are still needed
  387. StateRoot: common.Hash(forgeBatchArgs.NewStRoot.Bytes()),
  388. NumAccounts: numAccounts,
  389. ExitRoot: common.Hash(forgeBatchArgs.NewExitRoot.Bytes()),
  390. ForgeL1TxsNum: forgeL1TxsNum,
  391. // SlotNum: TODO: Calculate once ethClient provides the info // calculate from blockNum + ethClient Constants
  392. }
  393. batchData.batch = batch
  394. rollupData.batches = append(rollupData.batches, batchData)
  395. }
  396. // Get Registered Tokens
  397. for _, eAddToken := range rollupEvents.AddToken {
  398. var token *common.Token
  399. token.TokenID = common.TokenID(eAddToken.TokenID)
  400. token.EthAddr = eAddToken.Address
  401. token.EthBlockNum = blockNum
  402. // TODO: Add external information consulting SC about it using Address
  403. rollupData.registeredTokens = append(rollupData.registeredTokens, token)
  404. }
  405. // TODO: rollupEvents.UpdateForgeL1L2BatchTimeout
  406. // TODO: rollupEvents.UpdateFeeAddToken
  407. // TODO: rollupEvents.WithdrawEvent
  408. // TODO: Emergency Mechanism
  409. // TODO: Variables
  410. // TODO: Constants
  411. return &rollupData, nil
  412. }
  413. // auctionSync gets information from the Auction Contract
  414. func (s *Synchronizer) auctionSync(blockNum int64) (*auctionData, error) {
  415. var auctionData = newAuctionData()
  416. // Get auction events in the block
  417. auctionEvents, _, err := s.ethClient.AuctionEventsByBlock(blockNum)
  418. if err != nil {
  419. return nil, err
  420. }
  421. // Get bids
  422. for _, eNewBid := range auctionEvents.NewBid {
  423. bid := &common.Bid{
  424. SlotNum: common.SlotNum(eNewBid.Slot),
  425. BidValue: eNewBid.BidAmount,
  426. ForgerAddr: eNewBid.CoordinatorForger,
  427. EthBlockNum: blockNum,
  428. }
  429. auctionData.bids = append(auctionData.bids, bid)
  430. }
  431. // Get Coordinators
  432. for _, eNewCoordinator := range auctionEvents.NewCoordinator {
  433. coordinator := &common.Coordinator{
  434. Forger: eNewCoordinator.ForgerAddress,
  435. WithdrawAddr: eNewCoordinator.WithdrawalAddress,
  436. URL: eNewCoordinator.CoordinatorURL,
  437. }
  438. auctionData.coordinators = append(auctionData.coordinators, coordinator)
  439. }
  440. // TODO: NewSlotDeadline
  441. // TODO: NewClosedAuctionSlots
  442. // TODO: NewOutbidding
  443. // TODO: NewDonationAddress
  444. // TODO: NewBootCoordinator
  445. // TODO: NewOpenAuctionSlots
  446. // TODO: NewAllocationRatio
  447. // TODO: NewForgeAllocated
  448. // TODO: NewDefaultSlotSetBid
  449. // TODO: NewForge
  450. // TODO: HEZClaimed
  451. // TODO: Think about separating new coordinaors from coordinator updated
  452. // Get Coordinators from updates
  453. for _, eCoordinatorUpdated := range auctionEvents.CoordinatorUpdated {
  454. coordinator := &common.Coordinator{
  455. Forger: eCoordinatorUpdated.ForgerAddress,
  456. WithdrawAddr: eCoordinatorUpdated.WithdrawalAddress,
  457. URL: eCoordinatorUpdated.CoordinatorURL,
  458. }
  459. auctionData.coordinators = append(auctionData.coordinators, coordinator)
  460. }
  461. // TODO: VARS
  462. // TODO: CONSTANTS
  463. return auctionData, nil
  464. }
  465. // wdelayerSync gets information from the Withdrawal Delayer Contract
  466. func (s *Synchronizer) wdelayerSync(blockNum int64) (*common.WithdrawalDelayerVars, error) {
  467. // TODO: VARS
  468. // TODO: CONSTANTS
  469. return nil, nil
  470. }
  471. // func (s *Synchronizer) getIdx(rollupEvents *eth.RollupEvents) (int64, error) {
  472. // // TODO: FIXME: There will be an error here when `len(rollupEvents.ForgeBatch) == 0`
  473. // lastForgeBatch := rollupEvents.ForgeBatch[len(rollupEvents.ForgeBatch)-1]
  474. //
  475. // // TODO: RollupForgeBatchArgs is already called in `rollupSync`.
  476. // // Ideally it should not need to be called twice for the same batch.
  477. // // Get the input for forgeBatch
  478. // forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(lastForgeBatch.EthTxHash)
  479. // if err != nil {
  480. // return 0, err
  481. // }
  482. //
  483. // return forgeBatchArgs.NewLastIdx + 1, nil
  484. // }
  485. func getL1UserTx(l1UserTxEvents []eth.RollupEventL1UserTx, blockNum int64) ([]*common.L1Tx, error) {
  486. l1Txs := make([]*common.L1Tx, 0)
  487. for _, eL1UserTx := range l1UserTxEvents {
  488. // Fill aditional Tx fields
  489. eL1UserTx.L1Tx.ToForgeL1TxsNum = eL1UserTx.ToForgeL1TxsNum
  490. eL1UserTx.L1Tx.Position = eL1UserTx.Position
  491. eL1UserTx.L1Tx.UserOrigin = true
  492. eL1UserTx.L1Tx.EthBlockNum = blockNum
  493. nL1Tx, err := common.NewL1Tx(&eL1UserTx.L1Tx)
  494. if err != nil {
  495. return nil, err
  496. }
  497. eL1UserTx.L1Tx = *nL1Tx
  498. l1Txs = append(l1Txs, &eL1UserTx.L1Tx)
  499. }
  500. return l1Txs, nil
  501. }