From 58542aea813e968217b2d39ac1873f75877e954c Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Fri, 20 Sep 2024 11:05:27 -0500 Subject: [PATCH] feat: base gordian --- chain/cosmos/consensus/gordian.go | 113 ++++++++++++++++++++++++++ examples/cosmos/chain_gordian_test.go | 109 +++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 chain/cosmos/consensus/gordian.go create mode 100644 examples/cosmos/chain_gordian_test.go diff --git a/chain/cosmos/consensus/gordian.go b/chain/cosmos/consensus/gordian.go new file mode 100644 index 000000000..f2bdbda0f --- /dev/null +++ b/chain/cosmos/consensus/gordian.go @@ -0,0 +1,113 @@ +package consensus + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net/http" + "os" + "strings" + + coretypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos/cli" + "github.com/strangelove-ventures/interchaintest/v8/dockerutil" +) + +var _ Client = (*GordianClient)(nil) + +type GordianClient struct { + addr string + client *http.Client +} + +func NewGordianClient(addr string, client *http.Client) *GordianClient { + addr = strings.Replace(addr, "tcp://", "http://", 1) + + return &GordianClient{ + addr: addr, + client: client, + } +} + +// ClientType implements Client. +func (g *GordianClient) ClientType() ClientType { + return Gordian +} + +// Block implements Client. +func (g *GordianClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { + return &coretypes.ResultBlock{}, nil +} + +// BlockResults implements Client. +func (g *GordianClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { + return &coretypes.ResultBlockResults{}, nil +} + +// Height implements Client. +func (g *GordianClient) Height(ctx context.Context) (int64, error) { + type GordianCurrentBlockResponse struct { + VotingHeight *uint64 `protobuf:"varint,1,opt,name=voting_height,json=votingHeight,proto3,oneof" json:"voting_height,omitempty"` + } + + // TODO: get hostname query to work + endpoint := fmt.Sprintf("%s/blocks/watermark", g.addr) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + log.Print(err) + os.Exit(1) + } + q := req.URL.Query() + + // make request as JSON + req.Header.Set("Content-Type", "application/json") + req.URL.RawQuery = q.Encode() + + // client := &http.Client{} + resp, err := g.client.Do(req) + if err != nil { + log.Print(err) + os.Exit(1) + } + defer resp.Body.Close() + + var watermark GordianCurrentBlockResponse + if err := json.NewDecoder(resp.Body).Decode(&watermark); err != nil { + log.Print(err) + os.Exit(1) + } + + return int64(*watermark.VotingHeight), nil +} + +// IsClient implements Client. +func (g *GordianClient) IsClient(ctx context.Context, img *dockerutil.Image, bin string) bool { + res := img.Run(ctx, []string{bin, "gordian"}, dockerutil.ContainerOptions{}) + return cli.HasCommand(res.Err) +} + +// IsSynced implements Client. +func (g *GordianClient) IsSynced(ctx context.Context) error { + // TODO: + h, err := g.Height(ctx) + if err != nil { + return fmt.Errorf("failed to get height: %w", err) + } + + if h > 0 { + return nil + } + + return fmt.Errorf("height is 0") +} + +// StartFlags implements Client. +func (g *GordianClient) StartFlags(context.Context) string { + return "" +} + +// Status implements Client. +func (g *GordianClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { + return &coretypes.ResultStatus{}, nil +} diff --git a/examples/cosmos/chain_gordian_test.go b/examples/cosmos/chain_gordian_test.go new file mode 100644 index 000000000..2041ce839 --- /dev/null +++ b/examples/cosmos/chain_gordian_test.go @@ -0,0 +1,109 @@ +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" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func TestChainGordian(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + t.Parallel() + + cosmos.SetSDKConfig(baseBech32) + + sdk47Genesis := []cosmos.GenesisKV{ + cosmos.NewGenesisKV("app_state.gov.params.voting_period", "15s"), + cosmos.NewGenesisKV("app_state.gov.params.max_deposit_period", "10s"), + cosmos.NewGenesisKV("app_state.gov.params.min_deposit.0.denom", "token"), + cosmos.NewGenesisKV("app_state.gov.params.min_deposit.0.amount", "1"), + cosmos.NewGenesisKV("app_state.bank.denom_metadata", []banktypes.Metadata{denomMetadata}), + } + + decimals := int64(6) + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + Name: "gordianproject", + ChainName: "gordianproject", + Version: "local", // spawn -> gordian, modify docker file, build + ChainConfig: ibc.ChainConfig{ + Images: []ibc.DockerImage{ + { + Repository: "gordianproject", + Version: "local", + UidGid: "1025:1025", + }, + }, + Type: "cosmos", + Name: "gordian", + ChainID: "gordian-1", + GasPrices: "0.0" + denomMetadata.Base, + CoinDecimals: &decimals, + Bin: "appd", + TrustingPeriod: "330h", + AdditionalStartArgs: []string{ + "--g-http-addr", ":26657", + "--g-grpc-addr", ":9092", // gRPC 9090 is already used by the SDK. + }, + Denom: denomMetadata.Base, + Bech32Prefix: baseBech32, + CoinType: "118", + ModifyGenesis: cosmos.ModifyGenesis(sdk47Genesis), + GasAdjustment: 1.5, + }, + NumValidators: &numValsOne, + NumFullNodes: &numFullNodesZero, + }, + }) + + 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() + }) + + // TODO: gordian does not yet accept standard tx commands, it requires a manual broadcast of a generate only. Need to submit the raw bytes properly + // users := interchaintest.GetAndFundTestUsers(t, ctx, "default", genesisAmt, chain, chain) + // user1 := users[1].FormattedAddress() + // fmt.Println("user1", user1, "yuh") + + // b2, err := chain.BankQueryBalance(ctx, user1, chain.Config().Denom) + // require.NoError(t, err) + + // fmt.Println("b2", b2) + + // send 1 token + // sendAmt := int64(1) + // _, err = sendTokens(ctx, chain, users[0], users[1], "", sendAmt) + // require.NoError(t, err) + + // // check balances + // b2New, err := chain.GetBalance(ctx, user1, chain.Config().Denom) + // require.NoError(t, err) + // require.Equal(t, b2.Add(sdkmath.NewInt(sendAmt)), b2New) + +}