github.com/cosmos/cosmos-sdk@v0.50.10/types/collections.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "time" 6 7 "cosmossdk.io/collections" 8 collcodec "cosmossdk.io/collections/codec" 9 "cosmossdk.io/math" 10 ) 11 12 var ( 13 // AccAddressKey follows the same semantics of collections.BytesKey. 14 // It just uses humanized format for the String() and EncodeJSON(). 15 AccAddressKey collcodec.KeyCodec[AccAddress] = genericAddressKey[AccAddress]{ 16 stringDecoder: AccAddressFromBech32, 17 keyType: "sdk.AccAddress", 18 } 19 20 // ValAddressKey follows the same semantics as AccAddressKey. 21 ValAddressKey collcodec.KeyCodec[ValAddress] = genericAddressKey[ValAddress]{ 22 stringDecoder: ValAddressFromBech32, 23 keyType: "sdk.ValAddress", 24 } 25 26 // ConsAddressKey follows the same semantics as ConsAddressKey. 27 ConsAddressKey collcodec.KeyCodec[ConsAddress] = genericAddressKey[ConsAddress]{ 28 stringDecoder: ConsAddressFromBech32, 29 keyType: "sdk.ConsAddress", 30 } 31 32 // IntValue represents a collections.ValueCodec to work with Int. 33 IntValue collcodec.ValueCodec[math.Int] = intValueCodec{} 34 35 // LegacyDecValue represents a collections.ValueCodec to work with LegacyDec. 36 LegacyDecValue collcodec.ValueCodec[math.LegacyDec] = legacyDecValueCodec{} 37 38 // TimeKey represents a collections.KeyCodec to work with time.Time 39 // Deprecated: exists only for state compatibility reasons, should not 40 // be used for new storage keys using time. Please use the time KeyCodec 41 // provided in the collections package. 42 TimeKey collcodec.KeyCodec[time.Time] = timeKeyCodec{} 43 ) 44 45 const ( 46 LegacyDec string = "math.LegacyDec" 47 ) 48 49 type addressUnion interface { 50 AccAddress | ValAddress | ConsAddress 51 String() string 52 } 53 54 type genericAddressKey[T addressUnion] struct { 55 stringDecoder func(string) (T, error) 56 keyType string 57 } 58 59 func (a genericAddressKey[T]) Encode(buffer []byte, key T) (int, error) { 60 return collections.BytesKey.Encode(buffer, key) 61 } 62 63 func (a genericAddressKey[T]) Decode(buffer []byte) (int, T, error) { 64 return collections.BytesKey.Decode(buffer) 65 } 66 67 func (a genericAddressKey[T]) Size(key T) int { 68 return collections.BytesKey.Size(key) 69 } 70 71 func (a genericAddressKey[T]) EncodeJSON(value T) ([]byte, error) { 72 return collections.StringKey.EncodeJSON(value.String()) 73 } 74 75 func (a genericAddressKey[T]) DecodeJSON(b []byte) (v T, err error) { 76 s, err := collections.StringKey.DecodeJSON(b) 77 if err != nil { 78 return 79 } 80 v, err = a.stringDecoder(s) 81 return 82 } 83 84 func (a genericAddressKey[T]) Stringify(key T) string { 85 return key.String() 86 } 87 88 func (a genericAddressKey[T]) KeyType() string { 89 return a.keyType 90 } 91 92 func (a genericAddressKey[T]) EncodeNonTerminal(buffer []byte, key T) (int, error) { 93 return collections.BytesKey.EncodeNonTerminal(buffer, key) 94 } 95 96 func (a genericAddressKey[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { 97 return collections.BytesKey.DecodeNonTerminal(buffer) 98 } 99 100 func (a genericAddressKey[T]) SizeNonTerminal(key T) int { 101 return collections.BytesKey.SizeNonTerminal(key) 102 } 103 104 // Deprecated: lengthPrefixedAddressKey is a special key codec used to retain state backwards compatibility 105 // when a generic address key (be: AccAddress, ValAddress, ConsAddress), is used as an index key. 106 // More docs can be found in the LengthPrefixedAddressKey function. 107 type lengthPrefixedAddressKey[T addressUnion] struct { 108 collcodec.KeyCodec[T] 109 } 110 111 func (g lengthPrefixedAddressKey[T]) Encode(buffer []byte, key T) (int, error) { 112 return g.EncodeNonTerminal(buffer, key) 113 } 114 115 func (g lengthPrefixedAddressKey[T]) Decode(buffer []byte) (int, T, error) { 116 return g.DecodeNonTerminal(buffer) 117 } 118 119 func (g lengthPrefixedAddressKey[T]) Size(key T) int { return g.SizeNonTerminal(key) } 120 121 func (g lengthPrefixedAddressKey[T]) KeyType() string { return "index_key/" + g.KeyCodec.KeyType() } 122 123 // Deprecated: LengthPrefixedAddressKey implements an SDK backwards compatible indexing key encoder 124 // for addresses. 125 // The status quo in the SDK is that address keys are length prefixed even when they're the 126 // last part of a composite key. This should never be used unless to retain state compatibility. 127 // For example, a composite key composed of `[string, address]` in theory would need you only to 128 // define a way to understand when the string part finishes, we usually do this by appending a null 129 // byte to the string, then when you know when the string part finishes, it's logical that the 130 // part which remains is the address key. In the SDK instead we prepend to the address key its 131 // length too. 132 func LengthPrefixedAddressKey[T addressUnion](keyCodec collcodec.KeyCodec[T]) collcodec.KeyCodec[T] { 133 return lengthPrefixedAddressKey[T]{ 134 keyCodec, 135 } 136 } 137 138 // Collection Codecs 139 140 type intValueCodec struct{} 141 142 func (i intValueCodec) Encode(value math.Int) ([]byte, error) { 143 return value.Marshal() 144 } 145 146 func (i intValueCodec) Decode(b []byte) (math.Int, error) { 147 v := new(math.Int) 148 err := v.Unmarshal(b) 149 if err != nil { 150 return math.Int{}, err 151 } 152 return *v, nil 153 } 154 155 func (i intValueCodec) EncodeJSON(value math.Int) ([]byte, error) { 156 return value.MarshalJSON() 157 } 158 159 func (i intValueCodec) DecodeJSON(b []byte) (math.Int, error) { 160 v := new(math.Int) 161 err := v.UnmarshalJSON(b) 162 if err != nil { 163 return math.Int{}, err 164 } 165 return *v, nil 166 } 167 168 func (i intValueCodec) Stringify(value math.Int) string { 169 return value.String() 170 } 171 172 func (i intValueCodec) ValueType() string { 173 return "math.Int" 174 } 175 176 type legacyDecValueCodec struct{} 177 178 func (i legacyDecValueCodec) Encode(value math.LegacyDec) ([]byte, error) { 179 return value.Marshal() 180 } 181 182 func (i legacyDecValueCodec) Decode(b []byte) (math.LegacyDec, error) { 183 v := new(math.LegacyDec) 184 err := v.Unmarshal(b) 185 if err != nil { 186 return math.LegacyDec{}, err 187 } 188 return *v, nil 189 } 190 191 func (i legacyDecValueCodec) EncodeJSON(value math.LegacyDec) ([]byte, error) { 192 return value.MarshalJSON() 193 } 194 195 func (i legacyDecValueCodec) DecodeJSON(b []byte) (math.LegacyDec, error) { 196 v := new(math.LegacyDec) 197 err := v.UnmarshalJSON(b) 198 if err != nil { 199 return math.LegacyDec{}, err 200 } 201 return *v, nil 202 } 203 204 func (i legacyDecValueCodec) Stringify(value math.LegacyDec) string { 205 return value.String() 206 } 207 208 func (i legacyDecValueCodec) ValueType() string { 209 return LegacyDec 210 } 211 212 type timeKeyCodec struct{} 213 214 func (timeKeyCodec) Encode(buffer []byte, key time.Time) (int, error) { 215 return copy(buffer, FormatTimeBytes(key)), nil 216 } 217 218 var timeSize = len(FormatTimeBytes(time.Time{})) 219 220 func (timeKeyCodec) Decode(buffer []byte) (int, time.Time, error) { 221 if len(buffer) != timeSize { 222 return 0, time.Time{}, fmt.Errorf("invalid time buffer buffer size") 223 } 224 t, err := ParseTimeBytes(buffer) 225 if err != nil { 226 return 0, time.Time{}, err 227 } 228 return timeSize, t, nil 229 } 230 231 func (timeKeyCodec) Size(key time.Time) int { return timeSize } 232 233 func (timeKeyCodec) EncodeJSON(value time.Time) ([]byte, error) { return value.MarshalJSON() } 234 235 func (timeKeyCodec) DecodeJSON(b []byte) (time.Time, error) { 236 t := time.Time{} 237 err := t.UnmarshalJSON(b) 238 return t, err 239 } 240 241 func (timeKeyCodec) Stringify(key time.Time) string { return key.String() } 242 func (timeKeyCodec) KeyType() string { return "sdk/time.Time" } 243 func (t timeKeyCodec) EncodeNonTerminal(buffer []byte, key time.Time) (int, error) { 244 return t.Encode(buffer, key) 245 } 246 247 func (t timeKeyCodec) DecodeNonTerminal(buffer []byte) (int, time.Time, error) { 248 if len(buffer) < timeSize { 249 return 0, time.Time{}, fmt.Errorf("invalid time buffer size, wanted: %d at least, got: %d", timeSize, len(buffer)) 250 } 251 return t.Decode(buffer[:timeSize]) 252 } 253 func (t timeKeyCodec) SizeNonTerminal(key time.Time) int { return t.Size(key) }