github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/key_codec.go (about) 1 package orm 2 3 import ( 4 "fmt" 5 6 errorsmod "cosmossdk.io/errors" 7 8 "github.com/cosmos/cosmos-sdk/x/group/errors" 9 ) 10 11 // MaxBytesLen is the maximum allowed length for a key part of type []byte 12 const MaxBytesLen = 255 13 14 // buildKeyFromParts encodes and concatenates primary key and index parts. 15 // They can be []byte, string, and integer types. The function will return 16 // an error if there is a part of any other type. 17 // Key parts, except the last part, follow these rules: 18 // - []byte is encoded with a single byte length prefix 19 // - strings are null-terminated 20 // - integers are encoded using 8 byte big endian. 21 func buildKeyFromParts(parts []interface{}) ([]byte, error) { 22 bytesSlice := make([][]byte, len(parts)) 23 totalLen := 0 24 var err error 25 for i, part := range parts { 26 bytesSlice[i], err = keyPartBytes(part, len(parts) > 1 && i == len(parts)-1) 27 if err != nil { 28 return nil, err 29 } 30 totalLen += len(bytesSlice[i]) 31 } 32 key := make([]byte, 0, totalLen) 33 for _, bs := range bytesSlice { 34 key = append(key, bs...) 35 } 36 return key, nil 37 } 38 39 func keyPartBytes(part interface{}, last bool) ([]byte, error) { 40 switch v := part.(type) { 41 case []byte: 42 if last || len(v) == 0 { 43 return v, nil 44 } 45 return AddLengthPrefix(v), nil 46 case string: 47 if last || len(v) == 0 { 48 return []byte(v), nil 49 } 50 return NullTerminatedBytes(v), nil 51 case uint64: 52 return EncodeSequence(v), nil 53 default: 54 return nil, fmt.Errorf("type %T not allowed as key part", v) 55 } 56 } 57 58 // AddLengthPrefix prefixes the byte array with its length as 8 bytes. The function will panic 59 // if the bytes length is bigger than 255. 60 func AddLengthPrefix(bytes []byte) []byte { 61 byteLen := len(bytes) 62 if byteLen > MaxBytesLen { 63 panic(errorsmod.Wrap(errors.ErrORMKeyMaxLength, "Cannot create key part with an []byte of length greater than 255 bytes. Try again with a smaller []byte.")) 64 } 65 66 prefixedBytes := make([]byte, 1+len(bytes)) 67 copy(prefixedBytes, []byte{uint8(byteLen)}) 68 copy(prefixedBytes[1:], bytes) 69 return prefixedBytes 70 } 71 72 // NullTerminatedBytes converts string to byte array and null terminate it 73 func NullTerminatedBytes(s string) []byte { 74 bytes := make([]byte, len(s)+1) 75 copy(bytes, s) 76 return bytes 77 } 78 79 // stripRowID returns the RowID from the indexKey based on secondaryIndexKey type. 80 // It is the reverse operation to buildKeyFromParts for index keys 81 // where the first part is the encoded secondaryIndexKey and the second part is the RowID. 82 func stripRowID(indexKey []byte, secondaryIndexKey interface{}) (RowID, error) { 83 switch v := secondaryIndexKey.(type) { 84 case []byte: 85 searchableKeyLen := indexKey[0] 86 return indexKey[1+searchableKeyLen:], nil 87 case string: 88 searchableKeyLen := 0 89 for i, b := range indexKey { 90 if b == 0 { 91 searchableKeyLen = i 92 break 93 } 94 } 95 return indexKey[1+searchableKeyLen:], nil 96 case uint64: 97 return indexKey[EncodedSeqLength:], nil 98 default: 99 return nil, fmt.Errorf("type %T not allowed as index key", v) 100 } 101 }