Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support chains with no gRPC & with BLS keys #43

Merged
merged 6 commits into from
Feb 28, 2025
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: 1 addition & 1 deletion internal/pkg/chain_watcher/height_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func NewStreamingHeightWatcher(ctx context.Context, cosmosClient *cosmos.Client,

// subscribe call hangs if the node is not running, this at least prevents
// the watcher from hanging at the start
if _, err := cosmosClient.GetCometbftClient().Status(ctx); err != nil {
if _, err := cosmosClient.GetStatus(ctx); err != nil {
return nil, errors.Wrapf(err, "failed to get cometbft status")
}

Expand Down
55 changes: 49 additions & 6 deletions internal/pkg/cosmos/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package cosmos

import (
"context"
"encoding/json"
"fmt"
"math"
"net"
"net/http"
"strconv"
"strings"
"time"
Expand All @@ -14,7 +16,6 @@ import (
cstypes "github.com/cometbft/cometbft/consensus/types"
cmtjson "github.com/cometbft/cometbft/libs/json"
cometbft "github.com/cometbft/cometbft/rpc/client/http"
ctypes "github.com/cometbft/cometbft/rpc/core/types"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
Expand Down Expand Up @@ -99,7 +100,11 @@ func (cc *Client) GetLatestBlockHeight(ctx context.Context) (int64, error) {

res, err := cc.tmClient.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{}, cc.callOptions...)
if err != nil {
return 0, errors.Wrapf(err, "failed to get latest block")
status, err2 := cc.GetStatus(ctx)
if err2 != nil {
return 0, errors.Wrapf(err, "failed to get latest block & status")
}
return status.SyncInfo.LatestBlockHeight, nil
}

if res.SdkBlock != nil {
Expand Down Expand Up @@ -160,12 +165,50 @@ func (cc *Client) GetProposalsV1beta1(ctx context.Context) (v1beta1.Proposals, e
return proposals, nil
}

func (cc *Client) GetStatus(ctx context.Context) (*ctypes.ResultStatus, error) {
response, err := cc.cometbftClient.Status(ctx)
type StatusResponse struct {
ValidatorInfo struct {
Address string `json:"address"`
VotingPower uint64 `json:"voting_power,string"`
} `json:"validator_info"`
NodeInfo struct {
Network string `json:"network"`
} `json:"node_info"`
SyncInfo struct {
LatestBlockTime string `json:"latest_block_time"`
LatestBlockHeight int64 `json:"latest_block_height,string"`
} `json:"sync_info"`
}

func (cc *Client) GetStatus(ctx context.Context) (*StatusResponse, error) {
// This code is manually deserializing the raw JSON output of the /status endpoint
// instead of using `cc.cometbftClient.Status(ctx)` because certain chains
// are using BLS12-381 keys, which are not part of the support enum for key format
// on the cometbft proto definitions, defined at
// https://github.com/cometbft/cometbft/blob/v0.38.17/proto/tendermint/crypto/keys.proto#L13
// BLS12-381 support was added to the enum on 1.0.0, in this commit
// https://github.com/cometbft/cometbft/commit/354c6bedd35a5825accb9defd60d65e27c6de643
// but 1.0.0 is not yet usable in this context; cosmossdk needs to release a new version for it

statusURL := strings.Replace(fmt.Sprintf("%s/status", cc.cometbftClient.Remote()), "tcp://", "http://", 1)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, statusURL, nil)
if err != nil {
return nil, errors.Wrapf(err, "failed to get status")
return nil, errors.Wrapf(err, "failed to create request")
}
return response, nil
c := http.Client{}
resp, err := c.Do(req)
if err != nil {
return nil, errors.Wrapf(err, "failed to perform HTTP request")
}
defer resp.Body.Close()

var statusResp struct {
Result StatusResponse `json:"result"`
}

if err := json.NewDecoder(resp.Body).Decode(&statusResp); err != nil {
return nil, errors.Wrapf(err, "failed to decode JSON")
}
return &statusResp.Result, nil
}

func (cc *Client) NodeInfo(ctx context.Context) (*tmservice.GetNodeInfoResponse, error) {
Expand Down
3 changes: 2 additions & 1 deletion internal/pkg/daemon/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func (d *Daemon) preUpgradeChecks(
cfg *config.PreUpgrade,
serviceName string,
upgrade *urproto.Upgrade,
networkName string,
) (int64, error) {
ctx = notification.WithUpgradeHeight(ctx, upgrade.Height)
logger := log.FromContext(ctx)
Expand All @@ -38,7 +39,7 @@ func (d *Daemon) preUpgradeChecks(
if currStep == urproto.UpgradeStep_MONITORING {
logger.Infof(
"Detected upcoming upgrade (type: %s, tag: %s, chain: %s) Current height: %d, upgrade height: %d",
upgrade.Type, upgrade.Tag, d.nodeInfo.DefaultNodeInfo.Network, currHeight, upgrade.Height,
upgrade.Type, upgrade.Tag, networkName, currHeight, upgrade.Height,
).Notify(ctx)

if len(cfg.Enabled) == 0 {
Expand Down
42 changes: 27 additions & 15 deletions internal/pkg/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package daemon

import (
"context"
"encoding/hex"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -136,18 +137,21 @@ func (d *Daemon) Init(ctx context.Context, cfg *config.Config) error {
}

d.chainID = status.NodeInfo.Network
d.validatorAddress = status.ValidatorInfo.Address.String()
d.validatorAddress = status.ValidatorInfo.Address

// display information about the node
d.nodeInfo, err = d.cosmosClient.NodeInfo(ctx)
if err != nil {
return errors.Wrapf(err, "failed to get node info")
}
logger.Infof("Connected to the %s node ID: %s", d.nodeInfo.ApplicationVersion.Name, d.nodeInfo.DefaultNodeInfo.DefaultNodeID)

// if the env prefix is not set, we set it to <APP_NAME>_ (e.g "GAIAD_")
if cfg.Compose.EnvPrefix == "" {
cfg.Compose.EnvPrefix = strings.ToUpper(d.nodeInfo.ApplicationVersion.AppName) + "_"
logger.Infof("No EnvPrefix found in config, fetching NodeInfo from GRPC")
d.nodeInfo, err = d.cosmosClient.NodeInfo(ctx)
if err != nil {
return errors.Wrapf(err, "failed to get node info")
}
logger.Infof("Connected to the %s node ID: %s", d.nodeInfo.ApplicationVersion.Name, d.nodeInfo.DefaultNodeInfo.DefaultNodeID)

// if the env prefix is not set, we set it to <APP_NAME>_ (e.g "GAIAD_")
if cfg.Compose.EnvPrefix == "" {
cfg.Compose.EnvPrefix = strings.ToUpper(d.nodeInfo.ApplicationVersion.AppName) + "_"
}
Comment on lines +144 to +154
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think there were some exceptions to the appname corresponding to the env prefix? onomy?? im not 100% sure, but even it that was the case it's okay for me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code didn't change -- just got indented; maybe it was always wrong?
as i see it: if left blank, take it from grpc. if the grpc value is not useful, provide it in the config.

}
logger.Infof("Using env prefix: %s", cfg.Compose.EnvPrefix)

Expand All @@ -158,11 +162,19 @@ func (d *Daemon) Init(ctx context.Context, cfg *config.Config) error {

logger.Infof("Observed latest block height: %d", status.SyncInfo.LatestBlockHeight)
d.currHeight = status.SyncInfo.LatestBlockHeight
d.currHeightTime = status.SyncInfo.LatestBlockTime
d.currHeightTime, err = time.Parse(time.RFC3339Nano, status.SyncInfo.LatestBlockTime)
if err != nil {
return errors.Wrapf(err, "failed to parse latest block time from status endpoint")
}
d.startupHeight = d.currHeight

logger.Infof("Observed node address: %s", status.ValidatorInfo.Address.String())
d.nodeAddress = status.ValidatorInfo.Address
logger.Infof("Observed node address: %s", status.ValidatorInfo.Address)
d.nodeAddress, err = hex.DecodeString(status.ValidatorInfo.Address)
if err != nil {
return errors.Wrapf(err, "failed to parse node address from status endpoint")
}

valVP := status.ValidatorInfo.VotingPower

// test consensus state endpoint
logger.Info("Attempting to get consensus state")
Expand All @@ -171,8 +183,8 @@ func (d *Daemon) Init(ctx context.Context, cfg *config.Config) error {
return errors.Wrapf(err, "failed to get consensus state")
}
logger.Infof(
"Total VP: %d, Node VP: %d, Node share: %.2f", pvp.TotalVP, status.ValidatorInfo.VotingPower,
(float64(status.ValidatorInfo.VotingPower)/float64(pvp.TotalVP))*100,
"Total VP: %d, Node VP: %d, Node share: %.2f", pvp.TotalVP, valVP,
(float64(valVP)/float64(pvp.TotalVP))*100,
)

// fetch future upgrades
Expand Down Expand Up @@ -385,7 +397,7 @@ func (d *Daemon) waitForUpgrade(ctx context.Context, cfg *config.Config) (int64,

// perform pre upgrade upgrade checks if we are close to the upgrade height
if futureUpgrade.Height < d.currHeight+cfg.Checks.PreUpgrade.Blocks {
newHeight, preErr := d.preUpgradeChecks(ctx, d.currHeight, d.stateMachine, d.dcc, &cfg.Compose, &cfg.Checks.PreUpgrade, cfg.ComposeService, futureUpgrade)
newHeight, preErr := d.preUpgradeChecks(ctx, d.currHeight, d.stateMachine, d.dcc, &cfg.Compose, &cfg.Checks.PreUpgrade, cfg.ComposeService, futureUpgrade, cfg.UpgradeRegistry.Network)
if preErr != nil {
d.MustSetStatus(futureUpgrade.Height, urproto.UpgradeStatus_FAILED)
}
Expand Down