github.com/cosmos/cosmos-sdk@v0.50.10/types/utils.go (about) 1 package types 2 3 import ( 4 "encoding/binary" 5 "encoding/json" 6 "fmt" 7 "time" 8 9 "cosmossdk.io/log" 10 11 "github.com/cosmos/cosmos-sdk/types/kv" 12 ) 13 14 // SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces 15 // are removed. 16 // This method can be used to canonicalize JSON to be returned by GetSignBytes, 17 // e.g. for the ledger integration. 18 // If the passed JSON isn't valid it will return an error. 19 // Deprecated: SortJSON was used for GetSignbytes, this is now automatic with amino signing 20 func SortJSON(toSortJSON []byte) ([]byte, error) { 21 var c interface{} 22 err := json.Unmarshal(toSortJSON, &c) 23 if err != nil { 24 return nil, err 25 } 26 js, err := json.Marshal(c) 27 if err != nil { 28 return nil, err 29 } 30 return js, nil 31 } 32 33 // MustSortJSON is like SortJSON but panic if an error occurs, e.g., if 34 // the passed JSON isn't valid. 35 // Deprecated: SortJSON was used for GetSignbytes, this is now automatic with amino signing 36 func MustSortJSON(toSortJSON []byte) []byte { 37 js, err := SortJSON(toSortJSON) 38 if err != nil { 39 panic(err) 40 } 41 return js 42 } 43 44 // Uint64ToBigEndian - marshals uint64 to a bigendian byte slice so it can be sorted 45 func Uint64ToBigEndian(i uint64) []byte { 46 b := make([]byte, 8) 47 binary.BigEndian.PutUint64(b, i) 48 return b 49 } 50 51 // BigEndianToUint64 returns an uint64 from big endian encoded bytes. If encoding 52 // is empty, zero is returned. 53 func BigEndianToUint64(bz []byte) uint64 { 54 if len(bz) == 0 { 55 return 0 56 } 57 58 return binary.BigEndian.Uint64(bz) 59 } 60 61 // Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info 62 const SortableTimeFormat = "2006-01-02T15:04:05.000000000" 63 64 // Formats a time.Time into a []byte that can be sorted 65 func FormatTimeBytes(t time.Time) []byte { 66 return []byte(FormatTimeString(t)) 67 } 68 69 // Formats a time.Time into a string 70 func FormatTimeString(t time.Time) string { 71 return t.UTC().Round(0).Format(SortableTimeFormat) 72 } 73 74 // Parses a []byte encoded using FormatTimeKey back into a time.Time 75 func ParseTimeBytes(bz []byte) (time.Time, error) { 76 return ParseTime(bz) 77 } 78 79 // Parses an encoded type using FormatTimeKey back into a time.Time 80 func ParseTime(t any) (time.Time, error) { 81 var ( 82 result time.Time 83 err error 84 ) 85 86 switch t := t.(type) { 87 case time.Time: 88 result, err = t, nil 89 case []byte: 90 result, err = time.Parse(SortableTimeFormat, string(t)) 91 case string: 92 result, err = time.Parse(SortableTimeFormat, t) 93 default: 94 return time.Time{}, fmt.Errorf("unexpected type %T", t) 95 } 96 97 if err != nil { 98 return result, err 99 } 100 101 return result.UTC().Round(0), nil 102 } 103 104 // copy bytes 105 func CopyBytes(bz []byte) (ret []byte) { 106 if bz == nil { 107 return nil 108 } 109 ret = make([]byte, len(bz)) 110 copy(ret, bz) 111 return ret 112 } 113 114 // AppendLengthPrefixedBytes combines the slices of bytes to one slice of bytes. 115 func AppendLengthPrefixedBytes(args ...[]byte) []byte { 116 length := 0 117 for _, v := range args { 118 length += len(v) 119 } 120 res := make([]byte, length) 121 122 length = 0 123 for _, v := range args { 124 copy(res[length:length+len(v)], v) 125 length += len(v) 126 } 127 128 return res 129 } 130 131 // ParseLengthPrefixedBytes panics when store key length is not equal to the given length. 132 func ParseLengthPrefixedBytes(key []byte, startIndex, sliceLength int) ([]byte, int) { 133 neededLength := startIndex + sliceLength 134 endIndex := neededLength - 1 135 kv.AssertKeyAtLeastLength(key, neededLength) 136 byteSlice := key[startIndex:neededLength] 137 138 return byteSlice, endIndex 139 } 140 141 // LogDeferred logs an error in a deferred function call if the returned error is non-nil. 142 func LogDeferred(logger log.Logger, f func() error) { 143 if err := f(); err != nil { 144 logger.Error(err.Error()) 145 } 146 }