Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/scripts/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 15 additions & 7 deletions deployment/cre/jobs/operations/propose_gateway_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ type ProposeGatewayJobInput struct {
ServiceCentricFormatEnabled bool `yaml:"serviceCentricFormatEnabled"`
DONs []DON `yaml:"dons"`
Services []GatewayService `yaml:"services"`
GatewayRequestTimeoutSec int `yaml:"gatewayRequestTimeoutSec"`
AllowedPorts []int `yaml:"allowedPorts"`
GatewayRequestTimeoutSec pkg.Int `yaml:"gatewayRequestTimeoutSec"`
AllowedPorts []pkg.Int `yaml:"allowedPorts"`
AllowedSchemes []string `yaml:"allowedSchemes"`
AllowedIPsCIDR []string `yaml:"allowedIPsCIDR"`
AuthGatewayID string `yaml:"authGatewayID"`
Expand All @@ -37,7 +37,7 @@ type ProposeGatewayJobInput struct {

type DON struct {
Name string `yaml:"name"`
F int `yaml:"f"`
F pkg.Int `yaml:"f"`
Handlers []string `yaml:"handlers"`
}

Expand Down Expand Up @@ -66,7 +66,7 @@ var ProposeGatewayJob = operations.NewOperation[ProposeGatewayJobInput, ProposeG
// When ServiceCentricFormatEnabled is true, it derives the set of unique DON names from
// input.Services; otherwise it uses the don-centric input.DONs list.
func proposeGatewayJob(b operations.Bundle, deps ProposeGatewayJobDeps, input ProposeGatewayJobInput) (ProposeGatewayJobOutput, error) {
requestTimeoutSec := input.GatewayRequestTimeoutSec
requestTimeoutSec := int(input.GatewayRequestTimeoutSec)
if requestTimeoutSec == 0 {
requestTimeoutSec = defaultGatewayRequestTimeoutSec
}
Expand Down Expand Up @@ -181,7 +181,7 @@ func buildServiceCentricJob(deps ProposeGatewayJobDeps, input ProposeGatewayJobI
DONs: dons,
Services: services,
RequestTimeoutSec: requestTimeoutSec,
AllowedPorts: input.AllowedPorts,
AllowedPorts: toIntSlice(input.AllowedPorts),
AllowedSchemes: input.AllowedSchemes,
AllowedIPsCIDR: input.AllowedIPsCIDR,
AuthGatewayID: input.AuthGatewayID,
Expand All @@ -197,7 +197,7 @@ func buildLegacyFormatJob(deps ProposeGatewayJobDeps, input ProposeGatewayJobInp
}
targetDONs = append(targetDONs, pkg.TargetDON{
ID: ad.Name,
F: ad.F,
F: int(ad.F),
Members: members,
Handlers: ad.Handlers,
})
Expand All @@ -207,7 +207,7 @@ func buildLegacyFormatJob(deps ProposeGatewayJobDeps, input ProposeGatewayJobInp
JobName: "CRE Gateway",
TargetDONs: targetDONs,
RequestTimeoutSec: requestTimeoutSec,
AllowedPorts: input.AllowedPorts,
AllowedPorts: toIntSlice(input.AllowedPorts),
AllowedSchemes: input.AllowedSchemes,
AllowedIPsCIDR: input.AllowedIPsCIDR,
AuthGatewayID: input.AuthGatewayID,
Expand Down Expand Up @@ -288,6 +288,14 @@ func resolveDONMembers(deps ProposeGatewayJobDeps, input ProposeGatewayJobInput,
return members, f, nil
}

func toIntSlice(vs []pkg.Int) []int {
out := make([]int, len(vs))
for i, v := range vs {
out[i] = int(v)
}
return out
}

func parseSelector(sel uint64) (nodev1.ChainType, string, error) {
fam, err := chainsel.GetSelectorFamily(sel)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions deployment/cre/jobs/operations/propose_gateway_job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func TestProposeGatewayJob(t *testing.T) {
output: ProposeGatewayJobOutput{
Specs: map[string][]string{
"node_5": {
"type = 'gateway'\nschemaVersion = 1\nname = 'CRE Gateway'\nexternalJobID = 'cf8aa339-6349-5e5b-9289-5c2907711200'\nforwardingAllowed = false\n\n[gatewayConfig]\n[gatewayConfig.ConnectionManagerConfig]\nAuthChallengeLen = 10\nAuthGatewayId = 'gateway-node-0'\nAuthTimestampToleranceSec = 5\nHeartbeatIntervalSec = 20\n\n[[gatewayConfig.ShardedDONs]]\nDonName = 'workflow_1_zone-b'\nF = 0\n\n[[gatewayConfig.ShardedDONs.Shards]]\n[[gatewayConfig.ShardedDONs.Shards.Nodes]]\nAddress = '0x04'\nName = 'cl-cre-one-zone-b-0 (DON workflow_1_zone-b)'\n\n[[gatewayConfig.Services]]\nServiceName = 'workflows'\nDONs = ['workflow_1_zone-b']\n\n[[gatewayConfig.Services.Handlers]]\nName = 'http-capabilities'\nServiceName = 'workflows'\n\n[gatewayConfig.Services.Handlers.Config]\nCleanUpPeriodMs = 600000\n\n[[gatewayConfig.Services.Handlers]]\nName = 'web-api-capabilities'\n\n[gatewayConfig.Services.Handlers.Config]\nmaxAllowedMessageAgeSec = 1000\n\n[gatewayConfig.Services.Handlers.Config.NodeRateLimiter]\nglobalBurst = 10\nglobalRPS = 50\nperSenderBurst = 10\nperSenderRPS = 10\n\n[gatewayConfig.HTTPClientConfig]\nMaxResponseBytes = 50000000\nAllowedPorts = [443]\nAllowedSchemes = ['https']\nAllowedIPsCIDR = []\n\n[gatewayConfig.NodeServerConfig]\nHandshakeTimeoutMillis = 1000\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5003\nReadTimeoutMillis = 1000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 1000\n\n[gatewayConfig.UserServerConfig]\nContentTypeHeader = 'application/jsonrpc'\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5002\nReadTimeoutMillis = 5000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 6000\n",
"type = 'gateway'\nschemaVersion = 1\nname = 'CRE Gateway'\nexternalJobID = 'cf8aa339-6349-5e5b-9289-5c2907711200'\nforwardingAllowed = false\n\n[gatewayConfig]\n[gatewayConfig.ConnectionManagerConfig]\nAuthChallengeLen = 10\nAuthGatewayId = 'gateway-node-0'\nAuthTimestampToleranceSec = 5\nHeartbeatIntervalSec = 20\n\n[[gatewayConfig.ShardedDONs]]\nDonName = 'workflow_1_zone-b'\nF = 0\n\n[[gatewayConfig.ShardedDONs.Shards]]\n[[gatewayConfig.ShardedDONs.Shards.Nodes]]\nAddress = '0x04'\nName = 'cl-cre-one-zone-b-0 (DON workflow_1_zone-b)'\n\n[[gatewayConfig.Services]]\nServiceName = 'workflows'\nDONs = ['workflow_1_zone-b']\n\n[[gatewayConfig.Services.Handlers]]\nName = 'http-capabilities'\nServiceName = 'workflows'\n\n[gatewayConfig.Services.Handlers.Config]\nCleanUpPeriodMs = 600000\n\n[gatewayConfig.Services.Handlers.Config.NodeRateLimiter]\nglobalBurst = 100\nglobalRPS = 500\nperSenderBurst = 100\nperSenderRPS = 100\n\n[[gatewayConfig.Services.Handlers]]\nName = 'web-api-capabilities'\n\n[gatewayConfig.Services.Handlers.Config]\nmaxAllowedMessageAgeSec = 1000\n\n[gatewayConfig.Services.Handlers.Config.NodeRateLimiter]\nglobalBurst = 10\nglobalRPS = 50\nperSenderBurst = 10\nperSenderRPS = 10\n\n[gatewayConfig.HTTPClientConfig]\nMaxResponseBytes = 50000000\nAllowedPorts = [443]\nAllowedSchemes = ['https']\nAllowedIPsCIDR = []\n\n[gatewayConfig.NodeServerConfig]\nHandshakeTimeoutMillis = 1000\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5003\nReadTimeoutMillis = 1000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 1000\n\n[gatewayConfig.UserServerConfig]\nContentTypeHeader = 'application/jsonrpc'\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5002\nReadTimeoutMillis = 5000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 6000\n",
},
},
},
Expand All @@ -201,7 +201,7 @@ func TestProposeGatewayJob(t *testing.T) {
output: ProposeGatewayJobOutput{
Specs: map[string][]string{
"node_5": {
"type = 'gateway'\nschemaVersion = 1\nname = 'CRE Gateway'\nexternalJobID = 'cf8aa339-6349-5e5b-9289-5c2907711200'\nforwardingAllowed = false\n\n[gatewayConfig]\n[gatewayConfig.ConnectionManagerConfig]\nAuthChallengeLen = 10\nAuthGatewayId = 'gateway-node-0'\nAuthTimestampToleranceSec = 5\nHeartbeatIntervalSec = 20\n\n[[gatewayConfig.Dons]]\nDonId = 'workflow_1_zone-b'\nF = 1\n\n[[gatewayConfig.Dons.Handlers]]\nName = 'http-capabilities'\nServiceName = 'workflows'\n\n[gatewayConfig.Dons.Handlers.Config]\nCleanUpPeriodMs = 600000\n\n[[gatewayConfig.Dons.Handlers]]\nName = 'web-api-capabilities'\n\n[gatewayConfig.Dons.Handlers.Config]\nmaxAllowedMessageAgeSec = 1000\n\n[gatewayConfig.Dons.Handlers.Config.NodeRateLimiter]\nglobalBurst = 10\nglobalRPS = 50\nperSenderBurst = 10\nperSenderRPS = 10\n\n[[gatewayConfig.Dons.Members]]\nAddress = '0x04'\nName = 'cl-cre-one-zone-b-0 (DON workflow_1_zone-b)'\n\n[gatewayConfig.HTTPClientConfig]\nMaxResponseBytes = 50000000\nAllowedPorts = [443]\nAllowedSchemes = ['https']\nAllowedIPsCIDR = []\n\n[gatewayConfig.NodeServerConfig]\nHandshakeTimeoutMillis = 1000\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5003\nReadTimeoutMillis = 1000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 1000\n\n[gatewayConfig.UserServerConfig]\nContentTypeHeader = 'application/jsonrpc'\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5002\nReadTimeoutMillis = 5000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 6000\n",
"type = 'gateway'\nschemaVersion = 1\nname = 'CRE Gateway'\nexternalJobID = 'cf8aa339-6349-5e5b-9289-5c2907711200'\nforwardingAllowed = false\n\n[gatewayConfig]\n[gatewayConfig.ConnectionManagerConfig]\nAuthChallengeLen = 10\nAuthGatewayId = 'gateway-node-0'\nAuthTimestampToleranceSec = 5\nHeartbeatIntervalSec = 20\n\n[[gatewayConfig.Dons]]\nDonId = 'workflow_1_zone-b'\nF = 1\n\n[[gatewayConfig.Dons.Handlers]]\nName = 'http-capabilities'\nServiceName = 'workflows'\n\n[gatewayConfig.Dons.Handlers.Config]\nCleanUpPeriodMs = 600000\n\n[gatewayConfig.Dons.Handlers.Config.NodeRateLimiter]\nglobalBurst = 100\nglobalRPS = 500\nperSenderBurst = 100\nperSenderRPS = 100\n\n[[gatewayConfig.Dons.Handlers]]\nName = 'web-api-capabilities'\n\n[gatewayConfig.Dons.Handlers.Config]\nmaxAllowedMessageAgeSec = 1000\n\n[gatewayConfig.Dons.Handlers.Config.NodeRateLimiter]\nglobalBurst = 10\nglobalRPS = 50\nperSenderBurst = 10\nperSenderRPS = 10\n\n[[gatewayConfig.Dons.Members]]\nAddress = '0x04'\nName = 'cl-cre-one-zone-b-0 (DON workflow_1_zone-b)'\n\n[gatewayConfig.HTTPClientConfig]\nMaxResponseBytes = 50000000\nAllowedPorts = [443]\nAllowedSchemes = ['https']\nAllowedIPsCIDR = []\n\n[gatewayConfig.NodeServerConfig]\nHandshakeTimeoutMillis = 1000\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5003\nReadTimeoutMillis = 1000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 1000\n\n[gatewayConfig.UserServerConfig]\nContentTypeHeader = 'application/jsonrpc'\nMaxRequestBytes = 100000\nPath = '/'\nPort = 5002\nReadTimeoutMillis = 5000\nRequestTimeoutMillis = 5000\nWriteTimeoutMillis = 6000\n",
},
},
},
Expand Down
9 changes: 8 additions & 1 deletion deployment/cre/jobs/pkg/gateway_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ type nodeRateLimiterConfig struct {
}

type httpCapabilitiesHandlerConfig struct {
CleanUpPeriodMs int `toml:"CleanUpPeriodMs"`
CleanUpPeriodMs int `toml:"CleanUpPeriodMs"`
NodeRateLimiter nodeRateLimiterConfig `toml:"NodeRateLimiter"`
}

func newDefaultHTTPCapabilitiesHandler() handler {
Expand All @@ -434,6 +435,12 @@ func newDefaultHTTPCapabilitiesHandler() handler {
ServiceName: "workflows",
Config: httpCapabilitiesHandlerConfig{
CleanUpPeriodMs: 10 * 60 * 1000, // 10 minutes
NodeRateLimiter: nodeRateLimiterConfig{
GlobalBurst: 100,
GlobalRPS: 500,
PerSenderBurst: 100,
PerSenderRPS: 100,
},
},
}
}
6 changes: 6 additions & 0 deletions deployment/cre/jobs/pkg/gateway_job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ ServiceName = 'workflows'
[gatewayConfig.Services.Handlers.Config]
CleanUpPeriodMs = 600000

[gatewayConfig.Services.Handlers.Config.NodeRateLimiter]
globalBurst = 100
globalRPS = 500
perSenderBurst = 100
perSenderRPS = 100

[[gatewayConfig.Services]]
ServiceName = 'vault'
DONs = ['workflow_2']
Expand Down
4 changes: 4 additions & 0 deletions deployment/cre/jobs/pkg/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pkg

import (
"context"
"errors"
"fmt"

cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
Expand All @@ -25,6 +26,9 @@ type FetchNodeChainConfigsResponse struct {
}

func FetchNodeChainConfigsFromJD(ctx context.Context, e cldf.Environment, req FetchNodesRequest) ([]FetchNodeChainConfigsResponse, error) {
if e.Offchain == nil {
return nil, errors.New("offchain client (JD) is not initialized; ensure JD_GRPC or OFFCHAIN_JD_ENDPOINTS_GRPC is set")
}
resp, err := e.Offchain.ListNodes(ctx, &nodev1.ListNodesRequest{Filter: req.Filters})
if err != nil {
return nil, fmt.Errorf("failed to list nodes: %w", err)
Expand Down
17 changes: 17 additions & 0 deletions deployment/cre/jobs/pkg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ type OracleFactoryConfig struct {
Network string `toml:"network"` // e.g., "evm"
}

// Int wraps int so that YAML fields can be populated from either a numeric
// literal or a quoted string (e.g. after environment-variable substitution).
type Int int

func (i *Int) UnmarshalYAML(node *yaml.Node) error {
v, err := strconv.Atoi(node.Value)
if err != nil {
return err
}
*i = Int(v)
return nil
}

func (i Int) MarshalYAML() ([]byte, error) {
return []byte(strconv.Itoa(int(i))), nil
}

type ChainSelector uint64

func (cs *ChainSelector) UnmarshalText(data []byte) error {
Expand Down
131 changes: 131 additions & 0 deletions deployment/cre/jobs/propose_job_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import (
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"

chainsel "github.com/smartcontractkit/chain-selectors"

"github.com/smartcontractkit/chainlink-common/pkg/settings/cresettings"
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
cldpipelineinput "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/pipeline/input"
"github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job"
"github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node"
"github.com/smartcontractkit/chainlink/deployment/cre/jobs"
Expand Down Expand Up @@ -1753,3 +1755,132 @@ CallLimit = 1_000`, "invalid inputs for CRE settings job spec: invalid wf abcd:
})
}
}

func TestProposeJobSpec_GatewayJobYAMLConversion(t *testing.T) {
t.Parallel()

t.Run("service-centric format", func(t *testing.T) {
t.Parallel()

yamlSpec := `
environment: staging
domain: cre
changesets:
- job_propose_arbitrary:
payload:
donName: gateway-don
donFilters:
- key: don_name
value: gateway-don
- key: environment
value: staging
- key: product
value: cre
jobName: test-gateway-job-svc
template: gateway
inputs:
serviceCentricFormatEnabled: true
dons:
- name: workflow-don
f: 1
services:
- servicename: workflows
handlers:
- web-api-capabilities
- http-capabilities
dons:
- workflow-don
gatewayRequestTimeoutSec: 10
allowedSchemes:
- https
allowedIPsCIDR:
- 10.0.0.0/8
`
var root yaml.Node
err := yaml.Unmarshal([]byte(yamlSpec), &root)
require.NoError(t, err)

rootMap, ok := cldpipelineinput.YamlNodeToAny(&root).(map[string]any)
require.True(t, ok)

environment, _ := rootMap["environment"].(string)
domain, _ := rootMap["domain"].(string)

changesetData, err := cldpipelineinput.FindChangesetInData(rootMap["changesets"], "job_propose_arbitrary", "test")
require.NoError(t, err)

changesetMap, ok := changesetData.(map[string]any)
require.True(t, ok)

payload, ok := changesetMap["payload"]
require.True(t, ok)

payloadBytes, err := yaml.Marshal(payload)
require.NoError(t, err)

var parsed jobs.ProposeJobSpecInput
err = yaml.Unmarshal(payloadBytes, &parsed)
require.NoError(t, err)

parsed.Environment = environment
parsed.Domain = domain

assert.Equal(t, "staging", parsed.Environment)
assert.Equal(t, "cre", parsed.Domain)
assert.Equal(t, job_types.Gateway, parsed.Template)

var gatewayInput operations.ProposeGatewayJobInput
err = parsed.Inputs.UnmarshalTo(&gatewayInput)
require.NoError(t, err)

assert.True(t, gatewayInput.ServiceCentricFormatEnabled)
require.Len(t, gatewayInput.DONs, 1)
assert.Equal(t, "workflow-don", gatewayInput.DONs[0].Name)
assert.Equal(t, pkg.Int(1), gatewayInput.DONs[0].F)
require.Len(t, gatewayInput.Services, 1)
assert.Equal(t, "workflows", gatewayInput.Services[0].ServiceName)
assert.Equal(t, []string{"web-api-capabilities", "http-capabilities"}, gatewayInput.Services[0].Handlers)
assert.Equal(t, []string{"workflow-don"}, gatewayInput.Services[0].DONs)
assert.Equal(t, pkg.Int(10), gatewayInput.GatewayRequestTimeoutSec)
assert.Equal(t, []string{"https"}, gatewayInput.AllowedSchemes)
assert.Equal(t, []string{"10.0.0.0/8"}, gatewayInput.AllowedIPsCIDR)

// Build GatewayJob manually; in production member addresses are resolved via JD.
gj := pkg.GatewayJob{
ServiceCentricFormatEnabled: true,
JobName: "CRE Gateway",
DONs: []pkg.TargetDON{
{
ID: gatewayInput.DONs[0].Name,
F: int(gatewayInput.DONs[0].F),
Members: []pkg.TargetDONMember{
{Address: "0xdef456", Name: "mock-node-1 (DON workflow-don)"},
},
},
},
Services: []pkg.GatewayServiceConfig{
{
ServiceName: gatewayInput.Services[0].ServiceName,
Handlers: gatewayInput.Services[0].Handlers,
DONs: gatewayInput.Services[0].DONs,
},
},
RequestTimeoutSec: int(gatewayInput.GatewayRequestTimeoutSec),
AllowedSchemes: gatewayInput.AllowedSchemes,
AllowedIPsCIDR: gatewayInput.AllowedIPsCIDR,
}

require.NoError(t, gj.Validate())
assert.True(t, gj.ServiceCentricFormatEnabled)
assert.Equal(t, "CRE Gateway", gj.JobName)
assert.Equal(t, 10, gj.RequestTimeoutSec)
assert.Equal(t, []string{"https"}, gj.AllowedSchemes)
assert.Equal(t, []string{"10.0.0.0/8"}, gj.AllowedIPsCIDR)
require.Len(t, gj.DONs, 1)
assert.Equal(t, "workflow-don", gj.DONs[0].ID)
require.Len(t, gj.Services, 1)
assert.Equal(t, "workflows", gj.Services[0].ServiceName)
assert.Equal(t, []string{"web-api-capabilities", "http-capabilities"}, gj.Services[0].Handlers)
assert.Equal(t, []string{"workflow-don"}, gj.Services[0].DONs)
})
}
4 changes: 4 additions & 0 deletions deployment/cre/pkg/offchain/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package offchain

import (
"context"
"errors"
"fmt"
"slices"
"sort"
Expand Down Expand Up @@ -32,6 +33,9 @@ const (
)

func FetchNodesFromJD(ctx context.Context, jd cldf_offchain.Client, filter *nodeapiv1.ListNodesRequest_Filter) (nodes []*nodeapiv1.Node, err error) {
if jd == nil {
return nil, errors.New("offchain client (JD) is not initialized; ensure JD_GRPC or OFFCHAIN_JD_ENDPOINTS_GRPC is set")
}
resp, err := jd.ListNodes(ctx, &nodeapiv1.ListNodesRequest{Filter: filter})
if err != nil {
return nil, fmt.Errorf("failed to list nodes: %w", err)
Expand Down
1 change: 1 addition & 0 deletions deployment/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ require (
github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/supranational/blst v0.3.16 // indirect
github.com/suzuki-shunsuke/go-convmap v0.2.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect
Expand Down
Loading
Loading