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  }