-
Notifications
You must be signed in to change notification settings - Fork 0
/
subspace.go
154 lines (123 loc) · 3.93 KB
/
subspace.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
150
151
152
153
154
package subspace
import (
"github.com/ci123chain/ci123chain/pkg/abci/codec"
"github.com/ci123chain/ci123chain/pkg/abci/store"
"github.com/ci123chain/ci123chain/pkg/abci/types"
"reflect"
)
const (
// StoreKey is the string store types for the param store
StoreKey = "params"
// TStoreKey is the string store types for the param transient store
TStoreKey = "transient_params"
)
// Individual parameter store for each keeper
// Transient store persists for a block, so we use it for
// recording whether the parameter has been changed or not
type Subspace struct {
cdc *codec.Codec
key types.StoreKey // []byte -> []byte, stores parameter
tkey types.StoreKey // []byte -> bool, stores parameter change
name []byte
table KeyTable
}
// NewSubspace constructs a store with namestore
func NewSubspace(cdc *codec.Codec, key types.StoreKey, tkey types.StoreKey, name string) (res Subspace) {
res = Subspace{
cdc: cdc,
key: key,
tkey: tkey,
name: []byte(name),
table: KeyTable{
m: make(map[string]attribute),
},
}
return
}
// HasKeyTable returns if the Subspace has a KeyTable registered.
func (s Subspace) HasKeyTable() bool {
return len(s.table.m) > 0
}
// WithKeyTable initializes KeyTable and returns modified Subspace
func (s Subspace) WithKeyTable(table KeyTable) Subspace {
if table.m == nil {
panic("SetKeyTable() called with nil KeyTable")
}
if len(s.table.m) != 0 {
panic("SetKeyTable() called on already initialized Subspace")
}
for k, v := range table.m {
s.table.m[k] = v
}
// Allocate additional capicity for Subspace.name
// So we don't have to allocate extra space each time appending to the key
name := s.name
s.name = make([]byte, len(name), len(name)+table.maxKeyLength())
copy(s.name, name)
return s
}
// Returns a KVStore identical with ctx.KVStore(s.types).Prefix()
func (s Subspace) kvStore(ctx types.Context) types.KVStore {
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
return store.NewPrefixStore(ctx.KVStore(s.key), append(s.name, '/'))
}
// Returns a transient store for modification
func (s Subspace) transientStore(ctx types.Context) types.KVStore {
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
return store.NewPrefixStore(ctx.TransientStore(s.tkey), append(s.name, '/'))
}
// Get parameter from store
func (s Subspace) Get(ctx types.Context, key []byte, ptr interface{}) {
store := s.kvStore(ctx)
bz := store.Get(key)
err := s.cdc.UnmarshalJSON(bz, ptr)
if err != nil {
panic(err)
}
}
// Set stores the parameter. It returns error if stored parameter has different types from input.
// It also set to the transient store to record change.
func (s Subspace) Set(ctx types.Context, key []byte, param interface{}) {
store := s.kvStore(ctx)
s.checkType(store, key, param)
bz, err := s.cdc.MarshalJSON(param)
if err != nil {
panic(err)
}
store.Set(key, bz)
tstore := s.transientStore(ctx)
tstore.Set(key, []byte{})
}
func (s Subspace) checkType(store types.KVStore, key []byte, param interface{}) {
attr, ok := s.table.m[string(key)]
if !ok {
panic("Parameter not registered")
}
ty := attr.ty
pty := reflect.TypeOf(param)
if pty.Kind() == reflect.Ptr {
pty = pty.Elem()
}
if pty != ty {
panic("Type mismatch with registered table")
}
}
// Set from ParamSet
func (s Subspace) SetParamSet(ctx types.Context, ps ParamSet) {
for _, pair := range ps.ParamSetPairs() {
// pair.Field is a pointer to the field, so indirecting the ptr.
// go-amino automatically handles it but just for sure,
// since SetStruct is meant to be used in InitGenesis
// so this method will not be called frequently
v := reflect.Indirect(reflect.ValueOf(pair.Value)).Interface()
s.Set(ctx, pair.Key, v)
}
}
// Get to ParamSet
func (s Subspace) GetParamSet(ctx types.Context, ps ParamSet) {
for _, pair := range ps.ParamSetPairs() {
s.Get(ctx, pair.Key, pair.Value)
}
}