From c6f6c90d05c5ef770272fe0f5de6eced5b51d313 Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Oct 2023 15:13:05 +0700 Subject: [PATCH] add more utils --- app/exit.go | 7 +++--- utils/error_util.go | 20 +++++++++++++--- utils/hash_util.go | 8 +++++++ utils/hash_util_test.go | 29 +++++++++++++++------- utils/ibc_util.go | 11 +++++++++ utils/ibc_util_test.go | 33 +++++++++++++++++++++++++ utils/time_util.go | 10 ++++++++ utils/time_util_test.go | 53 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 utils/ibc_util.go create mode 100644 utils/ibc_util_test.go diff --git a/app/exit.go b/app/exit.go index 5caaa9e..f9cbb5a 100644 --- a/app/exit.go +++ b/app/exit.go @@ -3,6 +3,7 @@ package app import ( "fmt" "github.com/EscanBE/go-lib/logging" + "github.com/EscanBE/go-lib/utils" ) // AppExitFunction is an alias of function which receives params @@ -36,20 +37,20 @@ func TryRecoverAndExecuteExitFunctionIfRecovered(logger logging.Logger, exitFunc if logger != nil { logger.Error("Panic caught", "error", err) } else { - fmt.Printf("Panic caught, err: %v\n", err) + utils.PrintfStdErr("Panic caught, err: %v\n", err) } panic(err) } else { if logger != nil { logger.Error("Recovered from panic, executing exit function") } else { - fmt.Println("Recovered from panic, executing exit function") + utils.PrintfStdErr("Recovered from panic, executing exit function") } ExecuteExitFunction(exitFuncParams...) if logger != nil { logger.Error("Executed exit function, going to panic using recovered error") } else { - fmt.Println("Executed exit function, going to panic using recovered error") + utils.PrintfStdErr("Executed exit function, going to panic using recovered error") } panic(err) } diff --git a/utils/error_util.go b/utils/error_util.go index 1b5e312..3ae7d8d 100644 --- a/utils/error_util.go +++ b/utils/error_util.go @@ -13,8 +13,7 @@ func ExitIfErr(err error, msg string) { if err == nil { return } - fmt.Printf("Exit with error: %s\n", msg) - fmt.Println(err) + PrintlnStdErr("Exit with error:", msg, "\n", err) osExit(1) } @@ -23,7 +22,7 @@ func PanicIfErr(err error, msg string) { if err == nil { return } - fmt.Printf("Exit with error: %s\n", msg) + PrintlnStdErr("Exit with error:", msg) panic(err) } @@ -34,3 +33,18 @@ func NilOrWrapIfError(err error, msg string) error { } return errors.Wrap(err, msg) } + +// PrintlnStdErr does println to StdErr +func PrintlnStdErr(a ...any) { + fmt.Fprintln(os.Stderr, a...) +} + +// PrintfStdErr does printf to StdErr +func PrintfStdErr(format string, a ...any) { + fmt.Fprintf(os.Stderr, format, a...) +} + +// PrintStdErr does print to StdErr +func PrintStdErr(a ...any) { + fmt.Fprint(os.Stderr, a...) +} diff --git a/utils/hash_util.go b/utils/hash_util.go index 3220c5c..f8e1db6 100644 --- a/utils/hash_util.go +++ b/utils/hash_util.go @@ -1,10 +1,18 @@ package utils import ( + "crypto/sha256" "encoding/hex" + "fmt" "github.com/ethereum/go-ethereum/crypto" ) +// Keccak256Hash computes and returns Keccak-256 value of an input string func Keccak256Hash(input string) string { return hex.EncodeToString(crypto.Keccak256Hash([]byte(input)).Bytes()) } + +// Sha256 returns SHA256 checksum string value of an input string +func Sha256(input string) string { + return fmt.Sprintf("%x", sha256.Sum256([]byte(input))) +} diff --git a/utils/hash_util_test.go b/utils/hash_util_test.go index 64633a1..da24700 100644 --- a/utils/hash_util_test.go +++ b/utils/hash_util_test.go @@ -2,24 +2,35 @@ package utils import "testing" -func TestKeccak256Hash(t *testing.T) { +func Test256Hashing(t *testing.T) { tests := []struct { - input string - want string + input string + wantKeccak256 string + wantSha256 string }{ { - input: "abcd", - want: "48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77", + input: "abc", + wantKeccak256: "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", + wantSha256: "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", }, { - input: "", - want: "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + input: "abcd", + wantKeccak256: "48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77", + wantSha256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", + }, + { + input: "", + wantKeccak256: "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + wantSha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { - if got := Keccak256Hash(tt.input); got != tt.want { - t.Errorf("Keccak256Hash() = %v, want %v", got, tt.want) + if got1 := Keccak256Hash(tt.input); got1 != tt.wantKeccak256 { + t.Errorf("Keccak256Hash() = %v, want %v", got1, tt.wantKeccak256) + } + if got2 := Sha256(tt.input); got2 != tt.wantSha256 { + t.Errorf("Sha256() = %v, want %v", got2, tt.wantSha256) } }) } diff --git a/utils/ibc_util.go b/utils/ibc_util.go new file mode 100644 index 0000000..c374826 --- /dev/null +++ b/utils/ibc_util.go @@ -0,0 +1,11 @@ +package utils + +import ( + "fmt" + "strings" +) + +// BuildIbcDenom returns IBC denom based on algorithm provided by IBC docs: Sha256(path/baseDenom) +func BuildIbcDenom(path, baseDenom string) string { + return fmt.Sprintf("ibc/%s", strings.ToUpper(Sha256(fmt.Sprintf("%s/%s", path, baseDenom)))) +} diff --git a/utils/ibc_util_test.go b/utils/ibc_util_test.go new file mode 100644 index 0000000..90e219b --- /dev/null +++ b/utils/ibc_util_test.go @@ -0,0 +1,33 @@ +package utils + +import ( + "fmt" + "testing" +) + +func TestBuildIbcDenom(t *testing.T) { + //goland:noinspection SpellCheckingInspection + tests := []struct { + path string + baseDenom string + want string + }{ + { + path: "transfer/channel-0", + baseDenom: "uosmo", + want: "ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518", + }, + { + path: "transfer/channel-3", + baseDenom: "uatom", + want: "ibc/A4DB47A9D3CF9A068D454513891B526702455D3EF08FB9EB558C561F9DC2B701", + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("%s/%s", tt.path, tt.baseDenom), func(t *testing.T) { + if got := BuildIbcDenom(tt.path, tt.baseDenom); got != tt.want { + t.Errorf("BuildIbcDenom() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/utils/time_util.go b/utils/time_util.go index e472624..0a7393f 100644 --- a/utils/time_util.go +++ b/utils/time_util.go @@ -26,6 +26,16 @@ func DiffMs(previous int64) int64 { return NowMs() - previous } +// IsTimeNear returns true when t1 and t2, are the same time (maximum diff is offset), regardless timezone. +// Eg: 03:00:00 UTC+0000 is equals to 10:00:00 UTC+0700 +func IsTimeNear(t1, t2 time.Time, offsetDuration time.Duration) bool { + t1 = t1.UTC() + t2 = t2.UTC() + + diff := t1.Sub(t2) + return offsetDuration.Abs() >= diff.Abs() +} + // GetLocationFromUtcTimezone returns location corresponding to specified UTC-based timezone func GetLocationFromUtcTimezone(utcTimezone int) *time.Location { ensureUtcTimezone(utcTimezone) diff --git a/utils/time_util_test.go b/utils/time_util_test.go index f0d3e59..48bb7e9 100644 --- a/utils/time_util_test.go +++ b/utils/time_util_test.go @@ -123,3 +123,56 @@ func TestGetUtcName(t *testing.T) { }) } } + +func TestIsTimeNear(t *testing.T) { + nowUTC := time.Now().UTC() + nowUS := nowUTC.In(GetLocationFromUtcTimezone(-7)) + + makeTimeUTC := func(shiftSeconds int) time.Time { + return nowUTC.Add(time.Duration(shiftSeconds) * time.Second) + } + + tests := []struct { + shiftSeconds int + timeFrame time.Time + offsetDuration time.Duration + want bool + }{ + { + shiftSeconds: 10, + offsetDuration: 10 * time.Second, + want: true, + }, + { + shiftSeconds: 9, + offsetDuration: 10 * time.Second, + want: true, + }, + { + shiftSeconds: 11, + offsetDuration: 10 * time.Second, + want: false, + }, + } + for i, tt := range tests { + timeFrameUTC := makeTimeUTC(tt.shiftSeconds) + + t.Run(fmt.Sprintf("[%d] UTC %v vs %v", i, nowUTC, timeFrameUTC), func(t *testing.T) { + if got := IsTimeNear(nowUTC, timeFrameUTC, tt.offsetDuration); got != tt.want { + t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want) + } + }) + + t.Run(fmt.Sprintf("[%d] AnyZone %v vs %v", i, nowUS, timeFrameUTC), func(t *testing.T) { + if got := IsTimeNear(nowUS, timeFrameUTC, tt.offsetDuration); got != tt.want { + t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want) + } + }) + + t.Run(fmt.Sprintf("[%d] Change position", i), func(t *testing.T) { + if got := IsTimeNear(timeFrameUTC, nowUS, tt.offsetDuration); got != tt.want { + t.Errorf("IsMatchTimeFrame() = %v, want %v", got, tt.want) + } + }) + } +}