-
Notifications
You must be signed in to change notification settings - Fork 36
/
record.go
143 lines (122 loc) · 4 KB
/
record.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
package keeper
import (
"fmt"
"github.com/provenance-io/provenance/x/metadata/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GetRecord returns the record with the given id.
func (k Keeper) GetRecord(ctx sdk.Context, id types.MetadataAddress) (record types.Record, found bool) {
if !id.IsRecordAddress() {
return record, false
}
store := ctx.KVStore(k.storeKey)
b := store.Get(id)
if b == nil {
return types.Record{}, false
}
k.cdc.MustUnmarshalBinaryBare(b, &record)
return record, true
}
// GetRecords returns records with scopeAddress and name
func (k Keeper) GetRecords(ctx sdk.Context, scopeAddress types.MetadataAddress, name string) ([]*types.Record, error) {
records := []*types.Record{}
err := k.IterateRecords(ctx, scopeAddress, func(r types.Record) (stop bool) {
if name == "" {
records = append(records, &r)
} else if name == r.Name {
records = append(records, &r)
}
return false
})
if err != nil {
return nil, err
}
return records, nil
}
// SetRecord stores a record in the module kv store.
func (k Keeper) SetRecord(ctx sdk.Context, record types.Record) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinaryBare(&record)
eventType := types.EventTypeRecordCreated
recordID := record.GroupId.GetRecordAddress(record.Name)
if store.Has(recordID) {
eventType = types.EventTypeRecordUpdated
}
store.Set(recordID, b)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
eventType,
sdk.NewAttribute(types.AttributeKeyScopeID, recordID.String()),
),
)
}
// RemoveRecord removes a scope from the module kv store.
func (k Keeper) RemoveRecord(ctx sdk.Context, id types.MetadataAddress) {
if !id.IsRecordAddress() {
panic(fmt.Errorf("invalid address, address must be for a record"))
}
store := ctx.KVStore(k.storeKey)
store.Delete(id)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeRecordRemoved,
sdk.NewAttribute(types.AttributeKeyRecordID, id.String()),
),
)
}
// IterateRecords processes all records in a scope with the given handler.
func (k Keeper) IterateRecords(ctx sdk.Context, scopeID types.MetadataAddress, handler func(types.Record) (stop bool)) error {
store := ctx.KVStore(k.storeKey)
prefix, err := scopeID.ScopeRecordIteratorPrefix()
if err != nil {
return err
}
it := sdk.KVStorePrefixIterator(store, prefix)
defer it.Close()
for ; it.Valid(); it.Next() {
var record types.Record
k.cdc.MustUnmarshalBinaryBare(it.Value(), &record)
if handler(record) {
break
}
}
return nil
}
// ValidateRecordUpdate checks the current record and the proposed record to determine if the the proposed changes are valid
// based on the existing state
func (k Keeper) ValidateRecordUpdate(ctx sdk.Context, existing, proposed types.Record, signers []string) error {
// get scope, collect required signers, get session (if it exists, if it is a new one make sure the contract-spec is allowed if restricted via scope spec), collect signers from that contract spec… verify update is correctly signed… pull record specification, check against the record update (this is a name match lookup against record name)
if err := proposed.ValidateBasic(); err != nil {
return err
}
scopeUUID, err := existing.GroupId.ScopeUUID()
if err != nil {
return err
}
scopeID := types.ScopeMetadataAddress(scopeUUID)
// get scope for existing record
scope, found := k.GetScope(ctx, scopeID)
if !found {
return fmt.Errorf("scope not found for scope uuid %s", scopeUUID)
}
// Validate any changes to the ValueOwner property.
requiredSignatures := []string{}
for _, p := range scope.Owners {
requiredSignatures = append(requiredSignatures, p.Address)
}
// Signatures required of all existing data owners.
for _, owner := range requiredSignatures {
found := false
for _, signer := range signers {
if owner == signer {
found = true
break
}
}
if !found {
return fmt.Errorf("missing signature from existing owner %s; required for update", owner)
}
}
// TODO finish full validation of update once specs are complete
return nil
}