From f76f3a46ca49bb00b3973a8fe8c3e91184685176 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Tue, 15 Oct 2024 04:25:11 +0700 Subject: [PATCH 1/2] refactor: add close body after use and fix lint (#22248) (cherry picked from commit 4274dcf4429cc725a3bda58410bd8325d721a3e9) # Conflicts: # collections/quad.go # tools/hubl/internal/registry.go --- collections/quad.go | 425 ++++++++++++++++++++++++++++++++ server/v2/cometbft/abci.go | 2 +- tools/hubl/internal/registry.go | 104 ++++++++ 3 files changed, 530 insertions(+), 1 deletion(-) create mode 100644 collections/quad.go create mode 100644 tools/hubl/internal/registry.go diff --git a/collections/quad.go b/collections/quad.go new file mode 100644 index 000000000000..cf17cc32eaba --- /dev/null +++ b/collections/quad.go @@ -0,0 +1,425 @@ +package collections + +import ( + "encoding/json" + "fmt" + "strings" + + "cosmossdk.io/collections/codec" + "cosmossdk.io/schema" +) + +// Quad defines a multipart key composed of four keys. +type Quad[K1, K2, K3, K4 any] struct { + k1 *K1 + k2 *K2 + k3 *K3 + k4 *K4 +} + +// Join4 instantiates a new Quad instance composed of the four provided keys, in order. +func Join4[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3, k4 K4) Quad[K1, K2, K3, K4] { + return Quad[K1, K2, K3, K4]{&k1, &k2, &k3, &k4} +} + +// K1 returns the first part of the key. If nil, the zero value is returned. +func (t Quad[K1, K2, K3, K4]) K1() (x K1) { + if t.k1 != nil { + return *t.k1 + } + return x +} + +// K2 returns the second part of the key. If nil, the zero value is returned. +func (t Quad[K1, K2, K3, K4]) K2() (x K2) { + if t.k2 != nil { + return *t.k2 + } + return x +} + +// K3 returns the third part of the key. If nil, the zero value is returned. +func (t Quad[K1, K2, K3, K4]) K3() (x K3) { + if t.k3 != nil { + return *t.k3 + } + return x +} + +// K4 returns the fourth part of the key. If nil, the zero value is returned. +func (t Quad[K1, K2, K3, K4]) K4() (x K4) { + if t.k4 != nil { + return *t.k4 + } + return x +} + +// QuadPrefix creates a new Quad instance composed only of the first part of the key. +func QuadPrefix[K1, K2, K3, K4 any](k1 K1) Quad[K1, K2, K3, K4] { + return Quad[K1, K2, K3, K4]{k1: &k1} +} + +// QuadSuperPrefix creates a new Quad instance composed only of the first two parts of the key. +func QuadSuperPrefix[K1, K2, K3, K4 any](k1 K1, k2 K2) Quad[K1, K2, K3, K4] { + return Quad[K1, K2, K3, K4]{k1: &k1, k2: &k2} +} + +// QuadSuperPrefix3 creates a new Quad instance composed only of the first three parts of the key. +func QuadSuperPrefix3[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3) Quad[K1, K2, K3, K4] { + return Quad[K1, K2, K3, K4]{k1: &k1, k2: &k2, k3: &k3} +} + +// QuadKeyCodec instantiates a new KeyCodec instance that can encode the Quad, given +// the KeyCodecs of the four parts of the key, in order. +func QuadKeyCodec[K1, K2, K3, K4 any](keyCodec1 codec.KeyCodec[K1], keyCodec2 codec.KeyCodec[K2], keyCodec3 codec.KeyCodec[K3], keyCodec4 codec.KeyCodec[K4]) codec.KeyCodec[Quad[K1, K2, K3, K4]] { + return quadKeyCodec[K1, K2, K3, K4]{ + keyCodec1: keyCodec1, + keyCodec2: keyCodec2, + keyCodec3: keyCodec3, + keyCodec4: keyCodec4, + } +} + +// NamedQuadKeyCodec instantiates a new KeyCodec instance that can encode the Quad, given +// the KeyCodecs of the four parts of the key, in order. +// The provided names are used to identify the parts of the key in the schema for indexing. +func NamedQuadKeyCodec[K1, K2, K3, K4 any](key1Name string, keyCodec1 codec.KeyCodec[K1], key2Name string, keyCodec2 codec.KeyCodec[K2], key3Name string, keyCodec3 codec.KeyCodec[K3], key4Name string, keyCodec4 codec.KeyCodec[K4]) codec.KeyCodec[Quad[K1, K2, K3, K4]] { + return quadKeyCodec[K1, K2, K3, K4]{ + name1: key1Name, + keyCodec1: keyCodec1, + name2: key2Name, + keyCodec2: keyCodec2, + name3: key3Name, + keyCodec3: keyCodec3, + name4: key4Name, + keyCodec4: keyCodec4, + } +} + +type quadKeyCodec[K1, K2, K3, K4 any] struct { + name1, name2, name3, name4 string + keyCodec1 codec.KeyCodec[K1] + keyCodec2 codec.KeyCodec[K2] + keyCodec3 codec.KeyCodec[K3] + keyCodec4 codec.KeyCodec[K4] +} + +type jsonQuadKey [4]json.RawMessage + +// EncodeJSON encodes Quads to json +func (t quadKeyCodec[K1, K2, K3, K4]) EncodeJSON(value Quad[K1, K2, K3, K4]) ([]byte, error) { + json1, err := t.keyCodec1.EncodeJSON(*value.k1) + if err != nil { + return nil, err + } + + json2, err := t.keyCodec2.EncodeJSON(*value.k2) + if err != nil { + return nil, err + } + + json3, err := t.keyCodec3.EncodeJSON(*value.k3) + if err != nil { + return nil, err + } + + json4, err := t.keyCodec4.EncodeJSON(*value.k4) + if err != nil { + return nil, err + } + + return json.Marshal(jsonQuadKey{json1, json2, json3, json4}) +} + +// DecodeJSON decodes json to Quads +func (t quadKeyCodec[K1, K2, K3, K4]) DecodeJSON(b []byte) (Quad[K1, K2, K3, K4], error) { + var jsonKey jsonQuadKey + err := json.Unmarshal(b, &jsonKey) + if err != nil { + return Quad[K1, K2, K3, K4]{}, err + } + + key1, err := t.keyCodec1.DecodeJSON(jsonKey[0]) + if err != nil { + return Quad[K1, K2, K3, K4]{}, err + } + + key2, err := t.keyCodec2.DecodeJSON(jsonKey[1]) + if err != nil { + return Quad[K1, K2, K3, K4]{}, err + } + + key3, err := t.keyCodec3.DecodeJSON(jsonKey[2]) + if err != nil { + return Quad[K1, K2, K3, K4]{}, err + } + + key4, err := t.keyCodec4.DecodeJSON(jsonKey[3]) + if err != nil { + return Quad[K1, K2, K3, K4]{}, err + } + + return Join4(key1, key2, key3, key4), nil +} + +// Stringify converts Quads to string +func (t quadKeyCodec[K1, K2, K3, K4]) Stringify(key Quad[K1, K2, K3, K4]) string { + b := new(strings.Builder) + b.WriteByte('(') + if key.k1 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec1.Stringify(*key.k1)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteString(", ") + if key.k2 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec2.Stringify(*key.k2)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteString(", ") + if key.k3 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec3.Stringify(*key.k3)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteString(", ") + if key.k4 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec4.Stringify(*key.k4)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteByte(')') + return b.String() +} + +func (t quadKeyCodec[K1, K2, K3, K4]) KeyType() string { + return fmt.Sprintf("Quad[%s,%s,%s,%s]", t.keyCodec1.KeyType(), t.keyCodec2.KeyType(), t.keyCodec3.KeyType(), t.keyCodec4.KeyType()) +} + +func (t quadKeyCodec[K1, K2, K3, K4]) Encode(buffer []byte, key Quad[K1, K2, K3, K4]) (int, error) { + writtenTotal := 0 + if key.k1 != nil { + written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k2 != nil { + written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k3 != nil { + written, err := t.keyCodec3.EncodeNonTerminal(buffer[writtenTotal:], *key.k3) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k4 != nil { + written, err := t.keyCodec4.Encode(buffer[writtenTotal:], *key.k4) + if err != nil { + return 0, err + } + writtenTotal += written + } + return writtenTotal, nil +} + +func (t quadKeyCodec[K1, K2, K3, K4]) Decode(buffer []byte) (int, Quad[K1, K2, K3, K4], error) { + readTotal := 0 + read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key3, err := t.keyCodec3.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key4, err := t.keyCodec4.Decode(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + return readTotal, Join4(key1, key2, key3, key4), nil +} + +func (t quadKeyCodec[K1, K2, K3, K4]) Size(key Quad[K1, K2, K3, K4]) int { + size := 0 + if key.k1 != nil { + size += t.keyCodec1.SizeNonTerminal(*key.k1) + } + if key.k2 != nil { + size += t.keyCodec2.SizeNonTerminal(*key.k2) + } + if key.k3 != nil { + size += t.keyCodec3.SizeNonTerminal(*key.k3) + } + if key.k4 != nil { + size += t.keyCodec4.Size(*key.k4) + } + return size +} + +func (t quadKeyCodec[K1, K2, K3, K4]) EncodeNonTerminal(buffer []byte, key Quad[K1, K2, K3, K4]) (int, error) { + writtenTotal := 0 + if key.k1 != nil { + written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k2 != nil { + written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k3 != nil { + written, err := t.keyCodec3.EncodeNonTerminal(buffer[writtenTotal:], *key.k3) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k4 != nil { + written, err := t.keyCodec4.EncodeNonTerminal(buffer[writtenTotal:], *key.k4) + if err != nil { + return 0, err + } + writtenTotal += written + } + return writtenTotal, nil +} + +func (t quadKeyCodec[K1, K2, K3, K4]) DecodeNonTerminal(buffer []byte) (int, Quad[K1, K2, K3, K4], error) { + readTotal := 0 + read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key3, err := t.keyCodec3.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + read, key4, err := t.keyCodec4.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Quad[K1, K2, K3, K4]{}, err + } + readTotal += read + return readTotal, Join4(key1, key2, key3, key4), nil +} + +func (t quadKeyCodec[K1, K2, K3, K4]) SizeNonTerminal(key Quad[K1, K2, K3, K4]) int { + size := 0 + if key.k1 != nil { + size += t.keyCodec1.SizeNonTerminal(*key.k1) + } + if key.k2 != nil { + size += t.keyCodec2.SizeNonTerminal(*key.k2) + } + if key.k3 != nil { + size += t.keyCodec3.SizeNonTerminal(*key.k3) + } + if key.k4 != nil { + size += t.keyCodec4.SizeNonTerminal(*key.k4) + } + return size +} + +func (t quadKeyCodec[K1, K2, K3, K4]) SchemaCodec() (codec.SchemaCodec[Quad[K1, K2, K3, K4]], error) { + field1, err := getNamedKeyField(t.keyCodec1, t.name1) + if err != nil { + return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key1 field: %w", err) + } + + field2, err := getNamedKeyField(t.keyCodec2, t.name2) + if err != nil { + return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key2 field: %w", err) + } + + field3, err := getNamedKeyField(t.keyCodec3, t.name3) + if err != nil { + return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key3 field: %w", err) + } + + field4, err := getNamedKeyField(t.keyCodec4, t.name4) + if err != nil { + return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key4 field: %w", err) + } + + return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{ + Fields: []schema.Field{field1, field2, field3, field4}, + }, nil +} + +// NewPrefixUntilQuadRange defines a collection query which ranges until the provided Quad prefix. +// Unstable: this API might change in the future. +func NewPrefixUntilQuadRange[K1, K2, K3, K4 any](k1 K1) Ranger[Quad[K1, K2, K3, K4]] { + key := QuadPrefix[K1, K2, K3, K4](k1) + return &Range[Quad[K1, K2, K3, K4]]{ + end: RangeKeyPrefixEnd(key), + } +} + +// NewPrefixedQuadRange provides a Range for all keys prefixed with the given +// first part of the Quad key. +func NewPrefixedQuadRange[K1, K2, K3, K4 any](k1 K1) Ranger[Quad[K1, K2, K3, K4]] { + key := QuadPrefix[K1, K2, K3, K4](k1) + return &Range[Quad[K1, K2, K3, K4]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} + +// NewSuperPrefixedQuadRange provides a Range for all keys prefixed with the given +// first and second parts of the Quad key. +func NewSuperPrefixedQuadRange[K1, K2, K3, K4 any](k1 K1, k2 K2) Ranger[Quad[K1, K2, K3, K4]] { + key := QuadSuperPrefix[K1, K2, K3, K4](k1, k2) + return &Range[Quad[K1, K2, K3, K4]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} + +// NewSuperPrefixedQuadRange3 provides a Range for all keys prefixed with the given +// first, second and third parts of the Quad key. +func NewSuperPrefixedQuadRange3[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3) Ranger[Quad[K1, K2, K3, K4]] { + key := QuadSuperPrefix3[K1, K2, K3, K4](k1, k2, k3) + return &Range[Quad[K1, K2, K3, K4]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index 57fac0676039..3248b48e1eba 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -108,7 +108,7 @@ func NewConsensus[T transaction.Tx]( indexedEvents: indexedEvents, initialHeight: 0, queryHandlersMap: queryHandlersMap, - getProtoRegistry: sync.OnceValues(func() (*protoregistry.Files, error) { return gogoproto.MergedRegistry() }), + getProtoRegistry: sync.OnceValues(gogoproto.MergedRegistry), } } diff --git a/tools/hubl/internal/registry.go b/tools/hubl/internal/registry.go new file mode 100644 index 000000000000..945e0ff4296c --- /dev/null +++ b/tools/hubl/internal/registry.go @@ -0,0 +1,104 @@ +package internal + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + "github.com/manifoldco/promptui" +) + +type ChainRegistryEntry struct { + APIs struct { + GRPC []*APIEntry `json:"grpc"` + } `json:"apis"` +} + +type APIEntry struct { + Address string + Provider string +} + +func GetChainRegistryEntry(chain string) (*ChainRegistryEntry, error) { + res, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/cosmos/chain-registry/master/%v/chain.json", chain)) + if err != nil { + return nil, err + } + bz, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + + if err = res.Body.Close(); err != nil { + return nil, err + } + + data := &ChainRegistryEntry{} + if err = json.Unmarshal(bz, data); err != nil { + return nil, err + } + + // clean-up the URL + cleanEntries := make([]*APIEntry, 0) + for i, apiEntry := range data.APIs.GRPC { + // clean-up the http(s):// prefix + if idx := strings.Index(apiEntry.Address, "://"); idx != -1 { + data.APIs.GRPC[i].Address = apiEntry.Address[idx+3:] + } + + // remove trailing slashes + data.APIs.GRPC[i].Address = strings.TrimSuffix(data.APIs.GRPC[i].Address, "/") + + // remove addresses without a port + if !strings.Contains(data.APIs.GRPC[i].Address, ":") { + continue + } + + cleanEntries = append(cleanEntries, data.APIs.GRPC[i]) + } + + data.APIs.GRPC = cleanEntries + return data, nil +} + +func SelectGRPCEndpoints(chain string) (string, error) { + entry, err := GetChainRegistryEntry(chain) + if err != nil || len(entry.APIs.GRPC) == 0 { + if err != nil { + // print error here so that user can know what happened and decide what to do next + fmt.Printf("Failed to load data for %s in the chain registry: %v\n", chain, err) + } else { + fmt.Printf("Found empty gRPC endpoint of %s in the chain registry.\n", chain) + } + fmt.Println("Specify a custom gRPC endpoint manually.") + prompt := &promptui.Prompt{ + Label: "Enter a gRPC endpoint that you trust", + } + return prompt.Run() + } + fmt.Printf("Found data for %s in the chain registry\n", chain) + + var items []string + for _, apiEntry := range entry.APIs.GRPC { + items = append(items, fmt.Sprintf("%s: %s", apiEntry.Provider, apiEntry.Address)) + } + prompt := promptui.SelectWithAdd{ + Label: fmt.Sprintf("Select a gRPC endpoint that you trust for the %s network", chain), + Items: items, + AddLabel: "Custom endpoint:", + } + + i, ep, err := prompt.Run() + if err != nil { + return "", err + } + + // user selected a custom endpoint + if i == -1 { + return ep, nil + } + + return entry.APIs.GRPC[i].Address, nil +} From e43168f95a1eb2ab779ea6842763d82f1253ddf9 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 15 Oct 2024 15:39:36 +0200 Subject: [PATCH 2/2] updates --- collections/quad.go | 425 -------------------------------- tools/hubl/internal/registry.go | 104 -------- 2 files changed, 529 deletions(-) delete mode 100644 collections/quad.go delete mode 100644 tools/hubl/internal/registry.go diff --git a/collections/quad.go b/collections/quad.go deleted file mode 100644 index cf17cc32eaba..000000000000 --- a/collections/quad.go +++ /dev/null @@ -1,425 +0,0 @@ -package collections - -import ( - "encoding/json" - "fmt" - "strings" - - "cosmossdk.io/collections/codec" - "cosmossdk.io/schema" -) - -// Quad defines a multipart key composed of four keys. -type Quad[K1, K2, K3, K4 any] struct { - k1 *K1 - k2 *K2 - k3 *K3 - k4 *K4 -} - -// Join4 instantiates a new Quad instance composed of the four provided keys, in order. -func Join4[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3, k4 K4) Quad[K1, K2, K3, K4] { - return Quad[K1, K2, K3, K4]{&k1, &k2, &k3, &k4} -} - -// K1 returns the first part of the key. If nil, the zero value is returned. -func (t Quad[K1, K2, K3, K4]) K1() (x K1) { - if t.k1 != nil { - return *t.k1 - } - return x -} - -// K2 returns the second part of the key. If nil, the zero value is returned. -func (t Quad[K1, K2, K3, K4]) K2() (x K2) { - if t.k2 != nil { - return *t.k2 - } - return x -} - -// K3 returns the third part of the key. If nil, the zero value is returned. -func (t Quad[K1, K2, K3, K4]) K3() (x K3) { - if t.k3 != nil { - return *t.k3 - } - return x -} - -// K4 returns the fourth part of the key. If nil, the zero value is returned. -func (t Quad[K1, K2, K3, K4]) K4() (x K4) { - if t.k4 != nil { - return *t.k4 - } - return x -} - -// QuadPrefix creates a new Quad instance composed only of the first part of the key. -func QuadPrefix[K1, K2, K3, K4 any](k1 K1) Quad[K1, K2, K3, K4] { - return Quad[K1, K2, K3, K4]{k1: &k1} -} - -// QuadSuperPrefix creates a new Quad instance composed only of the first two parts of the key. -func QuadSuperPrefix[K1, K2, K3, K4 any](k1 K1, k2 K2) Quad[K1, K2, K3, K4] { - return Quad[K1, K2, K3, K4]{k1: &k1, k2: &k2} -} - -// QuadSuperPrefix3 creates a new Quad instance composed only of the first three parts of the key. -func QuadSuperPrefix3[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3) Quad[K1, K2, K3, K4] { - return Quad[K1, K2, K3, K4]{k1: &k1, k2: &k2, k3: &k3} -} - -// QuadKeyCodec instantiates a new KeyCodec instance that can encode the Quad, given -// the KeyCodecs of the four parts of the key, in order. -func QuadKeyCodec[K1, K2, K3, K4 any](keyCodec1 codec.KeyCodec[K1], keyCodec2 codec.KeyCodec[K2], keyCodec3 codec.KeyCodec[K3], keyCodec4 codec.KeyCodec[K4]) codec.KeyCodec[Quad[K1, K2, K3, K4]] { - return quadKeyCodec[K1, K2, K3, K4]{ - keyCodec1: keyCodec1, - keyCodec2: keyCodec2, - keyCodec3: keyCodec3, - keyCodec4: keyCodec4, - } -} - -// NamedQuadKeyCodec instantiates a new KeyCodec instance that can encode the Quad, given -// the KeyCodecs of the four parts of the key, in order. -// The provided names are used to identify the parts of the key in the schema for indexing. -func NamedQuadKeyCodec[K1, K2, K3, K4 any](key1Name string, keyCodec1 codec.KeyCodec[K1], key2Name string, keyCodec2 codec.KeyCodec[K2], key3Name string, keyCodec3 codec.KeyCodec[K3], key4Name string, keyCodec4 codec.KeyCodec[K4]) codec.KeyCodec[Quad[K1, K2, K3, K4]] { - return quadKeyCodec[K1, K2, K3, K4]{ - name1: key1Name, - keyCodec1: keyCodec1, - name2: key2Name, - keyCodec2: keyCodec2, - name3: key3Name, - keyCodec3: keyCodec3, - name4: key4Name, - keyCodec4: keyCodec4, - } -} - -type quadKeyCodec[K1, K2, K3, K4 any] struct { - name1, name2, name3, name4 string - keyCodec1 codec.KeyCodec[K1] - keyCodec2 codec.KeyCodec[K2] - keyCodec3 codec.KeyCodec[K3] - keyCodec4 codec.KeyCodec[K4] -} - -type jsonQuadKey [4]json.RawMessage - -// EncodeJSON encodes Quads to json -func (t quadKeyCodec[K1, K2, K3, K4]) EncodeJSON(value Quad[K1, K2, K3, K4]) ([]byte, error) { - json1, err := t.keyCodec1.EncodeJSON(*value.k1) - if err != nil { - return nil, err - } - - json2, err := t.keyCodec2.EncodeJSON(*value.k2) - if err != nil { - return nil, err - } - - json3, err := t.keyCodec3.EncodeJSON(*value.k3) - if err != nil { - return nil, err - } - - json4, err := t.keyCodec4.EncodeJSON(*value.k4) - if err != nil { - return nil, err - } - - return json.Marshal(jsonQuadKey{json1, json2, json3, json4}) -} - -// DecodeJSON decodes json to Quads -func (t quadKeyCodec[K1, K2, K3, K4]) DecodeJSON(b []byte) (Quad[K1, K2, K3, K4], error) { - var jsonKey jsonQuadKey - err := json.Unmarshal(b, &jsonKey) - if err != nil { - return Quad[K1, K2, K3, K4]{}, err - } - - key1, err := t.keyCodec1.DecodeJSON(jsonKey[0]) - if err != nil { - return Quad[K1, K2, K3, K4]{}, err - } - - key2, err := t.keyCodec2.DecodeJSON(jsonKey[1]) - if err != nil { - return Quad[K1, K2, K3, K4]{}, err - } - - key3, err := t.keyCodec3.DecodeJSON(jsonKey[2]) - if err != nil { - return Quad[K1, K2, K3, K4]{}, err - } - - key4, err := t.keyCodec4.DecodeJSON(jsonKey[3]) - if err != nil { - return Quad[K1, K2, K3, K4]{}, err - } - - return Join4(key1, key2, key3, key4), nil -} - -// Stringify converts Quads to string -func (t quadKeyCodec[K1, K2, K3, K4]) Stringify(key Quad[K1, K2, K3, K4]) string { - b := new(strings.Builder) - b.WriteByte('(') - if key.k1 != nil { - b.WriteByte('"') - b.WriteString(t.keyCodec1.Stringify(*key.k1)) - b.WriteByte('"') - } else { - b.WriteString("") - } - - b.WriteString(", ") - if key.k2 != nil { - b.WriteByte('"') - b.WriteString(t.keyCodec2.Stringify(*key.k2)) - b.WriteByte('"') - } else { - b.WriteString("") - } - - b.WriteString(", ") - if key.k3 != nil { - b.WriteByte('"') - b.WriteString(t.keyCodec3.Stringify(*key.k3)) - b.WriteByte('"') - } else { - b.WriteString("") - } - - b.WriteString(", ") - if key.k4 != nil { - b.WriteByte('"') - b.WriteString(t.keyCodec4.Stringify(*key.k4)) - b.WriteByte('"') - } else { - b.WriteString("") - } - - b.WriteByte(')') - return b.String() -} - -func (t quadKeyCodec[K1, K2, K3, K4]) KeyType() string { - return fmt.Sprintf("Quad[%s,%s,%s,%s]", t.keyCodec1.KeyType(), t.keyCodec2.KeyType(), t.keyCodec3.KeyType(), t.keyCodec4.KeyType()) -} - -func (t quadKeyCodec[K1, K2, K3, K4]) Encode(buffer []byte, key Quad[K1, K2, K3, K4]) (int, error) { - writtenTotal := 0 - if key.k1 != nil { - written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k2 != nil { - written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k3 != nil { - written, err := t.keyCodec3.EncodeNonTerminal(buffer[writtenTotal:], *key.k3) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k4 != nil { - written, err := t.keyCodec4.Encode(buffer[writtenTotal:], *key.k4) - if err != nil { - return 0, err - } - writtenTotal += written - } - return writtenTotal, nil -} - -func (t quadKeyCodec[K1, K2, K3, K4]) Decode(buffer []byte) (int, Quad[K1, K2, K3, K4], error) { - readTotal := 0 - read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key3, err := t.keyCodec3.DecodeNonTerminal(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key4, err := t.keyCodec4.Decode(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - return readTotal, Join4(key1, key2, key3, key4), nil -} - -func (t quadKeyCodec[K1, K2, K3, K4]) Size(key Quad[K1, K2, K3, K4]) int { - size := 0 - if key.k1 != nil { - size += t.keyCodec1.SizeNonTerminal(*key.k1) - } - if key.k2 != nil { - size += t.keyCodec2.SizeNonTerminal(*key.k2) - } - if key.k3 != nil { - size += t.keyCodec3.SizeNonTerminal(*key.k3) - } - if key.k4 != nil { - size += t.keyCodec4.Size(*key.k4) - } - return size -} - -func (t quadKeyCodec[K1, K2, K3, K4]) EncodeNonTerminal(buffer []byte, key Quad[K1, K2, K3, K4]) (int, error) { - writtenTotal := 0 - if key.k1 != nil { - written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k2 != nil { - written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k3 != nil { - written, err := t.keyCodec3.EncodeNonTerminal(buffer[writtenTotal:], *key.k3) - if err != nil { - return 0, err - } - writtenTotal += written - } - if key.k4 != nil { - written, err := t.keyCodec4.EncodeNonTerminal(buffer[writtenTotal:], *key.k4) - if err != nil { - return 0, err - } - writtenTotal += written - } - return writtenTotal, nil -} - -func (t quadKeyCodec[K1, K2, K3, K4]) DecodeNonTerminal(buffer []byte) (int, Quad[K1, K2, K3, K4], error) { - readTotal := 0 - read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key3, err := t.keyCodec3.DecodeNonTerminal(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - read, key4, err := t.keyCodec4.DecodeNonTerminal(buffer[readTotal:]) - if err != nil { - return 0, Quad[K1, K2, K3, K4]{}, err - } - readTotal += read - return readTotal, Join4(key1, key2, key3, key4), nil -} - -func (t quadKeyCodec[K1, K2, K3, K4]) SizeNonTerminal(key Quad[K1, K2, K3, K4]) int { - size := 0 - if key.k1 != nil { - size += t.keyCodec1.SizeNonTerminal(*key.k1) - } - if key.k2 != nil { - size += t.keyCodec2.SizeNonTerminal(*key.k2) - } - if key.k3 != nil { - size += t.keyCodec3.SizeNonTerminal(*key.k3) - } - if key.k4 != nil { - size += t.keyCodec4.SizeNonTerminal(*key.k4) - } - return size -} - -func (t quadKeyCodec[K1, K2, K3, K4]) SchemaCodec() (codec.SchemaCodec[Quad[K1, K2, K3, K4]], error) { - field1, err := getNamedKeyField(t.keyCodec1, t.name1) - if err != nil { - return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key1 field: %w", err) - } - - field2, err := getNamedKeyField(t.keyCodec2, t.name2) - if err != nil { - return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key2 field: %w", err) - } - - field3, err := getNamedKeyField(t.keyCodec3, t.name3) - if err != nil { - return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key3 field: %w", err) - } - - field4, err := getNamedKeyField(t.keyCodec4, t.name4) - if err != nil { - return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{}, fmt.Errorf("error getting key4 field: %w", err) - } - - return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{ - Fields: []schema.Field{field1, field2, field3, field4}, - }, nil -} - -// NewPrefixUntilQuadRange defines a collection query which ranges until the provided Quad prefix. -// Unstable: this API might change in the future. -func NewPrefixUntilQuadRange[K1, K2, K3, K4 any](k1 K1) Ranger[Quad[K1, K2, K3, K4]] { - key := QuadPrefix[K1, K2, K3, K4](k1) - return &Range[Quad[K1, K2, K3, K4]]{ - end: RangeKeyPrefixEnd(key), - } -} - -// NewPrefixedQuadRange provides a Range for all keys prefixed with the given -// first part of the Quad key. -func NewPrefixedQuadRange[K1, K2, K3, K4 any](k1 K1) Ranger[Quad[K1, K2, K3, K4]] { - key := QuadPrefix[K1, K2, K3, K4](k1) - return &Range[Quad[K1, K2, K3, K4]]{ - start: RangeKeyExact(key), - end: RangeKeyPrefixEnd(key), - } -} - -// NewSuperPrefixedQuadRange provides a Range for all keys prefixed with the given -// first and second parts of the Quad key. -func NewSuperPrefixedQuadRange[K1, K2, K3, K4 any](k1 K1, k2 K2) Ranger[Quad[K1, K2, K3, K4]] { - key := QuadSuperPrefix[K1, K2, K3, K4](k1, k2) - return &Range[Quad[K1, K2, K3, K4]]{ - start: RangeKeyExact(key), - end: RangeKeyPrefixEnd(key), - } -} - -// NewSuperPrefixedQuadRange3 provides a Range for all keys prefixed with the given -// first, second and third parts of the Quad key. -func NewSuperPrefixedQuadRange3[K1, K2, K3, K4 any](k1 K1, k2 K2, k3 K3) Ranger[Quad[K1, K2, K3, K4]] { - key := QuadSuperPrefix3[K1, K2, K3, K4](k1, k2, k3) - return &Range[Quad[K1, K2, K3, K4]]{ - start: RangeKeyExact(key), - end: RangeKeyPrefixEnd(key), - } -} diff --git a/tools/hubl/internal/registry.go b/tools/hubl/internal/registry.go deleted file mode 100644 index 945e0ff4296c..000000000000 --- a/tools/hubl/internal/registry.go +++ /dev/null @@ -1,104 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - - "github.com/manifoldco/promptui" -) - -type ChainRegistryEntry struct { - APIs struct { - GRPC []*APIEntry `json:"grpc"` - } `json:"apis"` -} - -type APIEntry struct { - Address string - Provider string -} - -func GetChainRegistryEntry(chain string) (*ChainRegistryEntry, error) { - res, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/cosmos/chain-registry/master/%v/chain.json", chain)) - if err != nil { - return nil, err - } - bz, err := io.ReadAll(res.Body) - if err != nil { - return nil, err - } - - if err = res.Body.Close(); err != nil { - return nil, err - } - - data := &ChainRegistryEntry{} - if err = json.Unmarshal(bz, data); err != nil { - return nil, err - } - - // clean-up the URL - cleanEntries := make([]*APIEntry, 0) - for i, apiEntry := range data.APIs.GRPC { - // clean-up the http(s):// prefix - if idx := strings.Index(apiEntry.Address, "://"); idx != -1 { - data.APIs.GRPC[i].Address = apiEntry.Address[idx+3:] - } - - // remove trailing slashes - data.APIs.GRPC[i].Address = strings.TrimSuffix(data.APIs.GRPC[i].Address, "/") - - // remove addresses without a port - if !strings.Contains(data.APIs.GRPC[i].Address, ":") { - continue - } - - cleanEntries = append(cleanEntries, data.APIs.GRPC[i]) - } - - data.APIs.GRPC = cleanEntries - return data, nil -} - -func SelectGRPCEndpoints(chain string) (string, error) { - entry, err := GetChainRegistryEntry(chain) - if err != nil || len(entry.APIs.GRPC) == 0 { - if err != nil { - // print error here so that user can know what happened and decide what to do next - fmt.Printf("Failed to load data for %s in the chain registry: %v\n", chain, err) - } else { - fmt.Printf("Found empty gRPC endpoint of %s in the chain registry.\n", chain) - } - fmt.Println("Specify a custom gRPC endpoint manually.") - prompt := &promptui.Prompt{ - Label: "Enter a gRPC endpoint that you trust", - } - return prompt.Run() - } - fmt.Printf("Found data for %s in the chain registry\n", chain) - - var items []string - for _, apiEntry := range entry.APIs.GRPC { - items = append(items, fmt.Sprintf("%s: %s", apiEntry.Provider, apiEntry.Address)) - } - prompt := promptui.SelectWithAdd{ - Label: fmt.Sprintf("Select a gRPC endpoint that you trust for the %s network", chain), - Items: items, - AddLabel: "Custom endpoint:", - } - - i, ep, err := prompt.Run() - if err != nil { - return "", err - } - - // user selected a custom endpoint - if i == -1 { - return ep, nil - } - - return entry.APIs.GRPC[i].Address, nil -}