From 20efba3d196eae01f0e701ba7b252e852e1d6316 Mon Sep 17 00:00:00 2001 From: Jeongseup Date: Sat, 13 May 2023 00:09:34 +0900 Subject: [PATCH] Feature : Support Valcons Address For ICS (#63) * support valcons address * update cc.valInfo.Valcons logic --------- Co-authored-by: schultzie --- example-config.yml | 3 ++- td2/validator.go | 65 +++++++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/example-config.yml b/example-config.yml index a8d3df0..21d6e77 100644 --- a/example-config.yml +++ b/example-config.yml @@ -59,7 +59,8 @@ chains: # chain_id is validated for a match when connecting to an RPC endpoint, also used as a label in several places. chain_id: osmosis-1 # Hooray, in v2 we derive the valcons from abci queries so you don't have to jump through hoops to figure out how - # to convert ed25519 keys to the appropriate bech32 address + # to convert ed25519 keys to the appropriate bech32 address. + # Use valcons address if using ICS valoper_address: osmovaloper1xxxxxxx... # Should the monitor revert to using public API endpoints if all supplied RCP nodes fail? # This isn't always reliable, not all public nodes have websocket proxying setup correctly. diff --git a/td2/validator.go b/td2/validator.go index 1c5e294..ac01ce7 100644 --- a/td2/validator.go +++ b/td2/validator.go @@ -2,16 +2,18 @@ package tenderduty import ( "context" + "encoding/hex" "errors" "fmt" + "strings" + "time" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/types/bech32" slashing "github.com/cosmos/cosmos-sdk/x/slashing/types" staking "github.com/cosmos/cosmos-sdk/x/staking/types" rpchttp "github.com/tendermint/tendermint/rpc/client/http" - "strings" - "time" ) // ValInfo holds most of the stats/info used for secondary alarms. It is refreshed roughly every minute. @@ -51,30 +53,36 @@ func (cc *ChainConfig) GetValInfo(first bool) (err error) { l(fmt.Sprintf("❌ %s (%s) is INACTIVE", cc.ValAddress, cc.valInfo.Moniker)) } - // need to know the prefix for when we serialize the slashing info query, this is too fragile. - // for now, we perform specific chain overrides based on known values because the valoper is used - // in so many places. - var prefix string - split := strings.Split(cc.ValAddress, "valoper") - if len(split) != 2 { - if pre, ok := altValopers.getAltPrefix(cc.ValAddress); ok { - cc.valInfo.Valcons, err = bech32.ConvertAndEncode(pre, cc.valInfo.Conspub[:20]) - if err != nil { + if strings.Contains(cc.ValAddress, "valcons") { + // no need to change prefix for signing info query + cc.valInfo.Valcons = cc.ValAddress + } else { + // need to know the prefix for when we serialize the slashing info query, this is too fragile. + // for now, we perform specific chain overrides based on known values because the valoper is used + // in so many places. + var prefix string + split := strings.Split(cc.ValAddress, "valoper") + if len(split) != 2 { + if pre, ok := altValopers.getAltPrefix(cc.ValAddress); ok { + cc.valInfo.Valcons, err = bech32.ConvertAndEncode(pre, cc.valInfo.Conspub[:20]) + if err != nil { + return + } + } else { + err = errors.New("❓ could not determine bech32 prefix from valoper address: " + cc.ValAddress) return } } else { - err = errors.New("❓ could not determine bech32 prefix from valoper address: " + cc.ValAddress) - return + prefix = split[0] + "valcons" + cc.valInfo.Valcons, err = bech32.ConvertAndEncode(prefix, cc.valInfo.Conspub[:20]) + if err != nil { + return + } } - } else { - prefix = split[0] + "valcons" - cc.valInfo.Valcons, err = bech32.ConvertAndEncode(prefix, cc.valInfo.Conspub[:20]) - if err != nil { - return + if first { + l("⚙️", cc.ValAddress[:20], "... is using consensus key:", cc.valInfo.Valcons) } - } - if first { - l("⚙️", cc.ValAddress[:20], "... is using consensus key:", cc.valInfo.Valcons) + } // get current signing information (tombstoned, missed block count) @@ -133,6 +141,16 @@ func (cc *ChainConfig) GetValInfo(first bool) (err error) { // getVal returns the public key, moniker, and if the validator is jailed. func getVal(ctx context.Context, client *rpchttp.HTTP, valoper string) (pub []byte, moniker string, jailed, bonded bool, err error) { + if strings.Contains(valoper, "valcons") { + _, bz, err := bech32.DecodeAndConvert(valoper) + if err != nil { + return nil, "", false, false, errors.New("could not decode and convert your address" + valoper) + } + + hexAddress := fmt.Sprintf("%X", bz) + return ToBytes(hexAddress), valoper, false, true, nil + } + q := staking.QueryValidatorRequest{ ValidatorAddr: valoper, } @@ -179,3 +197,8 @@ func getVal(ctx context.Context, client *rpchttp.HTTP, valoper string) (pub []by return pubBytes, val.Validator.GetMoniker(), val.Validator.Jailed, val.Validator.Status == 3, nil } + +func ToBytes(address string) []byte { + bz, _ := hex.DecodeString(strings.ToLower(address)) + return bz +}