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

feat: add the query signers command #315

Merged
merged 8 commits into from
Apr 26, 2023
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
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())
}
}
}()
Comment on lines +63 to +71
Copy link
Member

@evan-forbes evan-forbes Apr 26, 2023

Choose a reason for hiding this comment

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

[not blocking]

ideally we just call this later and pass the slice after we have appended to it. This should work, I think its just not ideal since multiple routines could touch that slice simultaneously. also, since we're already makeing a slice, then we might as well use the expected capacity

stopFuncs := make([]func() error, 0, 1)

Copy link
Member Author

Choose a reason for hiding this comment

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


// 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
}
Comment on lines +102 to +125
Copy link
Member

Choose a reason for hiding this comment

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

how long should this take and how heavy is this operation? should we just query an existing relayer instead of spinning up one in memory and querying the dht?

Copy link
Member Author

Choose a reason for hiding this comment

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

It takes no time to do this. Yes, it would make sense to add an RPC endpoint to get this information. However, we don't have time right now to implement it and we need a way to know who signed or not. We can merge this and open an issue to have this as an endpoint, what do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

okie dokie that's what I thought

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(),
)

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