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.

271 lines
6.9 KiB

  1. package synchronizer
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "sync"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  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. // BatchData contains information about Batches from the contracts
  22. //nolint:structcheck,unused
  23. type BatchData struct {
  24. l1txs []common.L1Tx
  25. l2txs []common.L2Tx
  26. registeredAccounts []common.Account
  27. exitTree []common.ExitInfo
  28. }
  29. // BlockData contains information about Blocks from the contracts
  30. //nolint:structcheck,unused
  31. type BlockData struct {
  32. block *common.Block
  33. // Rollup
  34. batches []BatchData
  35. withdrawals []common.ExitInfo
  36. registeredTokens []common.Token
  37. rollupVars *common.RollupVars
  38. // Auction
  39. bids []common.Bid
  40. coordinators []common.Coordinator
  41. auctionVars *common.AuctionVars
  42. }
  43. // Status is returned by the Status method
  44. type Status struct {
  45. CurrentBlock int64
  46. CurrentBatch common.BatchNum
  47. CurrentForgerAddr ethCommon.Address
  48. NextForgerAddr ethCommon.Address
  49. Synchronized bool
  50. }
  51. // Synchronizer implements the Synchronizer type
  52. type Synchronizer struct {
  53. ethClient *eth.Client
  54. historyDB *historydb.HistoryDB
  55. stateDB *statedb.StateDB
  56. firstSavedBlock *common.Block
  57. mux sync.Mutex
  58. }
  59. // NewSynchronizer creates a new Synchronizer
  60. func NewSynchronizer(ethClient *eth.Client, historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *Synchronizer {
  61. s := &Synchronizer{
  62. ethClient: ethClient,
  63. historyDB: historyDB,
  64. stateDB: stateDB,
  65. }
  66. return s
  67. }
  68. // Sync updates History and State DB with information from the blockchain
  69. func (s *Synchronizer) Sync() error {
  70. // Avoid new sync while performing one
  71. s.mux.Lock()
  72. defer s.mux.Unlock()
  73. var lastStoredForgeL1TxsNum int64
  74. // TODO: Get this information from ethClient once it's implemented
  75. // for the moment we will get the latestblock - 20 as firstSavedBlock
  76. latestBlock, err := s.ethClient.EthBlockByNumber(context.Background(), 0)
  77. if err != nil {
  78. return err
  79. }
  80. s.firstSavedBlock, err = s.ethClient.EthBlockByNumber(context.Background(), latestBlock.EthBlockNum-blocksToSync)
  81. if err != nil {
  82. return err
  83. }
  84. // Get lastSavedBlock from History DB
  85. lastSavedBlock, err := s.historyDB.GetLastBlock()
  86. if err != nil && err != sql.ErrNoRows {
  87. return err
  88. }
  89. // Check if we got a block or nil
  90. // In case of nil we must do a full sync
  91. if lastSavedBlock == nil || lastSavedBlock.EthBlockNum == 0 {
  92. lastSavedBlock = s.firstSavedBlock
  93. } else {
  94. // Get the latest block we have in History DB from blockchain to detect a reorg
  95. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), lastSavedBlock.EthBlockNum)
  96. if err != nil {
  97. return err
  98. }
  99. if ethBlock.Hash != lastSavedBlock.Hash {
  100. // Reorg detected
  101. log.Debugf("Reorg Detected...")
  102. err := s.reorg(lastSavedBlock)
  103. if err != nil {
  104. return err
  105. }
  106. lastSavedBlock, err = s.historyDB.GetLastBlock()
  107. if err != nil {
  108. return err
  109. }
  110. }
  111. }
  112. log.Debugf("Syncing...")
  113. // Get latest blockNum in blockchain
  114. latestBlockNum, err := s.ethClient.EthCurrentBlock()
  115. if err != nil {
  116. return err
  117. }
  118. log.Debugf("Blocks to sync: %v (lastSavedBlock: %v, latestBlock: %v)", latestBlockNum-lastSavedBlock.EthBlockNum, lastSavedBlock.EthBlockNum, latestBlockNum)
  119. for lastSavedBlock.EthBlockNum < latestBlockNum {
  120. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), lastSavedBlock.EthBlockNum+1)
  121. if err != nil {
  122. return err
  123. }
  124. // Get data from the rollup contract
  125. blockData, batchData, err := s.rollupSync(ethBlock, lastStoredForgeL1TxsNum)
  126. if err != nil {
  127. return err
  128. }
  129. // Get data from the auction contract
  130. err = s.auctionSync(blockData, batchData)
  131. if err != nil {
  132. return err
  133. }
  134. // Add rollupData and auctionData once the method is updated
  135. err = s.historyDB.AddBlock(ethBlock)
  136. if err != nil {
  137. return err
  138. }
  139. // We get the block on every iteration
  140. lastSavedBlock, err = s.historyDB.GetLastBlock()
  141. if err != nil {
  142. return err
  143. }
  144. }
  145. return nil
  146. }
  147. // reorg manages a reorg, updating History and State DB as needed
  148. func (s *Synchronizer) reorg(uncleBlock *common.Block) error {
  149. var block *common.Block
  150. blockNum := uncleBlock.EthBlockNum
  151. found := false
  152. log.Debugf("Reorg first uncle block: %v", blockNum)
  153. // Iterate History DB and the blokchain looking for the latest valid block
  154. for !found && blockNum > s.firstSavedBlock.EthBlockNum {
  155. ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), blockNum)
  156. if err != nil {
  157. return err
  158. }
  159. block, err = s.historyDB.GetBlock(blockNum)
  160. if err != nil {
  161. return err
  162. }
  163. if block.Hash == ethBlock.Hash {
  164. found = true
  165. log.Debugf("Found valid block: %v", blockNum)
  166. } else {
  167. log.Debugf("Discarding block: %v", blockNum)
  168. }
  169. blockNum--
  170. }
  171. if found {
  172. // Set History DB and State DB to the correct state
  173. err := s.historyDB.Reorg(block.EthBlockNum)
  174. if err != nil {
  175. return err
  176. }
  177. batchNum, err := s.historyDB.GetLastBatchNum()
  178. if err != nil && err != sql.ErrNoRows {
  179. return err
  180. }
  181. if batchNum != 0 {
  182. err = s.stateDB.Reset(batchNum)
  183. if err != nil {
  184. return err
  185. }
  186. }
  187. return nil
  188. }
  189. return ErrNotAbleToSync
  190. }
  191. // Status returns current status values from the Synchronizer
  192. func (s *Synchronizer) Status() (*Status, error) {
  193. // Avoid possible inconsistencies
  194. s.mux.Lock()
  195. defer s.mux.Unlock()
  196. var status *Status
  197. // Get latest block in History DB
  198. lastSavedBlock, err := s.historyDB.GetLastBlock()
  199. if err != nil {
  200. return nil, err
  201. }
  202. status.CurrentBlock = lastSavedBlock.EthBlockNum
  203. // Get latest batch in History DB
  204. lastSavedBatch, err := s.historyDB.GetLastBatchNum()
  205. if err != nil && err != sql.ErrNoRows {
  206. return nil, err
  207. }
  208. status.CurrentBatch = lastSavedBatch
  209. // Get latest blockNum in blockchain
  210. latestBlockNum, err := s.ethClient.EthCurrentBlock()
  211. if err != nil {
  212. return nil, err
  213. }
  214. // TODO: Get CurrentForgerAddr & NextForgerAddr
  215. // Check if Synchronizer is synchronized
  216. status.Synchronized = status.CurrentBlock == latestBlockNum
  217. return status, nil
  218. }
  219. // rollupSync gets information from the Rollup Contract
  220. func (s *Synchronizer) rollupSync(block *common.Block, lastStoredForgeL1TxsNum int64) (*BlockData, []*BatchData, error) {
  221. // To be implemented
  222. return nil, nil, nil
  223. }
  224. // auctionSync gets information from the Auction Contract
  225. func (s *Synchronizer) auctionSync(blockData *BlockData, batchData []*BatchData) error {
  226. // To be implemented
  227. return nil
  228. }