From c5b51348a5dfa8ea4159dc9c2812e63945dceadc Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" Date: Wed, 6 Nov 2024 16:39:07 +0700 Subject: [PATCH] Implement command to list power table and certificates form a peer (#735) Implement command to get certificates from a specific peer using the cert exchange protocol and optionally list power table entries for the first certificate listed. --- cmd/f3/certs.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ cmd/f3/main.go | 1 + 2 files changed, 130 insertions(+) create mode 100644 cmd/f3/certs.go diff --git a/cmd/f3/certs.go b/cmd/f3/certs.go new file mode 100644 index 00000000..ccec0a18 --- /dev/null +++ b/cmd/f3/certs.go @@ -0,0 +1,129 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "time" + + "github.com/filecoin-project/go-f3/certexchange" + "github.com/filecoin-project/go-f3/certs" + "github.com/filecoin-project/go-f3/gpbft" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/urfave/cli/v2" +) + +var ( + certFrom *peer.AddrInfo + + certsCmd = cli.Command{ + Name: "certs", + Subcommands: []*cli.Command{ + { + Name: "list-from", + Flags: []cli.Flag{ + limitFlag, + fromAddrFlag, + networkNameFlag, + includePowerTableFlag, + }, + Action: func(cctx *cli.Context) error { + instanceArg := cctx.Args().First() + if instanceArg == "" { + return errors.New("missing instance as first argument") + } + instance, err := strconv.ParseUint(instanceArg, 10, 64) + if err != nil { + return err + } + + if certFrom == nil { + return errors.New("--from addrinfo is required") + } + + host, err := libp2p.New() + if err != nil { + return err + } + defer func() { _ = host.Close() }() + + if err := host.Connect(cctx.Context, *certFrom); err != nil { + return err + } + client := certexchange.Client{ + Host: host, + NetworkName: gpbft.NetworkName(cctx.String(networkNameFlag.Name)), + RequestTimeout: cctx.Duration(timeoutFlag.Name), + } + + rh, ch, err := client.Request(cctx.Context, certFrom.ID, &certexchange.Request{ + FirstInstance: instance, + Limit: cctx.Uint64(limitFlag.Name), + IncludePowerTable: true, + }) + if err != nil { + return err + } + var result = struct { + *certexchange.ResponseHeader + PowerTableCID cid.Cid + Certificates []*certs.FinalityCertificate + }{ + ResponseHeader: rh, + } + + result.PowerTableCID, err = certs.MakePowerTableCID(rh.PowerTable) + if err != nil { + return err + } + + for certificate := range ch { + result.Certificates = append(result.Certificates, certificate) + } + output, err := json.MarshalIndent(result, "", " ") + if err != nil { + return err + } + _, _ = fmt.Fprintln(cctx.App.Writer, string(output)) + return nil + }, + }, + }, + } + + limitFlag = &cli.Uint64Flag{ + Name: "limit", + Usage: "Maximum number of certificates to list from the peer", + Value: 100, + } + fromAddrFlag = &cli.StringFlag{ + Name: "peer", + Aliases: []string{"p"}, + Usage: "The addrinfo of the peer to get the certificate from", + Action: func(cctx *cli.Context, v string) (err error) { + certFrom, err = peer.AddrInfoFromString(v) + return + }, + Required: true, + } + networkNameFlag = &cli.StringFlag{ + Name: "networkName", + Aliases: []string{"nn"}, + Usage: "The network name", + Required: true, + } + + includePowerTableFlag = &cli.BoolFlag{ + Name: "includePowerTable", + Aliases: []string{"pt"}, + Usage: "Whether to include the power table in the results", + } + timeoutFlag = &cli.DurationFlag{ + Name: "timeout", + Usage: "Request timeout.", + Value: 30 * time.Second, + } +) diff --git a/cmd/f3/main.go b/cmd/f3/main.go index 932b4e8f..0b5b3a64 100644 --- a/cmd/f3/main.go +++ b/cmd/f3/main.go @@ -26,6 +26,7 @@ func main() { &manifestCmd, &observerCmd, &toolsCmd, + &certsCmd, }, }