From 684b4fed68f954a527a8aa3e961d9a92ed54c63d Mon Sep 17 00:00:00 2001 From: Reece Williams <31943163+Reecepbcups@users.noreply.github.com> Date: Thu, 14 Sep 2023 22:22:53 -0500 Subject: [PATCH] Get binary build information & dependencies (#760) --- chain/cosmos/chain_node.go | 76 +++++++++++++++ chain/cosmos/types.go | 20 ++++ examples/cosmos/chain_export_test.go | 6 +- examples/cosmos/chain_miscellaneous_test.go | 100 ++++++++++++++++++++ 4 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 examples/cosmos/chain_miscellaneous_test.go diff --git a/chain/cosmos/chain_node.go b/chain/cosmos/chain_node.go index 93f2cc6f6..ba00e429c 100644 --- a/chain/cosmos/chain_node.go +++ b/chain/cosmos/chain_node.go @@ -844,6 +844,82 @@ func (tn *ChainNode) HasCommand(ctx context.Context, command ...string) bool { return false } +// GetBuildInformation returns the build information and dependencies for the chain binary. +func (tn *ChainNode) GetBuildInformation(ctx context.Context) *BinaryBuildInformation { + stdout, _, err := tn.ExecBin(ctx, "version", "--long", "--output", "json") + if err != nil { + return nil + } + + type tempBuildDeps struct { + Name string `json:"name"` + ServerName string `json:"server_name"` + Version string `json:"version"` + Commit string `json:"commit"` + BuildTags string `json:"build_tags"` + Go string `json:"go"` + BuildDeps []string `json:"build_deps"` + CosmosSdkVersion string `json:"cosmos_sdk_version"` + } + + var deps tempBuildDeps + if err := json.Unmarshal([]byte(stdout), &deps); err != nil { + return nil + } + + getRepoAndVersion := func(dep string) (string, string) { + split := strings.Split(dep, "@") + return split[0], split[1] + } + + var buildDeps []BuildDependency + for _, dep := range deps.BuildDeps { + var bd BuildDependency + + if strings.Contains(dep, "=>") { + // Ex: "github.com/aaa/bbb@v1.2.1 => github.com/ccc/bbb@v1.2.0" + split := strings.Split(dep, " => ") + main, replacement := split[0], split[1] + + parent, parentVersion := getRepoAndVersion(main) + r, rV := getRepoAndVersion(replacement) + + bd = BuildDependency{ + Parent: parent, + Version: parentVersion, + IsReplacement: true, + Replacement: r, + ReplacementVersion: rV, + } + + } else { + // Ex: "github.com/aaa/bbb@v0.0.0-20191008050251-8e49817e8af4" + parent, version := getRepoAndVersion(dep) + + bd = BuildDependency{ + Parent: parent, + Version: version, + IsReplacement: false, + Replacement: "", + ReplacementVersion: "", + } + } + + buildDeps = append(buildDeps, bd) + } + + return &BinaryBuildInformation{ + BuildDeps: buildDeps, + Name: deps.Name, + ServerName: deps.ServerName, + Version: deps.Version, + Commit: deps.Commit, + BuildTags: deps.BuildTags, + Go: deps.Go, + CosmosSdkVersion: deps.CosmosSdkVersion, + } +} + // InstantiateContract takes a code id for a smart contract and initialization message and returns the instantiated contract address. func (tn *ChainNode) InstantiateContract(ctx context.Context, keyName string, codeID string, initMessage string, needsNoAdminFlag bool, extraExecTxArgs ...string) (string, error) { command := []string{"wasm", "instantiate", codeID, initMessage, "--label", "wasm-contract"} diff --git a/chain/cosmos/types.go b/chain/cosmos/types.go index 868b49035..7fd083d10 100644 --- a/chain/cosmos/types.go +++ b/chain/cosmos/types.go @@ -107,3 +107,23 @@ type ContractStateModels struct { Key string `json:"key"` Value string `json:"value"` } + +type BuildDependency struct { + Parent string `json:"parent"` + Version string `json:"version"` + + IsReplacement bool `json:"is_replacement"` + Replacement string `json:"replacement"` + ReplacementVersion string `json:"replacement_version"` +} + +type BinaryBuildInformation struct { + Name string `json:"name"` + ServerName string `json:"server_name"` + Version string `json:"version"` + Commit string `json:"commit"` + BuildTags string `json:"build_tags"` + Go string `json:"go"` + BuildDeps []BuildDependency `json:"build_deps"` + CosmosSdkVersion string `json:"cosmos_sdk_version"` +} diff --git a/examples/cosmos/chain_export_test.go b/examples/cosmos/chain_export_test.go index 5dcfc3eaa..feda8e5cd 100644 --- a/examples/cosmos/chain_export_test.go +++ b/examples/cosmos/chain_export_test.go @@ -16,12 +16,12 @@ import ( func TestJunoStateExport(t *testing.T) { // SDK v45 - CosmosChainStateExportTest(t, "juno", "v15.0.0", false) + CosmosChainStateExportTest(t, "juno", "v15.0.0") // SDK v47 - CosmosChainStateExportTest(t, "juno", "v16.0.0", true) + CosmosChainStateExportTest(t, "juno", "v16.0.0") } -func CosmosChainStateExportTest(t *testing.T, name, version string, useNewGenesisCmd bool) { +func CosmosChainStateExportTest(t *testing.T, name, version string) { if testing.Short() { t.Skip("skipping in short mode") } diff --git a/examples/cosmos/chain_miscellaneous_test.go b/examples/cosmos/chain_miscellaneous_test.go new file mode 100644 index 000000000..b12d3c728 --- /dev/null +++ b/examples/cosmos/chain_miscellaneous_test.go @@ -0,0 +1,100 @@ +package cosmos_test + +import ( + "context" + "testing" + + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +func TestICTestMiscellaneous(t *testing.T) { + CosmosChainTestMiscellaneous(t, "juno", "v16.0.0") +} + +func CosmosChainTestMiscellaneous(t *testing.T, name, version string) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + numVals := 1 + numFullNodes := 0 + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + Name: name, + ChainName: name, + Version: version, + ChainConfig: ibc.ChainConfig{ + Denom: "ujuno", + }, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + + ic := interchaintest.NewInterchain(). + AddChain(chain) + + ctx := context.Background() + client, network := interchaintest.DockerSetup(t) + + require.NoError(t, ic.Build(ctx, nil, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: true, + })) + t.Cleanup(func() { + _ = ic.Close() + }) + + BuildDependencies(ctx, t, chain) + +} + +func BuildDependencies(ctx context.Context, t *testing.T, chain *cosmos.CosmosChain) { + deps := chain.Validators[0].GetBuildInformation(ctx) + + sdkVer := "v0.47.3" + + require.Equal(t, deps.Name, "juno") + require.Equal(t, deps.ServerName, "junod") + require.Equal(t, deps.Version, "v16.0.0") + require.Equal(t, deps.CosmosSdkVersion, sdkVer) + require.Equal(t, deps.Commit, "054796f6173a9f15d012b656e255f94a4ec1d2cd") + require.Equal(t, deps.BuildTags, "netgo muslc,") + + for _, dep := range deps.BuildDeps { + dep := dep + + // Verify specific examples + if dep.Parent == "github.com/cosmos/cosmos-sdk" { + require.Equal(t, dep.Version, sdkVer) + require.Equal(t, dep.IsReplacement, false) + } else if dep.Parent == "github.com/99designs/keyring" { + require.Equal(t, dep.Version, "v1.2.2") + require.Equal(t, dep.IsReplacement, true) + require.Equal(t, dep.Replacement, "github.com/cosmos/keyring") + require.Equal(t, dep.ReplacementVersion, "v1.2.0") + + } + + // Verify all replacement logic + if dep.IsReplacement { + require.GreaterOrEqual(t, len(dep.ReplacementVersion), 6, "ReplacementVersion: %s must be >=6 length (ex: vA.B.C)", dep.ReplacementVersion) + require.Greater(t, len(dep.Replacement), 0, "Replacement: %s must be >0 length.", dep.Replacement) + } else { + require.Equal(t, len(dep.Replacement), 0, "Replacement: %s is not 0.", dep.Replacement) + require.Equal(t, len(dep.ReplacementVersion), 0, "ReplacementVersion: %s is not 0.", dep.ReplacementVersion) + } + } +}