github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/derived_data_invalidator.go (about)

     1  package environment
     2  
     3  import (
     4  	"github.com/onflow/cadence/runtime/common"
     5  
     6  	"github.com/onflow/flow-go/fvm/storage/derived"
     7  	"github.com/onflow/flow-go/fvm/storage/snapshot"
     8  	"github.com/onflow/flow-go/model/flow"
     9  )
    10  
    11  type ContractUpdate struct {
    12  	Location common.AddressLocation
    13  	Code     []byte
    14  }
    15  
    16  type ContractUpdates struct {
    17  	Updates   []common.AddressLocation
    18  	Deploys   []common.AddressLocation
    19  	Deletions []common.AddressLocation
    20  }
    21  
    22  func (u ContractUpdates) Any() bool {
    23  	return len(u.Updates) > 0 || len(u.Deploys) > 0 || len(u.Deletions) > 0
    24  }
    25  
    26  type DerivedDataInvalidator struct {
    27  	ContractUpdates
    28  
    29  	MeterParamOverridesUpdated bool
    30  }
    31  
    32  var _ derived.TransactionInvalidator = DerivedDataInvalidator{}
    33  
    34  func NewDerivedDataInvalidator(
    35  	contractUpdates ContractUpdates,
    36  	serviceAddress flow.Address,
    37  	executionSnapshot *snapshot.ExecutionSnapshot,
    38  ) DerivedDataInvalidator {
    39  	return DerivedDataInvalidator{
    40  		ContractUpdates: contractUpdates,
    41  		MeterParamOverridesUpdated: meterParamOverridesUpdated(
    42  			serviceAddress,
    43  			executionSnapshot),
    44  	}
    45  }
    46  
    47  func meterParamOverridesUpdated(
    48  	serviceAddress flow.Address,
    49  	executionSnapshot *snapshot.ExecutionSnapshot,
    50  ) bool {
    51  	serviceAccount := string(serviceAddress.Bytes())
    52  	storageDomain := common.PathDomainStorage.Identifier()
    53  
    54  	for registerId := range executionSnapshot.WriteSet {
    55  		// The meter param override values are stored in the service account.
    56  		if registerId.Owner != serviceAccount {
    57  			continue
    58  		}
    59  
    60  		// NOTE: This condition is empirically generated by running the
    61  		// MeterParamOverridesComputer to capture touched registers.
    62  		//
    63  		// The paramater settings are stored as regular fields in the service
    64  		// account.  In general, each account's regular fields are stored in
    65  		// ordered map known only to cadence.  Cadence encodes this map into
    66  		// bytes and split the bytes into slab chunks before storing the slabs
    67  		// into the ledger.  Hence any changes to the stabs indicate changes
    68  		// the ordered map.
    69  		//
    70  		// The meter param overrides use storageDomain as input, so any
    71  		// changes to it must also invalidate the values.
    72  		if registerId.Key == storageDomain || registerId.IsSlabIndex() {
    73  			return true
    74  		}
    75  	}
    76  
    77  	return false
    78  }
    79  
    80  func (invalidator DerivedDataInvalidator) ProgramInvalidator() derived.ProgramInvalidator {
    81  	return ProgramInvalidator{invalidator}
    82  }
    83  
    84  func (invalidator DerivedDataInvalidator) MeterParamOverridesInvalidator() derived.MeterParamOverridesInvalidator {
    85  	return MeterParamOverridesInvalidator{invalidator}
    86  }
    87  
    88  type ProgramInvalidator struct {
    89  	DerivedDataInvalidator
    90  }
    91  
    92  func (invalidator ProgramInvalidator) ShouldInvalidateEntries() bool {
    93  	return invalidator.MeterParamOverridesUpdated ||
    94  		invalidator.ContractUpdates.Any()
    95  }
    96  
    97  func (invalidator ProgramInvalidator) ShouldInvalidateEntry(
    98  	location common.AddressLocation,
    99  	program *derived.Program,
   100  	snapshot *snapshot.ExecutionSnapshot,
   101  ) bool {
   102  	if invalidator.MeterParamOverridesUpdated {
   103  		// if meter parameters changed we need to invalidate all programs
   104  		return true
   105  	}
   106  
   107  	// invalidate all programs depending on any of the contracts that were
   108  	// updated. A program has itself listed as a dependency, so that this
   109  	// simpler.
   110  	for _, loc := range invalidator.ContractUpdates.Updates {
   111  		ok := program.Dependencies.ContainsLocation(loc)
   112  		if ok {
   113  			return true
   114  		}
   115  	}
   116  
   117  	// In case a contract was deployed or removed from an address,
   118  	// we need to invalidate all programs depending on that address.
   119  	for _, loc := range invalidator.ContractUpdates.Deploys {
   120  		ok := program.Dependencies.ContainsAddress(loc.Address)
   121  		if ok {
   122  			return true
   123  		}
   124  	}
   125  	for _, loc := range invalidator.ContractUpdates.Deletions {
   126  		ok := program.Dependencies.ContainsAddress(loc.Address)
   127  		if ok {
   128  			return true
   129  		}
   130  	}
   131  
   132  	return false
   133  }
   134  
   135  type MeterParamOverridesInvalidator struct {
   136  	DerivedDataInvalidator
   137  }
   138  
   139  func (invalidator MeterParamOverridesInvalidator) ShouldInvalidateEntries() bool {
   140  	return invalidator.MeterParamOverridesUpdated
   141  }
   142  
   143  func (invalidator MeterParamOverridesInvalidator) ShouldInvalidateEntry(
   144  	_ struct{},
   145  	_ derived.MeterParamOverrides,
   146  	_ *snapshot.ExecutionSnapshot,
   147  ) bool {
   148  	return invalidator.MeterParamOverridesUpdated
   149  }