github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/store_migration.go (about)

     1  package gossip
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/unicornultrafoundation/go-helios/hash"
     8  	"github.com/unicornultrafoundation/go-helios/u2udb"
     9  	"github.com/unicornultrafoundation/go-u2u/common"
    10  
    11  	"github.com/unicornultrafoundation/go-u2u/native"
    12  	"github.com/unicornultrafoundation/go-u2u/native/iblockproc"
    13  	"github.com/unicornultrafoundation/go-u2u/utils/migration"
    14  )
    15  
    16  func isEmptyDB(db u2udb.Iteratee) bool {
    17  	it := db.NewIterator(nil, nil)
    18  	defer it.Release()
    19  	return !it.Next()
    20  }
    21  
    22  func (s *Store) migrateData() error {
    23  	versions := migration.NewU2UdbIDStore(s.table.Version)
    24  	if isEmptyDB(s.table.Version) {
    25  		// short circuit if empty DB
    26  		versions.SetID(s.migrations().ID())
    27  		return nil
    28  	}
    29  
    30  	_ = s.eraseGenesisDB() // force eraseGenesisDB migration for alternative versions
    31  	err := s.migrations().Exec(versions, s.flushDBs)
    32  	return err
    33  }
    34  
    35  func (s *Store) migrations() *migration.Migration {
    36  	return migration.
    37  		Begin("u2u-gossip-store").
    38  		Next("used gas recovery", unsupportedMigration).
    39  		Next("tx hashes recovery", unsupportedMigration).
    40  		Next("DAG heads recovery", unsupportedMigration).
    41  		Next("DAG last events recovery", unsupportedMigration).
    42  		Next("BlockState recovery", unsupportedMigration).
    43  		Next("LlrState recovery", s.recoverLlrState).
    44  		Next("erase gossip-async db", s.eraseGossipAsyncDB).
    45  		Next("erase SFC API table", s.eraseSfcApiTable).
    46  		Next("erase legacy genesis DB", s.eraseGenesisDB).
    47  		Next("calculate upgrade heights", s.calculateUpgradeHeights)
    48  }
    49  
    50  func unsupportedMigration() error {
    51  	return fmt.Errorf("DB version isn't supported, please restart from scratch")
    52  }
    53  
    54  var (
    55  	fixTxHash1  = common.HexToHash("0xb6840d4c0eb562b0b1731760223d91b36edc6c160958e23e773e6058eea30458")
    56  	fixTxEvent1 = hash.HexToEventHash("0x00001718000003d4d3955bf592e12fb80a60574fa4b18bd5805b4c010d75e86d")
    57  	fixTxHash2  = common.HexToHash("0x3aeede91740093cb8feb1296a34cf70d86d2f802cff860edd798978e94a40534")
    58  	fixTxEvent2 = hash.HexToEventHash("0x0000179e00000c464d756a7614d0ca067fcb37ee4452004bf308c9df561e85e8")
    59  )
    60  
    61  const (
    62  	fixTxEventPos1 = 2
    63  	fixTxBlock1    = 4738821
    64  	fixTxEventPos2 = 0
    65  	fixTxBlock2    = 4801307
    66  )
    67  
    68  func fixEventTxHashes(e *native.EventPayload) {
    69  	if e.ID() == fixTxEvent1 {
    70  		e.Txs()[fixTxEventPos1].SetHash(fixTxHash1)
    71  	}
    72  	if e.ID() == fixTxEvent2 {
    73  		e.Txs()[fixTxEventPos2].SetHash(fixTxHash2)
    74  	}
    75  }
    76  
    77  func (s *Store) recoverLlrState() error {
    78  	v1, ok := s.rlp.Get(s.table.BlockEpochState, []byte(sKey), &BlockEpochState{}).(*BlockEpochState)
    79  	if !ok {
    80  		return errors.New("epoch state reading failed: genesis not applied")
    81  	}
    82  
    83  	epoch := v1.EpochState.Epoch + 1
    84  	block := v1.BlockState.LastBlock.Idx + 1
    85  
    86  	s.setLlrState(LlrState{
    87  		LowestEpochToDecide: epoch,
    88  		LowestEpochToFill:   epoch,
    89  		LowestBlockToDecide: block,
    90  		LowestBlockToFill:   block,
    91  	})
    92  	s.FlushLlrState()
    93  	return nil
    94  }
    95  
    96  func (s *Store) eraseSfcApiTable() error {
    97  	sfcapiTable, _ := s.dbs.OpenDB("gossip/S")
    98  	it := sfcapiTable.NewIterator(nil, nil)
    99  	defer it.Release()
   100  	for it.Next() {
   101  		err := sfcapiTable.Delete(it.Key())
   102  		if err != nil {
   103  			return err
   104  		}
   105  	}
   106  	return nil
   107  }
   108  
   109  func (s *Store) eraseGossipAsyncDB() error {
   110  	asyncDB, err := s.dbs.OpenDB("gossip-async")
   111  	if err != nil {
   112  		return fmt.Errorf("failed to open gossip-async to drop: %v", err)
   113  	}
   114  
   115  	_ = asyncDB.Close()
   116  	asyncDB.Drop()
   117  
   118  	return nil
   119  }
   120  
   121  func (s *Store) eraseGenesisDB() error {
   122  	genesisDB, err := s.dbs.OpenDB("genesis")
   123  	if err != nil {
   124  		return nil
   125  	}
   126  
   127  	_ = genesisDB.Close()
   128  	genesisDB.Drop()
   129  	return nil
   130  }
   131  
   132  func (s *Store) calculateUpgradeHeights() error {
   133  	var prevEs *iblockproc.EpochState
   134  	s.ForEachHistoryBlockEpochState(func(bs iblockproc.BlockState, es iblockproc.EpochState) bool {
   135  		s.WriteUpgradeHeight(bs, es, prevEs)
   136  		prevEs = &es
   137  		return true
   138  	})
   139  	if prevEs == nil {
   140  		// special case when no history is available
   141  		s.WriteUpgradeHeight(s.GetBlockState(), s.GetEpochState(), nil)
   142  	}
   143  	return nil
   144  }