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