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 }