diff --git a/gossip/store.go b/gossip/store.go index 4bc257bd3..5ca9bd6da 100644 --- a/gossip/store.go +++ b/gossip/store.go @@ -102,6 +102,10 @@ func NewStore(dbs kvdb.FlushableDBProducer, cfg StoreConfig) *Store { s.evm = evmstore.NewStore(s.mainDB, cfg.EVM) s.sfcapi = sfcapi.NewStore(s.table.SfcAPI) + if err := s.migrateData(); err != nil { + s.Log.Crit("Failed to migrate Gossip DB", "err", err) + } + return s } diff --git a/gossip/store_migration.go b/gossip/store_migration.go index f9733abbf..5f5498c06 100644 --- a/gossip/store_migration.go +++ b/gossip/store_migration.go @@ -1,6 +1,8 @@ package gossip import ( + "fmt" + "github.com/Fantom-foundation/lachesis-base/kvdb" "github.com/Fantom-foundation/go-opera/utils/migration" @@ -12,17 +14,72 @@ func isEmptyDB(db kvdb.Iteratee) bool { return !it.Next() } -func (s *Store) Migrate() error { +func (s *Store) migrateData() error { versions := migration.NewKvdbIDStore(s.table.Version) if isEmptyDB(s.mainDB) && isEmptyDB(s.async.mainDB) { // short circuit if empty DB versions.SetID(s.migrations().ID()) return nil } - return s.migrations().Exec(versions) + err := s.migrations().Exec(versions) + if err == nil { + err = s.Commit() + } + + return err } func (s *Store) migrations() *migration.Migration { return migration. - Begin("opera-gossip-store") + Begin("opera-gossip-store"). + Next("used gas recovery", s.dataRecovery_UsedGas) +} + +func (s *Store) dataRecovery_UsedGas() error { + start := s.GetGenesisBlockIndex() + if start == nil { + return fmt.Errorf("genesis block index is not set") + } + + for n := *start; true; n++ { + b := s.GetBlock(n) + if b == nil { + break + } + + var ( + rr = s.EvmStore().GetReceipts(n) + cumulativeGasWrong uint64 + cumulativeGasRight uint64 + fixed bool + ) + for i, r := range rr { + // simulate the bug + switch { + case n == *start: // genesis block + if i == len(b.InternalTxs)-2 || i == len(b.InternalTxs)-1 { + cumulativeGasWrong = 0 + } + default: // other blocks + if i == len(b.InternalTxs)-1 || i == len(b.InternalTxs) { + cumulativeGasWrong = 0 + } + } + // recalc + gasUsed := r.CumulativeGasUsed - cumulativeGasWrong + cumulativeGasWrong += gasUsed + cumulativeGasRight += gasUsed + // fix + if r.CumulativeGasUsed != cumulativeGasRight { + r.CumulativeGasUsed = cumulativeGasRight + r.GasUsed = gasUsed + fixed = true + } + } + if fixed { + s.EvmStore().SetReceipts(n, rr) + } + } + + return nil } diff --git a/integration/assembly.go b/integration/assembly.go index e55fb5756..61070e0d2 100644 --- a/integration/assembly.go +++ b/integration/assembly.go @@ -82,10 +82,6 @@ func rawApplyGenesis(gdb *gossip.Store, cdb *abft.Store, g opera.Genesis, cfg Co func rawMakeEngine(gdb *gossip.Store, cdb *abft.Store, g opera.Genesis, cfg Configs, applyGenesis bool) (*abft.Lachesis, *vecmt.Index, gossip.BlockProc, error) { blockProc := gossip.DefaultBlockProc(g) - err := gdb.Migrate() - if err != nil { - return nil, nil, blockProc, fmt.Errorf("failed to migrate Gossip DB: %v", err) - } if applyGenesis { _, err := gdb.ApplyGenesis(blockProc, g) if err != nil { diff --git a/inter/block.go b/inter/block.go index 18134de82..84d0341a8 100644 --- a/inter/block.go +++ b/inter/block.go @@ -21,6 +21,25 @@ func (b *Block) EstimateSize() int { return (len(b.Events)+len(b.InternalTxs)+len(b.Txs)+1+1)*32 + len(b.SkippedTxs)*4 + 8 + 8 } +func (b *Block) NotSkippedTxs() []common.Hash { + txs := append(b.InternalTxs, b.Txs...) + + if len(b.SkippedTxs) == 0 { + // short circuit if nothing to skip + return txs + } + skipCount := 0 + res := make([]common.Hash, 0, len(txs)) + for i, tx := range txs { + if skipCount < len(b.SkippedTxs) && b.SkippedTxs[skipCount] == uint32(i) { + skipCount++ + } else { + res = append(res, tx) + } + } + return res +} + func FilterSkippedTxs(txs types.Transactions, skippedTxs []uint32) types.Transactions { if len(skippedTxs) == 0 { // short circuit if nothing to skip