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.

559 lines
15 KiB

  1. package synchronizer
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "strconv"
  7. "sync"
  8. "github.com/hermeznetwork/hermez-node/common"
  9. "github.com/hermeznetwork/hermez-node/db/historydb"
  10. "github.com/hermeznetwork/hermez-node/db/statedb"
  11. "github.com/hermeznetwork/hermez-node/eth"
  12. "github.com/hermeznetwork/hermez-node/log"
  13. )
  14. const (
  15. blocksToSync = 20 // TODO: This will be deleted once we can get the firstSavedBlock from the ethClient
  16. )
  17. var (
  18. // ErrNotAbleToSync is used when there is not possible to find a valid block to sync
  19. ErrNotAbleToSync = errors.New("it has not been possible to synchronize any block")
  20. )
  21. // rollupData contains information returned by the Rollup SC
  22. type rollupData struct {
  23. l1Txs []*common.L1Tx
  24. batches []*BatchData
  25. // withdrawals []*common.ExitInfo
  26. registeredTokens []*common.Token
  27. rollupVars *common.RollupVars
  28. }
  29. // NewRollupData creates an empty rollupData with the slices initialized.
  30. func newRollupData() rollupData {
  31. return rollupData{
  32. l1Txs: make([]*common.L1Tx, 0),
  33. batches: make([]*BatchData, 0),
  34. // withdrawals: make([]*common.ExitInfo, 0),
  35. registeredTokens: make([]*common.Token, 0),
  36. }
  37. }
  38. // auctionData contains information returned by the Action SC
  39. type auctionData struct {
  40. bids []*common.Bid
  41. coordinators []*common.Coordinator
  42. auctionVars *common.AuctionVars
  43. }
  44. // newAuctionData creates an empty auctionData with the slices initialized.
  45. func newAuctionData() *auctionData {
  46. return &auctionData{
  47. bids: make([]*common.Bid, 0),
  48. coordinators: make([]*common.Coordinator, 0),
  49. }
  50. }
  51. // BatchData contains information about Batches from the contracts
  52. type BatchData struct {
  53. l1UserTxs []*common.L1Tx
  54. l1CoordinatorTxs []*common.L1Tx
  55. l2Txs []*common.L2Tx
  56. registeredAccounts []*common.Account
  57. exitTree []*common.ExitInfo
  58. batch *common.Batch
  59. }
  60. // NewBatchData creates an empty BatchData with the slices initialized.
  61. func NewBatchData() *BatchData {
  62. return &BatchData{
  63. l1UserTxs: make([]*common.L1Tx, 0),
  64. l1CoordinatorTxs: make([]*common.L1Tx, 0),
  65. l2Txs: make([]*common.L2Tx, 0),
  66. registeredAccounts: make([]*common.Account, 0),
  67. exitTree: make([]*common.ExitInfo, 0),
  68. }
  69. }
  70. // BlockData contains information about Blocks from the contracts
  71. type BlockData struct {
  72. block *common.Block
  73. // Rollup
  74. l1Txs []*common.L1Tx
  75. batches []*BatchData
  76. // withdrawals []*common.ExitInfo
  77. registeredTokens []*common.Token
  78. rollupVars *common.RollupVars
  79. // Auction
  80. bids []*common.Bid
  81. coordinators []*common.Coordinator
  82. auctionVars *common.AuctionVars
  83. // WithdrawalDelayer
  84. withdrawalDelayerVars *common.WithdrawalDelayerVars
  85. }
  86. // Synchronizer implements the Synchronizer type
  87. type Synchronizer struct {
  88. ethClient *eth.Client
  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.Client, historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *Synchronizer {
  96. s := &Synchronizer{
  97. ethClient: ethClient,
  98. historyDB: historyDB,
  99. stateDB: stateDB,
  100. }
  101. return s
  102. }
  103. // Sync updates History and State DB with information from the blockchain
  104. func (s *Synchronizer) Sync() error {
  105. // Avoid new sync while performing one
  106. s.mux.Lock()
  107. defer s.mux.Unlock()
  108. // TODO: Get this information from ethClient once it's implemented
  109. // for the moment we will get the latestblock - 20 as firstSavedBlock
  110. latestBlock, err := s.ethClient.EthBlockByNumber(context.Background(), 0)
  111. if err != nil {
  112. return err
  113. }
  114. s.firstSavedBlock, err = s.ethClient.EthBlockByNumber(context.Background(), latestBlock.EthBlockNum-blocksToSync)
  115. if err != nil {
  116. return err
  117. }
  118. // Get lastSavedBlock from History DB
  119. lastSavedBlock, err := s.historyDB.GetLastBlock()
  120. if err != nil && err != sql.ErrNoRows {
  121. return err
  122. }
  123. // Check if we got a block or nil
  124. // In case of nil we must do a full sync
  125. if lastSavedBlock == nil || lastSavedBlock.EthBlockNum == 0 {
  126. lastSavedBlock = s.firstSavedBlock
  127. } else {
  128. // Get the latest block we have in History DB from blockchain to detect a reorg
  129. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), lastSavedBlock.EthBlockNum)
  130. if err != nil {
  131. return err
  132. }
  133. if ethBlock.Hash != lastSavedBlock.Hash {
  134. // Reorg detected
  135. log.Debugf("Reorg Detected...")
  136. err := s.reorg(lastSavedBlock)
  137. if err != nil {
  138. return err
  139. }
  140. lastSavedBlock, err = s.historyDB.GetLastBlock()
  141. if err != nil {
  142. return err
  143. }
  144. }
  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 (lastSavedBlock: %v, latestBlock: %v)", latestBlockNum-lastSavedBlock.EthBlockNum, lastSavedBlock.EthBlockNum, latestBlockNum)
  153. for lastSavedBlock.EthBlockNum < latestBlockNum {
  154. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), lastSavedBlock.EthBlockNum+1)
  155. if err != nil {
  156. return err
  157. }
  158. // Get data from the rollup contract
  159. rollupData, err := s.rollupSync(ethBlock)
  160. if err != nil {
  161. return err
  162. }
  163. // Get data from the auction contract
  164. auctionData, err := s.auctionSync(ethBlock)
  165. if err != nil {
  166. return err
  167. }
  168. // Get data from the WithdrawalDelayer contract
  169. wdelayerData, err := s.wdelayerSync(ethBlock)
  170. if err != nil {
  171. return err
  172. }
  173. // Group all the block data into the structs to save into HistoryDB
  174. var blockData BlockData
  175. blockData.block = ethBlock
  176. if rollupData != nil {
  177. blockData.l1Txs = rollupData.l1Txs
  178. blockData.batches = rollupData.batches
  179. // blockData.withdrawals = rollupData.withdrawals
  180. blockData.registeredTokens = rollupData.registeredTokens
  181. blockData.rollupVars = rollupData.rollupVars
  182. }
  183. if auctionData != nil {
  184. blockData.bids = auctionData.bids
  185. blockData.coordinators = auctionData.coordinators
  186. blockData.auctionVars = auctionData.auctionVars
  187. }
  188. if wdelayerData != nil {
  189. blockData.withdrawalDelayerVars = wdelayerData
  190. }
  191. // Add rollupData and auctionData once the method is updated
  192. // TODO: Save Whole Struct -> AddBlockSCData(blockData)
  193. err = s.historyDB.AddBlock(blockData.block)
  194. if err != nil {
  195. return err
  196. }
  197. // We get the block on every iteration
  198. lastSavedBlock, err = s.historyDB.GetLastBlock()
  199. if err != nil {
  200. return err
  201. }
  202. }
  203. return nil
  204. }
  205. // reorg manages a reorg, updating History and State DB as needed
  206. func (s *Synchronizer) reorg(uncleBlock *common.Block) error {
  207. var block *common.Block
  208. blockNum := uncleBlock.EthBlockNum
  209. found := false
  210. log.Debugf("Reorg first uncle block: %v", blockNum)
  211. // Iterate History DB and the blokchain looking for the latest valid block
  212. for !found && blockNum > s.firstSavedBlock.EthBlockNum {
  213. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), blockNum)
  214. if err != nil {
  215. return err
  216. }
  217. block, err = s.historyDB.GetBlock(blockNum)
  218. if err != nil {
  219. return err
  220. }
  221. if block.Hash == ethBlock.Hash {
  222. found = true
  223. log.Debugf("Found valid block: %v", blockNum)
  224. } else {
  225. log.Debugf("Discarding block: %v", blockNum)
  226. }
  227. blockNum--
  228. }
  229. if found {
  230. // Set History DB and State DB to the correct state
  231. err := s.historyDB.Reorg(block.EthBlockNum)
  232. if err != nil {
  233. return err
  234. }
  235. batchNum, err := s.historyDB.GetLastBatchNum()
  236. if err != nil && err != sql.ErrNoRows {
  237. return err
  238. }
  239. if batchNum != 0 {
  240. err = s.stateDB.Reset(batchNum)
  241. if err != nil {
  242. return err
  243. }
  244. }
  245. return nil
  246. }
  247. return ErrNotAbleToSync
  248. }
  249. // Status returns current status values from the Synchronizer
  250. func (s *Synchronizer) Status() (*common.SyncStatus, error) {
  251. // Avoid possible inconsistencies
  252. s.mux.Lock()
  253. defer s.mux.Unlock()
  254. var status *common.SyncStatus
  255. // Get latest block in History DB
  256. lastSavedBlock, err := s.historyDB.GetLastBlock()
  257. if err != nil {
  258. return nil, err
  259. }
  260. status.CurrentBlock = lastSavedBlock.EthBlockNum
  261. // Get latest batch in History DB
  262. lastSavedBatch, err := s.historyDB.GetLastBatchNum()
  263. if err != nil && err != sql.ErrNoRows {
  264. return nil, err
  265. }
  266. status.CurrentBatch = lastSavedBatch
  267. // Get latest blockNum in blockchain
  268. latestBlockNum, err := s.ethClient.EthCurrentBlock()
  269. if err != nil {
  270. return nil, err
  271. }
  272. // TODO: Get CurrentForgerAddr & NextForgerAddr from the Auction SC
  273. // Check if Synchronizer is synchronized
  274. status.Synchronized = status.CurrentBlock == latestBlockNum
  275. return status, nil
  276. }
  277. // rollupSync gets information from the Rollup Contract
  278. func (s *Synchronizer) rollupSync(block *common.Block) (*rollupData, error) {
  279. var rollupData = newRollupData()
  280. var forgeL1TxsNum uint32
  281. var numAccounts int
  282. // using GetLastL1TxsNum as GetNextL1TxsNum
  283. lastStoredForgeL1TxsNum := uint32(0)
  284. lastStoredForgeL1TxsNumPtr, err := s.historyDB.GetLastL1TxsNum()
  285. if err != nil {
  286. return nil, err
  287. }
  288. if lastStoredForgeL1TxsNumPtr != nil {
  289. lastStoredForgeL1TxsNum = *lastStoredForgeL1TxsNumPtr + 1
  290. }
  291. // }
  292. // Get rollup events in the block
  293. rollupEvents, _, err := s.ethClient.RollupEventsByBlock(block.EthBlockNum)
  294. if err != nil {
  295. return nil, err
  296. }
  297. // Get newLastIdx that will be used to complete the accounts
  298. idx, err := s.getIdx(rollupEvents)
  299. if err != nil {
  300. return nil, err
  301. }
  302. // Get L1UserTX
  303. rollupData.l1Txs = s.getL1UserTx(rollupEvents.L1UserTx, block)
  304. // Get ForgeBatch events to get the L1CoordinatorTxs
  305. for _, fbEvent := range rollupEvents.ForgeBatch {
  306. batchData := NewBatchData()
  307. // TODO: Get position from HistoryDB filtering by
  308. // to_forge_l1_txs_num and batch_num and latest position, then add 1
  309. position := 1
  310. // Get the input for each Tx
  311. forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(fbEvent.EthTxHash)
  312. if err != nil {
  313. return nil, err
  314. }
  315. // Check if this is a L1Bath to get L1 Tx from it
  316. if forgeBatchArgs.L1Batch {
  317. // Get L1 User Txs from History DB
  318. // TODO: Get L1TX from HistoryDB filtered by toforgeL1txNum & fromidx = 0 and
  319. // update batch number and add accounts to registeredAccounts updating idx
  320. // l1UserTxs, err := s.historyDB.GetL1UserTxs(lastStoredForgeL1TxsNum)
  321. // Get L1 Coordinator Txs
  322. for _, l1CoordinatorTx := range forgeBatchArgs.L1CoordinatorTxs {
  323. l1CoordinatorTx.Position = position
  324. l1CoordinatorTx.ToForgeL1TxsNum = uint32(lastStoredForgeL1TxsNum)
  325. l1CoordinatorTx.TxID = common.TxID(common.Hash([]byte("0x01" + strconv.FormatInt(int64(lastStoredForgeL1TxsNum), 10) + strconv.FormatInt(int64(l1CoordinatorTx.Position), 10) + "00")))
  326. l1CoordinatorTx.UserOrigin = false
  327. l1CoordinatorTx.EthBlockNum = block.EthBlockNum
  328. l1CoordinatorTx.BatchNum = common.BatchNum(fbEvent.BatchNum)
  329. batchData.l1CoordinatorTxs = append(batchData.l1CoordinatorTxs, l1CoordinatorTx)
  330. forgeL1TxsNum++
  331. // Check if we have to register an account
  332. if l1CoordinatorTx.FromIdx == 0 {
  333. account := common.Account{
  334. // TODO: Uncommnent when common.account has IDx
  335. // IDx: common.Idx(idx),
  336. TokenID: l1CoordinatorTx.TokenID,
  337. Nonce: 0,
  338. Balance: l1CoordinatorTx.LoadAmount,
  339. PublicKey: l1CoordinatorTx.FromBJJ,
  340. EthAddr: l1CoordinatorTx.FromEthAddr,
  341. }
  342. idx++
  343. batchData.registeredAccounts = append(batchData.registeredAccounts, &account)
  344. numAccounts++
  345. }
  346. position++
  347. }
  348. lastStoredForgeL1TxsNum++
  349. }
  350. // Get L2Txs
  351. poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2Txs) // TODO: This is a big uggly, find a better way
  352. // Get exitTree
  353. _, exitInfo, err := s.stateDB.ProcessTxs(true, false, batchData.l1UserTxs, batchData.l1CoordinatorTxs, poolL2Txs)
  354. if err != nil {
  355. return nil, err
  356. }
  357. l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs) // TODO: This is a big uggly, find a better way
  358. batchData.l2Txs = append(batchData.l2Txs, l2Txs...)
  359. batchData.exitTree = exitInfo
  360. // Get Batch information
  361. batch := &common.Batch{
  362. BatchNum: common.BatchNum(fbEvent.BatchNum),
  363. EthBlockNum: block.EthBlockNum,
  364. // ForgerAddr: , TODO: Get it from ethClient
  365. // CollectedFees: , TODO: Clarify where to get them if they are still needed
  366. StateRoot: common.Hash(forgeBatchArgs.NewStRoot.Bytes()),
  367. NumAccounts: numAccounts,
  368. ExitRoot: common.Hash(forgeBatchArgs.NewExitRoot.Bytes()),
  369. ForgeL1TxsNum: forgeL1TxsNum,
  370. // SlotNum: TODO: Calculate once ethClient provides the info
  371. }
  372. batchData.batch = batch
  373. rollupData.batches = append(rollupData.batches, batchData)
  374. }
  375. // Get Registered Tokens
  376. for _, eAddToken := range rollupEvents.AddToken {
  377. var token *common.Token
  378. token.TokenID = common.TokenID(eAddToken.TokenID)
  379. token.EthAddr = eAddToken.Address
  380. token.EthBlockNum = block.EthBlockNum
  381. // TODO: Add external information consulting SC about it using Address
  382. rollupData.registeredTokens = append(rollupData.registeredTokens, token)
  383. }
  384. // TODO: Emergency Mechanism
  385. // TODO: Variables
  386. // TODO: Constants
  387. return &rollupData, nil
  388. }
  389. // auctionSync gets information from the Auction Contract
  390. func (s *Synchronizer) auctionSync(block *common.Block) (*auctionData, error) {
  391. var auctionData = newAuctionData()
  392. // Get auction events in the block
  393. auctionEvents, _, err := s.ethClient.AuctionEventsByBlock(block.EthBlockNum)
  394. if err != nil {
  395. return nil, err
  396. }
  397. // Get bids
  398. for _, eNewBid := range auctionEvents.NewBid {
  399. bid := &common.Bid{
  400. SlotNum: common.SlotNum(eNewBid.Slot),
  401. BidValue: eNewBid.BidAmount,
  402. ForgerAddr: eNewBid.CoordinatorForger,
  403. EthBlockNum: block.EthBlockNum,
  404. }
  405. auctionData.bids = append(auctionData.bids, bid)
  406. }
  407. // Get Coordinators
  408. for _, eNewCoordinator := range auctionEvents.NewCoordinator {
  409. coordinator := &common.Coordinator{
  410. Forger: eNewCoordinator.ForgerAddress,
  411. Withdraw: eNewCoordinator.WithdrawalAddress,
  412. URL: eNewCoordinator.URL,
  413. }
  414. auctionData.coordinators = append(auctionData.coordinators, coordinator)
  415. }
  416. // Get Coordinators from updates
  417. for _, eCoordinatorUpdated := range auctionEvents.CoordinatorUpdated {
  418. coordinator := &common.Coordinator{
  419. Forger: eCoordinatorUpdated.ForgerAddress,
  420. Withdraw: eCoordinatorUpdated.WithdrawalAddress,
  421. URL: eCoordinatorUpdated.URL,
  422. }
  423. auctionData.coordinators = append(auctionData.coordinators, coordinator)
  424. }
  425. // TODO: VARS
  426. // TODO: CONSTANTS
  427. return auctionData, nil
  428. }
  429. // wdelayerSync gets information from the Withdrawal Delayer Contract
  430. func (s *Synchronizer) wdelayerSync(block *common.Block) (*common.WithdrawalDelayerVars, error) {
  431. // TODO: VARS
  432. // TODO: CONSTANTS
  433. return nil, nil
  434. }
  435. func (s *Synchronizer) getIdx(rollupEvents *eth.RollupEvents) (int64, error) {
  436. lastForgeBatch := rollupEvents.ForgeBatch[len(rollupEvents.ForgeBatch)-1]
  437. // Get the input for forgeBatch
  438. forgeBatchArgs, err := s.ethClient.RollupForgeBatchArgs(lastForgeBatch.EthTxHash)
  439. if err != nil {
  440. return 0, err
  441. }
  442. return forgeBatchArgs.NewLastIdx + 1, nil
  443. }
  444. func (s *Synchronizer) getL1UserTx(l1UserTxEvents []eth.RollupEventL1UserTx, block *common.Block) []*common.L1Tx {
  445. l1Txs := make([]*common.L1Tx, 0)
  446. for _, eL1UserTx := range l1UserTxEvents {
  447. // Fill aditional Tx fields
  448. eL1UserTx.L1Tx.TxID = common.TxID(common.Hash([]byte("0x00" + strconv.FormatInt(int64(eL1UserTx.ToForgeL1TxsNum), 10) + strconv.FormatInt(int64(eL1UserTx.Position), 10) + "00")))
  449. eL1UserTx.L1Tx.ToForgeL1TxsNum = uint32(eL1UserTx.ToForgeL1TxsNum)
  450. eL1UserTx.L1Tx.Position = eL1UserTx.Position
  451. eL1UserTx.L1Tx.UserOrigin = true
  452. eL1UserTx.L1Tx.EthBlockNum = block.EthBlockNum
  453. eL1UserTx.L1Tx.BatchNum = 0
  454. l1Txs = append(l1Txs, &eL1UserTx.L1Tx)
  455. }
  456. return l1Txs
  457. }