2024-04-19 05:53:45 +00:00
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
|
|
import (
|
2024-10-14 01:37:19 +00:00
|
|
|
|
"bytes"
|
|
|
|
|
"crypto/tls"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"fmt"
|
2024-04-19 05:53:45 +00:00
|
|
|
|
"os"
|
2024-10-14 01:37:19 +00:00
|
|
|
|
"strings"
|
2024-04-19 05:53:45 +00:00
|
|
|
|
|
2024-10-14 01:37:19 +00:00
|
|
|
|
"github.com/cloudflare/circl/sign/ed448"
|
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
|
|
|
|
mn "github.com/multiformats/go-multiaddr/net"
|
2024-04-19 05:53:45 +00:00
|
|
|
|
"github.com/spf13/cobra"
|
2024-10-14 01:37:19 +00:00
|
|
|
|
"golang.org/x/crypto/sha3"
|
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
2024-04-19 05:53:45 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var configDirectory string
|
2024-10-14 01:37:19 +00:00
|
|
|
|
var signatureCheck bool = true
|
|
|
|
|
var NodeConfig *config.Config
|
2024-04-19 05:53:45 +00:00
|
|
|
|
var simulateFail bool
|
2024-10-14 01:37:19 +00:00
|
|
|
|
var LightNode bool = false
|
|
|
|
|
var DryRun bool = false
|
2024-04-19 05:53:45 +00:00
|
|
|
|
|
|
|
|
|
var rootCmd = &cobra.Command{
|
|
|
|
|
Use: "qclient",
|
|
|
|
|
Short: "Quilibrium RPC Client",
|
2024-10-14 01:37:19 +00:00
|
|
|
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
|
|
|
if signatureCheck {
|
|
|
|
|
ex, err := os.Executable()
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := os.ReadFile(ex)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(
|
|
|
|
|
"Error encountered during signature check – are you running this " +
|
|
|
|
|
"from source? (use --signature-check=false)",
|
|
|
|
|
)
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checksum := sha3.Sum256(b)
|
|
|
|
|
digest, err := os.ReadFile(ex + ".dgst")
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Digest file not found")
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parts := strings.Split(string(digest), " ")
|
|
|
|
|
if len(parts) != 2 {
|
|
|
|
|
fmt.Println("Invalid digest file format")
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
digestBytes, err := hex.DecodeString(parts[1][:64])
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Invalid digest file format")
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !bytes.Equal(checksum[:], digestBytes) {
|
|
|
|
|
fmt.Println("Invalid digest for node")
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
|
|
|
|
|
|
for i := 1; i <= len(config.Signatories); i++ {
|
|
|
|
|
signatureFile := fmt.Sprintf(ex+".dgst.sig.%d", i)
|
|
|
|
|
sig, err := os.ReadFile(signatureFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pubkey, _ := hex.DecodeString(config.Signatories[i-1])
|
|
|
|
|
if !ed448.Verify(pubkey, digest, sig, "") {
|
|
|
|
|
fmt.Printf("Failed signature check for signatory #%d\n", i)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if count < len(config.Signatories)/2+len(config.Signatories)%2 {
|
|
|
|
|
fmt.Printf("Quorum on signatures not met")
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("Signature check passed")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println("Signature check bypassed, be sure you know what you're doing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, err := os.Stat(configDirectory)
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
fmt.Printf("config directory doesn't exist: %s\n", configDirectory)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 23:44:03 +00:00
|
|
|
|
NodeConfig, err = config.LoadConfig(configDirectory, "", false)
|
2024-10-14 01:37:19 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("invalid config directory: %s\n", configDirectory)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if NodeConfig.ListenGRPCMultiaddr == "" {
|
|
|
|
|
fmt.Println("gRPC not enabled, using light node")
|
|
|
|
|
LightNode = true
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-04-19 05:53:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Execute() {
|
|
|
|
|
err := rootCmd.Execute()
|
|
|
|
|
if err != nil {
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 01:37:19 +00:00
|
|
|
|
func GetGRPCClient() (*grpc.ClientConn, error) {
|
|
|
|
|
addr := "rpc.quilibrium.com:8337"
|
|
|
|
|
credentials := credentials.NewTLS(&tls.Config{InsecureSkipVerify: false})
|
|
|
|
|
if !LightNode {
|
|
|
|
|
ma, err := multiaddr.NewMultiaddr(NodeConfig.ListenGRPCMultiaddr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, addr, err = mn.DialArgs(ma)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
credentials = insecure.NewCredentials()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return grpc.Dial(
|
|
|
|
|
addr,
|
|
|
|
|
grpc.WithTransportCredentials(
|
|
|
|
|
credentials,
|
|
|
|
|
),
|
|
|
|
|
grpc.WithDefaultCallOptions(
|
|
|
|
|
grpc.MaxCallSendMsgSize(600*1024*1024),
|
|
|
|
|
grpc.MaxCallRecvMsgSize(600*1024*1024),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-19 05:53:45 +00:00
|
|
|
|
func init() {
|
|
|
|
|
rootCmd.PersistentFlags().StringVar(
|
|
|
|
|
&configDirectory,
|
|
|
|
|
"config",
|
2024-05-25 05:22:50 +00:00
|
|
|
|
".config/",
|
|
|
|
|
"config directory (default is .config/)",
|
2024-04-19 05:53:45 +00:00
|
|
|
|
)
|
2024-10-14 01:37:19 +00:00
|
|
|
|
rootCmd.PersistentFlags().BoolVar(
|
|
|
|
|
&DryRun,
|
|
|
|
|
"dry-run",
|
|
|
|
|
false,
|
|
|
|
|
"runs the command (if applicable) without actually mutating state (printing effect output)",
|
|
|
|
|
)
|
|
|
|
|
rootCmd.PersistentFlags().BoolVar(
|
|
|
|
|
&signatureCheck,
|
|
|
|
|
"signature-check",
|
|
|
|
|
true,
|
|
|
|
|
"bypass signature check (not recommended for binaries)",
|
|
|
|
|
)
|
2024-04-19 05:53:45 +00:00
|
|
|
|
}
|