github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/util/ledger/migrations/prune_migration.go (about)

     1  package migrations
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/cadence/runtime"
     7  	"github.com/onflow/cadence/runtime/common"
     8  	"github.com/onflow/cadence/runtime/interpreter"
     9  	"github.com/rs/zerolog"
    10  
    11  	"github.com/onflow/flow-go/ledger"
    12  	"github.com/onflow/flow-go/model/flow"
    13  )
    14  
    15  // PruneEmptyMigration removes all the payloads with empty value
    16  // this prunes the trie for values that has been deleted
    17  func PruneEmptyMigration(payload []ledger.Payload) ([]ledger.Payload, error) {
    18  	newPayload := make([]ledger.Payload, 0, len(payload))
    19  	for _, p := range payload {
    20  		if len(p.Value()) > 0 {
    21  			newPayload = append(newPayload, p)
    22  		}
    23  	}
    24  	return newPayload, nil
    25  }
    26  
    27  // NewCadence1PruneMigration prunes some values from the service account in the Testnet state
    28  func NewCadence1PruneMigration(
    29  	chainID flow.ChainID,
    30  	log zerolog.Logger,
    31  	nWorkers int,
    32  ) RegistersMigration {
    33  	if chainID != flow.Testnet {
    34  		return nil
    35  	}
    36  
    37  	serviceAccountAddress := common.Address(chainID.Chain().ServiceAddress())
    38  
    39  	migrate := func(storage *runtime.Storage, inter *interpreter.Interpreter) error {
    40  
    41  		err := pruneRandomBeaconHistory(storage, inter, log, serviceAccountAddress)
    42  		if err != nil {
    43  			return err
    44  		}
    45  
    46  		return nil
    47  	}
    48  
    49  	return NewAccountStorageMigration(
    50  		serviceAccountAddress,
    51  		log,
    52  		chainID,
    53  		migrate,
    54  	)
    55  }
    56  
    57  func pruneRandomBeaconHistory(
    58  	storage *runtime.Storage,
    59  	inter *interpreter.Interpreter,
    60  	log zerolog.Logger,
    61  	serviceAccountAddress common.Address,
    62  ) error {
    63  
    64  	log.Info().Msgf("pruning RandomBeaconHistory in service account %s", serviceAccountAddress)
    65  
    66  	contracts := storage.GetStorageMap(serviceAccountAddress, runtime.StorageDomainContract, false)
    67  	if contracts == nil {
    68  		return fmt.Errorf("failed to get contracts storage map")
    69  	}
    70  
    71  	randomBeaconHistory, ok := contracts.ReadValue(
    72  		nil,
    73  		interpreter.StringStorageMapKey("RandomBeaconHistory"),
    74  	).(*interpreter.CompositeValue)
    75  	if !ok {
    76  		return fmt.Errorf("failed to read RandomBeaconHistory contract")
    77  	}
    78  
    79  	randomSourceHistory, ok := randomBeaconHistory.GetField(
    80  		inter,
    81  		interpreter.EmptyLocationRange,
    82  		"randomSourceHistory",
    83  	).(*interpreter.ArrayValue)
    84  	if !ok {
    85  		return fmt.Errorf("failed to read randomSourceHistory field")
    86  	}
    87  
    88  	// Remove all but the last value from the randomSourceHistory
    89  	oldCount := randomSourceHistory.Count()
    90  	removalCount := oldCount - 1
    91  
    92  	for i := 0; i < removalCount; i++ {
    93  		randomSourceHistory.RemoveWithoutTransfer(
    94  			inter,
    95  			interpreter.EmptyLocationRange,
    96  			// NOTE: always remove the first element
    97  			0,
    98  		)
    99  	}
   100  
   101  	// Check
   102  	if randomSourceHistory.Count() != 1 {
   103  		return fmt.Errorf("failed to prune randomSourceHistory")
   104  	}
   105  
   106  	log.Info().Msgf(
   107  		"pruned %d entries in RandomBeaconHistory in service account %s",
   108  		removalCount,
   109  		serviceAccountAddress,
   110  	)
   111  
   112  	return nil
   113  }