Skip to content
This repository has been archived by the owner on Apr 15, 2024. It is now read-only.

Commit

Permalink
feat: add the query signers command (#315)
Browse files Browse the repository at this point in the history
* feat: add relayer query command

* feat: add relayer query command

* chore: refactor to a separate subcommand

* chore: timeout

* chore: move p2p node flag to where it belongs

* chore: lint fix

* chore: lint fix
  • Loading branch information
rach-id authored Apr 26, 2023
1 parent 72e2b47 commit a30c81d
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 4 deletions.
229 changes: 229 additions & 0 deletions cmd/qgb/query/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package query

import (
"context"
"fmt"
"math/big"
"os"
"strconv"
"time"

celestiatypes "github.com/celestiaorg/celestia-app/x/qgb/types"
"github.com/celestiaorg/orchestrator-relayer/cmd/qgb/common"
"github.com/celestiaorg/orchestrator-relayer/p2p"
"github.com/celestiaorg/orchestrator-relayer/rpc"
"github.com/celestiaorg/orchestrator-relayer/types"
ds "github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/pkg/errors"
"github.com/spf13/cobra"
tmlog "github.com/tendermint/tendermint/libs/log"
)

func Command() *cobra.Command {
queryCmd := &cobra.Command{
Use: "query",
Aliases: []string{"q"},
Short: "Query relevant information from a running QGB",
SilenceUsage: true,
}

queryCmd.AddCommand(
Signers(),
)

queryCmd.SetHelpCommand(&cobra.Command{})

return queryCmd
}

func Signers() *cobra.Command {
command := &cobra.Command{
Use: "signers <nonce>",
Args: cobra.ExactArgs(1),
Short: "Queries the QGB for attestations signers",
Long: "Queries the QGB for attestations signers. The nonce is the attestation nonce that the command" +
" will query signatures for. It should be either a specific nonce starting from 2 and on." +
" Or, use 'latest' as argument to check the latest attestation nonce",
RunE: func(cmd *cobra.Command, args []string) error {
config, err := parseFlags(cmd)
if err != nil {
return err
}

// creating the logger
logger := tmlog.NewTMLogger(os.Stdout)
logger.Debug("initializing queriers")

ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()

stopFuncs := make([]func() error, 0)
defer func() {
for _, f := range stopFuncs {
err := f()
if err != nil {
logger.Error(err.Error())
}
}
}()

// create tm querier and app querier
tmQuerier, appQuerier, stops, err := common.NewTmAndAppQuerier(logger, config.tendermintRPC, config.celesGRPC)
stopFuncs = append(stopFuncs, stops...)
if err != nil {
return err
}

// creating the host
h, err := libp2p.New()
if err != nil {
return err
}
addrInfo, err := peer.AddrInfoFromString(config.targetNode)
if err != nil {
return err
}
for i := 0; i < 5; i++ {
logger.Debug("connecting to target node...")
err := h.Connect(ctx, *addrInfo)
if err != nil {
logger.Error("couldn't connect to target node", "err", err.Error())
}
if err == nil {
logger.Debug("connected to target node")
break
}
time.Sleep(5 * time.Second)
}

// creating the data store
dataStore := dssync.MutexWrap(ds.NewMapDatastore())

// creating the dht
dht, err := p2p.NewQgbDHT(cmd.Context(), h, dataStore, []peer.AddrInfo{}, logger)
if err != nil {
return err
}

// creating the p2p querier
p2pQuerier := p2p.NewQuerier(dht, logger)

nonce, err := parseNonce(ctx, appQuerier, args[0])
if err != nil {
return err
}
if nonce == 1 {
return fmt.Errorf("nonce 1 doesn't need to be signed. signatures start from nonce 2")
}

err = getSignaturesAndPrintThem(ctx, logger, appQuerier, tmQuerier, p2pQuerier, nonce)
if err != nil {
return err
}
return nil
},
}
return addFlags(command)
}

func getSignaturesAndPrintThem(ctx context.Context, logger tmlog.Logger, appQuerier *rpc.AppQuerier, tmQuerier *rpc.TmQuerier, p2pQuerier *p2p.Querier, nonce uint64) error {
logger.Info("getting signatures for nonce", "nonce", nonce)

lastValset, err := appQuerier.QueryLastValsetBeforeNonce(ctx, nonce)
if err != nil {
return err
}

att, err := appQuerier.QueryAttestationByNonce(ctx, nonce)
if err != nil {
return err
}
if att == nil {
return celestiatypes.ErrAttestationNotFound
}

switch att.Type() {
case celestiatypes.ValsetRequestType:
vs, ok := att.(*celestiatypes.Valset)
if !ok {
return errors.Wrap(celestiatypes.ErrAttestationNotValsetRequest, strconv.FormatUint(nonce, 10))
}
signBytes, err := vs.SignBytes()
if err != nil {
return err
}
confirms, err := p2pQuerier.QueryValsetConfirms(ctx, nonce, *lastValset, signBytes.Hex())
if err != nil {
return err
}
confirmsMap := make(map[string]string)
for _, confirm := range confirms {
confirmsMap[confirm.EthAddress] = confirm.Signature
}
printConfirms(logger, confirmsMap, lastValset)
case celestiatypes.DataCommitmentRequestType:
dc, ok := att.(*celestiatypes.DataCommitment)
if !ok {
return errors.Wrap(types.ErrAttestationNotDataCommitmentRequest, strconv.FormatUint(nonce, 10))
}
commitment, err := tmQuerier.QueryCommitment(
ctx,
dc.BeginBlock,
dc.EndBlock,
)
if err != nil {
return err
}
dataRootHash := types.DataCommitmentTupleRootSignBytes(big.NewInt(int64(dc.Nonce)), commitment)
confirms, err := p2pQuerier.QueryDataCommitmentConfirms(ctx, *lastValset, nonce, dataRootHash.Hex())
if err != nil {
return err
}
confirmsMap := make(map[string]string)
for _, confirm := range confirms {
confirmsMap[confirm.EthAddress] = confirm.Signature
}
printConfirms(logger, confirmsMap, lastValset)
default:
return errors.Wrap(types.ErrUnknownAttestationType, strconv.FormatUint(nonce, 10))
}
return nil
}

func parseNonce(ctx context.Context, querier *rpc.AppQuerier, nonce string) (uint64, error) {
switch nonce {
case "latest":
return querier.QueryLatestAttestationNonce(ctx)
default:
return strconv.ParseUint(nonce, 10, 0)
}
}

func printConfirms(logger tmlog.Logger, confirmsMap map[string]string, valset *celestiatypes.Valset) {
signers := make(map[string]string)
missingSigners := make([]string, 0)

for _, validator := range valset.Members {
val, ok := confirmsMap[validator.EvmAddress]
if ok {
signers[validator.EvmAddress] = val
continue
}
missingSigners = append(missingSigners, validator.EvmAddress)
}

logger.Info("orchestrators that signed the attestation", "count", len(signers))
i := 0
for addr, sig := range signers {
logger.Info(addr, "number", i, "signature", sig)
i++
}

logger.Info("orchestrators that missed signing the attestation", "count", len(missingSigners))
for i, addr := range missingSigners {
logger.Info(addr, "number", i)
}
}
42 changes: 42 additions & 0 deletions cmd/qgb/query/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package query

import (
"github.com/celestiaorg/orchestrator-relayer/cmd/qgb/relayer"
"github.com/spf13/cobra"
)

const FlagP2PNode = "p2p-node"

func addFlags(cmd *cobra.Command) *cobra.Command {
cmd.Flags().StringP(relayer.FlagCelesGRPC, "c", "localhost:9090", "Specify the grpc address")
cmd.Flags().StringP(relayer.FlagTendermintRPC, "t", "http://localhost:26657", "Specify the rest rpc address")
cmd.Flags().StringP(FlagP2PNode, "n", "", "P2P target node multiaddress (eg. /ip4/127.0.0.1/tcp/30000/p2p/12D3KooWBSMasWzRSRKXREhediFUwABNZwzJbkZcYz5rYr9Zdmfn)")

return cmd
}

type Config struct {
celesGRPC, tendermintRPC string
targetNode string
}

func parseFlags(cmd *cobra.Command) (Config, error) {
tendermintRPC, err := cmd.Flags().GetString(relayer.FlagTendermintRPC)
if err != nil {
return Config{}, err
}
celesGRPC, err := cmd.Flags().GetString(relayer.FlagCelesGRPC)
if err != nil {
return Config{}, err
}
targetNode, err := cmd.Flags().GetString(FlagP2PNode)
if err != nil {
return Config{}, err
}

return Config{
celesGRPC: celesGRPC,
tendermintRPC: tendermintRPC,
targetNode: targetNode,
}, nil
}
8 changes: 4 additions & 4 deletions cmd/qgb/relayer/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ import (
)

func Command() *cobra.Command {
orchCmd := &cobra.Command{
relCmd := &cobra.Command{
Use: "relayer",
Aliases: []string{"rel"},
Short: "QGB relayer that relays signatures to the target EVM chain",
SilenceUsage: true,
}

orchCmd.AddCommand(
relCmd.AddCommand(
Start(),
Init(),
keys.Command("relayer"),
)

orchCmd.SetHelpCommand(&cobra.Command{})
relCmd.SetHelpCommand(&cobra.Command{})

return orchCmd
return relCmd
}

// Init initializes the orchestrator store and creates necessary files.
Expand Down
2 changes: 2 additions & 0 deletions cmd/qgb/root/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package root

import (
"github.com/celestiaorg/orchestrator-relayer/cmd/qgb/generate"
"github.com/celestiaorg/orchestrator-relayer/cmd/qgb/query"

"github.com/celestiaorg/celestia-app/x/qgb/client"
"github.com/celestiaorg/orchestrator-relayer/cmd/qgb/deploy"
Expand All @@ -26,6 +27,7 @@ func Cmd() *cobra.Command {
deploy.Command(),
client.VerifyCmd(),
generate.Command(),
query.Command(),
)

rootCmd.SetHelpCommand(&cobra.Command{})
Expand Down

0 comments on commit a30c81d

Please sign in to comment.