From 8125acc2786cbb6087f339c0d28962e715416fdd Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 27 Oct 2025 10:37:34 +0000 Subject: [PATCH 1/4] fix: removing tssSocketPath to avoid conflict between port in the config and the flag --- node/cmd/guardiand/node.go | 6 +-- node/pkg/node/node_test.go | 2 +- node/pkg/node/options.go | 6 +-- node/pkg/tss/comm/runnable.go | 38 +++++++++++++- node/pkg/tss/comm/server_test.go | 66 +++++++++++++++++++------ node/pkg/tss/internal/cmd/dkg/server.go | 11 ++--- 6 files changed, 97 insertions(+), 32 deletions(-) diff --git a/node/cmd/guardiand/node.go b/node/cmd/guardiand/node.go index f826e2ddd3..03dab1cb35 100644 --- a/node/cmd/guardiand/node.go +++ b/node/cmd/guardiand/node.go @@ -73,8 +73,7 @@ var ( guardianKeyPath *string guardianSignerUri *string - tssSecretsPath *string - tssNetworkSocketPath *string + tssSecretsPath *string ethRPC *string ethContract *string @@ -326,7 +325,6 @@ func init() { fogoShimContract = NodeCmd.Flags().String("fogoShimContract", "", "Address of the Fogo shim program") tssSecretsPath = NodeCmd.Flags().String("tssSecret", "", "Path to guardian tss secrets (required)") - tssNetworkSocketPath = NodeCmd.Flags().String("tssNetworkPort", "[::]:8998", "Listen address for TSS server") ethRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "ethRPC", "Ethereum RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"}) ethContract = NodeCmd.Flags().String("ethContract", "", "Ethereum contract address") @@ -1919,7 +1917,7 @@ func runNode(cmd *cobra.Command, args []string) { node.GuardianOptionStatusServer(*statusAddr), node.GuardianOptionAlternatePublisher(guardianAddrAsBytes, *additionalPublishers), node.GuardianOptionProcessor(*p2pNetworkID), - node.GuardianOptionTSSNetwork(*tssNetworkSocketPath), + node.GuardianOptionTSSNetwork(), // Keep this last so that all of its dependencies are met. node.GuardianOptionP2P( diff --git a/node/pkg/node/node_test.go b/node/pkg/node/node_test.go index 7a1fad3e2e..0dd400e922 100644 --- a/node/pkg/node/node_test.go +++ b/node/pkg/node/node_test.go @@ -267,7 +267,7 @@ func mockGuardianRunnable(t testing.TB, gs []*mockGuardian, mockGuardianIndex ui GuardianOptionAlternatePublisher([]byte{}, []string{}), // disable alternate publisher GuardianOptionProcessor(networkID), - GuardianOptionTSSNetwork(fmt.Sprintf("[::]:%d", cfg.tssNetworkPort)), + GuardianOptionTSSNetwork(), // Keep this last so that all of its dependencies are met. GuardianOptionP2P(gs[mockGuardianIndex].p2pKey, networkID, bootstrapPeers, nodeName, informOnNewVAAs, false, cfg.p2pPort, "", 0, "", "", false, []string{}, []string{}, []string{}), diff --git a/node/pkg/node/options.go b/node/pkg/node/options.go index e73c1dbb09..6d908f4eb9 100644 --- a/node/pkg/node/options.go +++ b/node/pkg/node/options.go @@ -662,15 +662,13 @@ func GuardianOptionProcessor(networkId string) *GuardianOption { }} } -func GuardianOptionTSSNetwork( - socketPath string, -) *GuardianOption { +func GuardianOptionTSSNetwork() *GuardianOption { serviceName := "tsscomm" return &GuardianOption{ name: serviceName, dependencies: []string{"processor"}, // TODO: I think it is dependant on it, since the TSS passes its signatures to the processor. f: func(_ context.Context, logger *zap.Logger, g *G) error { - srvr, err := tsscomm.NewServer(socketPath, logger.Named(serviceName), g.tssEngine) + srvr, err := tsscomm.NewServer(logger.Named(serviceName), g.tssEngine) if err != nil { return fmt.Errorf("failed to create tsscomm server: %w", err) } diff --git a/node/pkg/tss/comm/runnable.go b/node/pkg/tss/comm/runnable.go index f26aae1393..17dd297624 100644 --- a/node/pkg/tss/comm/runnable.go +++ b/node/pkg/tss/comm/runnable.go @@ -4,8 +4,10 @@ import ( "context" "crypto/tls" "crypto/x509" + "errors" "fmt" "net" + "strconv" tsscommv1 "github.com/certusone/wormhole/node/pkg/proto/tsscomm/v1" "github.com/certusone/wormhole/node/pkg/tss" @@ -27,7 +29,41 @@ type DirectLink interface { WaitForConnections(ctx context.Context) error } -func NewServer(socketPath string, logger *zap.Logger, tssMessenger tss.ReliableMessenger) (DirectLink, error) { +func NewServer(logger *zap.Logger, tssMessenger tss.ReliableMessenger) (DirectLink, error) { + cert := tssMessenger.GetCertificate() + if cert == nil { + return nil, errors.New("tssMessenger returned nil certificate") + } + + selfID, err := tssMessenger.FetchIdentity(cert.Leaf) + if err != nil { + return nil, fmt.Errorf("failed to fetch self identity from tssMessenger: %w", err) + } + + port := selfID.Port + if port == 0 { + p, err := strconv.Atoi(tss.DefaultPort) + if err != nil { + return nil, fmt.Errorf("failed to parse default port: %w", err) + } + + port = p + } + + return newServer(fmt.Sprintf("[::]:%d", port), logger, tssMessenger) +} + +func newServer(socketPath string, logger *zap.Logger, tssMessenger tss.ReliableMessenger) (DirectLink, error) { + if socketPath == "" { + return nil, errors.New("can't create DirectLink server: socketPath is empty") + } + if logger == nil { + return nil, errors.New("can't create DirectLink server: logger is nil") + } + if tssMessenger == nil { + return nil, errors.New("can't create DirectLink server: tssMessenger is nil") + } + peers := tssMessenger.GetPeers() partyIds := make([]*tss.Identity, len(peers)) peerToCert := make(map[string]*x509.Certificate, len(peers)) diff --git a/node/pkg/tss/comm/server_test.go b/node/pkg/tss/comm/server_test.go index c4945f9fd5..58cf7a077a 100644 --- a/node/pkg/tss/comm/server_test.go +++ b/node/pkg/tss/comm/server_test.go @@ -50,6 +50,7 @@ func (m *mockTssMessageHandler) FetchIdentity(*x509.Certificate) (*tss.Identity, func (m *mockTssMessageHandler) ProducedOutputMessages() <-chan tss.Sendable { return m.chn } + func (m *mockTssMessageHandler) HandleIncomingTssMessage(msg tss.Incoming) { fmt.Println("received message from", msg.GetSource()) } @@ -85,7 +86,7 @@ func TestTLSConnectAndRedial(t *testing.T) { en, err := _loadGuardians(2) a.NoError(err) - tmpSrvr, err := NewServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ + tmpSrvr, err := newServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: en[0].GetCertificate(), // connect to no one. @@ -117,7 +118,7 @@ func TestTLSConnectAndRedial(t *testing.T) { a.NoError(err) msgChan := make(chan tss.Sendable) - srvr, err := NewServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ + srvr, err := newServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ chn: msgChan, selfCert: en[1].GetCertificate(), peersToConnectTo: []*x509.Certificate{serverCert}, // will ask to fetch each peer (and return the below peerId) @@ -167,7 +168,7 @@ func TestRelentlessReconnections(t *testing.T) { a.NoError(err) msgChan := make(chan tss.Sendable) - srvr, err := NewServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ + srvr, err := newServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ chn: msgChan, selfCert: en[1].GetCertificate(), peersToConnectTo: []*x509.Certificate{serverCert}, // will ask to fetch each peer (and return the below peerId) @@ -184,7 +185,7 @@ func TestRelentlessReconnections(t *testing.T) { // setting up server dailer and sender srv.run() - tmpSrvr, err := NewServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ + tmpSrvr, err := newServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: en[0].GetCertificate(), // connect to no one. @@ -259,7 +260,7 @@ func TestNonBlockedBroadcast(t *testing.T) { donechns := make([]chan struct{}, 2) // set servers up. for i := 0; i < 2; i++ { - tmpSrvr, err := NewServer(workingServers[i], supervisor.Logger(ctx), &mockTssMessageHandler{ + tmpSrvr, err := newServer(workingServers[i], supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: en[i].GetCertificate(), peersToConnectTo: en[0].GetPeers(), // Give the peer a certificate. @@ -309,7 +310,7 @@ func TestNonBlockedBroadcast(t *testing.T) { en[2].GuardianStorage.SetInnerFields() msgChan := make(chan tss.Sendable) - srvr, err := NewServer("localhost:5930", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ + srvr, err := newServer("localhost:5930", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ ReliableMessenger: en[2], chn: msgChan, }) @@ -529,7 +530,7 @@ func TestNotAcceptNonCAs(t *testing.T) { defer cancel() ctx = testutils.MakeSupervisorContext(ctx) - tmp, err := NewServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ + tmp, err := newServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: en[0].GetCertificate(), // connect to no one. @@ -620,7 +621,7 @@ func TestDialWithDefaultPort(t *testing.T) { listenerServerPath := "localhost:" + tss.DefaultPort // set up server that only listent and aren't able to connect to anyone. - listenerServer, err := NewServer(listenerServerPath, supervisor.Logger(ctx), &mockTssMessageHandler{ + listenerServer, err := newServer(listenerServerPath, supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: listenerEngine.GetCertificate(), // the listening server will expect this cert to connect with. @@ -665,7 +666,7 @@ func TestDialWithDefaultPort(t *testing.T) { a.NoError(communicatingEngine.GuardianStorage.SetInnerFields()) msgChan := make(chan tss.Sendable) - communicator, err := NewServer("localhost:5930", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ + communicator, err := newServer("localhost:5930", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ ReliableMessenger: communicatingEngine, chn: msgChan, }) @@ -750,7 +751,7 @@ func TestDialWithDefaultPortDeliverCorrectSrc(t *testing.T) { senderEngine.GuardianStorage.SetInnerFields() incomingDataChan := make(chan tss.Incoming) - listenerServer, err := NewServer(streamReceiverPath, supervisor.Logger(ctx), + listenerServer, err := newServer(streamReceiverPath, supervisor.Logger(ctx), &mockJustHandleIncomingMessage{ ReliableMessenger: streamReceiverEngine, receivedData: incomingDataChan, @@ -772,7 +773,7 @@ func TestDialWithDefaultPortDeliverCorrectSrc(t *testing.T) { go gserver.Serve(l) msgChan := make(chan tss.Sendable) - sender, err := NewServer("nonsensePort", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ + sender, err := newServer("nonsensePort", supervisor.Logger(ctx), &tssMockJustForMessageGeneration{ ReliableMessenger: senderEngine, chn: msgChan, }) @@ -844,7 +845,7 @@ func TestConnectingToServers(t *testing.T) { e.GuardianStorage.SetInnerFields() e.Start(ctx) - s, err := NewServer(e.GuardianStorage.Self.NetworkName(), supervisor.Logger(ctx), &mockProduceOutputMessages{ + s, err := newServer(e.GuardianStorage.Self.NetworkName(), supervisor.Logger(ctx), &mockProduceOutputMessages{ mockJustHandleIncomingMessage: mockJustHandleIncomingMessage{ ReliableMessenger: e, receivedData: incomingMsgChn[i], @@ -891,7 +892,7 @@ func TestDetectConnectionsDone(t *testing.T) { en, err := _loadGuardians(2) a.NoError(err) - tmpSrvr, err := NewServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ + tmpSrvr, err := newServer(workingServerSock, supervisor.Logger(ctx), &mockTssMessageHandler{ chn: nil, selfCert: en[0].GetCertificate(), // connect to no one. @@ -923,7 +924,7 @@ func TestDetectConnectionsDone(t *testing.T) { a.NoError(err) msgChan := make(chan tss.Sendable) - srvr, err := NewServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ + srvr, err := newServer("localhost:5930", supervisor.Logger(ctx), &mockTssMessageHandler{ chn: msgChan, selfCert: en[1].GetCertificate(), peersToConnectTo: []*x509.Certificate{serverCert}, // will ask to fetch each peer (and return the below peerId) @@ -961,3 +962,40 @@ func TestDetectConnectionsDone(t *testing.T) { case <-tstServer.done: } } + +func TestSocketPathCreation(t *testing.T) { + a := require.New(t) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + ctx = testutils.MakeSupervisorContext(ctx) + + en, err := _loadGuardians(2) + a.NoError(err) + + en[0].Self.Port = 1233456 + en[0].GuardianStorage.Identities[en[0].Self.CommunicationIndex].Port = 1233456 + + tmpSrvr, err := NewServer(supervisor.Logger(ctx), en[0]) + a.NoError(err) + + a.Equal(fmt.Sprintf("[::]:%d", en[0].Self.Port), tmpSrvr.(*server).socketPath) + + // now checking correct behavior when port is 0 + en[1].Self.Port = 0 + en[1].GuardianStorage.Identities[en[1].Self.CommunicationIndex].Port = 0 + tmpSrvr2, err := NewServer(supervisor.Logger(ctx), en[1]) + a.NoError(err) + a.Equal(fmt.Sprintf("[::]:%s", tss.DefaultPort), tmpSrvr2.(*server).socketPath) + + // For coverage completness we Invoke Run and close the server. + + go tmpSrvr2.Run(ctx) + time.Sleep(time.Second * 1) + + cancel() + select { + case <-ctx.Done(): + case <-time.After(time.Second * 2): + t.Fatal("server run did not stop after context cancel") + } +} diff --git a/node/pkg/tss/internal/cmd/dkg/server.go b/node/pkg/tss/internal/cmd/dkg/server.go index 2fa4aceb9d..c4c47a1b62 100644 --- a/node/pkg/tss/internal/cmd/dkg/server.go +++ b/node/pkg/tss/internal/cmd/dkg/server.go @@ -42,7 +42,7 @@ func main() { keygen.Start(ctx) logger.Info("Setting up server...") - srvr := createServer(gst, keygen) + srvr := createServer(keygen) go func() { if err := srvr.Run(ctx); err != nil { logger.Fatal("Server stopped", zap.Error(err)) @@ -149,13 +149,8 @@ func run(ctx context.Context, keygen engine.KeyGenerator, gst *engine.GuardianSt logger.Fatal("failed to complete DKG after 10 attempts, please check the logs for more details") } -func createServer(gst *engine.GuardianStorage, keygen engine.KeyGenerator) comm.DirectLink { - socketpath := "[::]:" + strconv.Itoa(gst.Self.Port) - if gst.Self.Port == 0 { - socketpath = "[::]:" + engine.DefaultPort - } - - srvr, err := comm.NewServer(socketpath, logger, keygen) +func createServer(keygen engine.KeyGenerator) comm.DirectLink { + srvr, err := comm.NewServer(logger, keygen) if err != nil { logger.Fatal("failed to create a new server", zap.Error(err)) } From 999034dd6bac5372aec15b6fce7948b75c16b4d0 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 27 Oct 2025 13:48:33 +0000 Subject: [PATCH 2/4] script to test dkg --- node/pkg/tss/internal/cmd/scripts_test.go | 193 +++++++++++++++++++--- 1 file changed, 172 insertions(+), 21 deletions(-) diff --git a/node/pkg/tss/internal/cmd/scripts_test.go b/node/pkg/tss/internal/cmd/scripts_test.go index d71881b2f7..24795201ed 100644 --- a/node/pkg/tss/internal/cmd/scripts_test.go +++ b/node/pkg/tss/internal/cmd/scripts_test.go @@ -13,7 +13,9 @@ import ( "os" "os/exec" "path" + "path/filepath" "runtime" + "strconv" "strings" "testing" "time" @@ -54,18 +56,57 @@ var hostnames = []string{ const saveFile = "./lkg/lkg.json" const specificKeysFolder = "5-servers" -type LKGConfig SetupConfigs +var prepareForLocalDKG = false + +type dkgTest struct { + hostnames []string + saveFolder string + + forLocalDKG bool + storeIntoInternalTestData bool +} + +func getCurrentFilePath(t *testing.T) string { + _, filename, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("Unable to get the current test file path") + } + + // The path returned by runtime.Caller might be relative. + // We use filepath.Abs to ensure we get the absolute path. + absPath, err := filepath.Abs(filename) + if err != nil { + t.Fatalf("Unable to get the absolute path: %v", err) + } + + // remove the filename to get the directory + return filepath.Dir(absPath) +} func TestMain(t *testing.T) { t.Skip("skipping main test, use specific tests instead") - t.Run("CreateLKGConfigs", createLKGConfigs) + tt := dkgTest{ + hostnames: hostnames, + saveFolder: path.Join("dkg"), + forLocalDKG: true, + } + t.Run("CreateDKGConfigs", tt.createDKGConfigs) - t.Run("shoveKeysToPosition", shoveKeys) + //get file location: + + tt = dkgTest{ + hostnames: hostnames, + saveFolder: path.Join(getCurrentFilePath(t), "dkg"), // workingdir + forLocalDKG: true, + storeIntoInternalTestData: true, + } + t.Run("RunDKG", tt.RunDKG) + // t.Run("shoveKeysToPosition", shoveKeys) - t.Run("storeGuardiansForTest", storeTestGuardians) + // t.Run("storeGuardiansForTest", storeTestGuardians) - t.Run("scpSecretsToServers", sendToServers) + // t.Run("scpSecretsToServers", sendToServers) } func storeTestGuardians(t *testing.T) { @@ -201,12 +242,12 @@ func sendToServers(t *testing.T) { fmt.Println("done sending files") } -func loadConfigs(t *testing.T) LKGConfig { +func loadConfigs(t *testing.T) SetupConfigs { bts, err := os.ReadFile(saveFile) if err != nil { t.Fatalf("failed to read file: %v", err) } - var cnfg LKGConfig + var cnfg SetupConfigs if err := json.Unmarshal(bts, &cnfg); err != nil { t.Fatalf("failed to unmarshal config: %v", err) } @@ -263,14 +304,10 @@ func shoveKeys(t *testing.T) { // }) } -func createLKGConfigs(t *testing.T) { - if _, err := os.Stat(saveFile); err == nil { - t.Fatalf("lkg.json already exists in lkg dir") - } else if !os.IsNotExist(err) { - t.Fatalf("unexpected error: %v", err) - } +func (d dkgTest) createDKGConfigs(t *testing.T) { + hostnames := d.hostnames - cnfg := LKGConfig{ + mainCnf := SetupConfigs{ NumParticipants: len(hostnames), WantedThreshold: 2*(len(hostnames)/3) + 1, Peers: make([]Identifier, len(hostnames)), @@ -279,22 +316,136 @@ func createLKGConfigs(t *testing.T) { } for i, hostname := range hostnames { + port := 8998 + if d.forLocalDKG { + port += i + hostname = "localhost" + mainCnf.SaveLocation[i] = fmt.Sprintf("guardian%d", i) + } sk, cert := createTLSCert(hostname) - cnfg.Peers[i] = Identifier{ + mainCnf.Peers[i] = Identifier{ Hostname: hostname, TlsX509: cert, + Port: port, } - cnfg.SaveLocation[i] = extractRegion(hostname) - cnfg.Secrets[i] = internal.PrivateKeyToPem(sk) + + mainCnf.Secrets[i] = internal.PrivateKeyToPem(sk) } - bts, err := json.MarshalIndent(cnfg, "", " ") + for i := range hostnames { + output := fmt.Sprintf("guardian%d", i) + cnfg := SetupConfigs{ + NumParticipants: mainCnf.NumParticipants, + WantedThreshold: mainCnf.WantedThreshold, + Self: mainCnf.Peers[i], + SelfSecret: mainCnf.Secrets[i], + StorageLocation: output, + Peers: mainCnf.Peers, + } + + bts, err := json.MarshalIndent(cnfg, "", " ") + if err != nil { + t.Fatalf("failed to marshal config: %v", err) + } + + if err := os.MkdirAll(d.saveFolder, 0777); err != nil { + t.Fatalf("failed to create directory: %v", err) + } + + savepath := path.Join(d.saveFolder, strconv.Itoa(i)+".json") + if err := os.WriteFile(savepath, bts, 0644); err != nil { + t.Fatalf("failed to write file: %v", err) + } + } +} + +func (d dkgTest) RunDKG(t *testing.T) { + errs := make(chan error, len(d.hostnames)) + + initialWd, err := os.Getwd() if err != nil { - t.Fatalf("failed to marshal config: %v", err) + t.Fatalf("failed to get working directory: %v", err) + } + defer func() { + if err := os.Chdir(initialWd); err != nil { + t.Fatalf("failed to restore working directory: %v", err) + } + }() + + if err := os.Chdir(d.saveFolder); err != nil { + t.Fatalf("failed to change working directory: %v", err) } - if err := os.WriteFile(saveFile, bts, 0644); err != nil { - t.Fatalf("failed to write file: %v", err) + for i := range d.hostnames { + serverPath := "server.go" + configPath := strconv.Itoa(i) + ".json" + // call go run ./dkg --config= + + args := []string{ + "run", + serverPath, + "-cnfg", configPath, + } + + // in parallel + cmd := exec.Command("go", args...) + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Start(); err != nil { + t.Fatalf("failed to start command: %v", err) + } + + fmt.Println("running command:", cmd.String()) + + go func(cmd *exec.Cmd, index int) { + // Wait for command to finish and send error (if any) back to the main goroutine. + if err := cmd.Wait(); err != nil { + errs <- fmt.Errorf("command %d failed: %v", index, err) + return + } + errs <- nil + }(cmd, i) + } + + fmt.Println("all commands started, waiting for results...") + time.Sleep(time.Second) + // collect results and fail from the test goroutine if any command failed + for i := 0; i < len(d.hostnames); i++ { + if err := <-errs; err != nil { + t.Fatalf("failed running dkg: %v", err) + } + } + + if !d.storeIntoInternalTestData { + return + } + // store the guardians into internal/testutils/testdata/dkg5 + mainFolder := "tss5" + resultDir := path.Join("..", "..", "..", "..", "internal", "testutils", "testdata", mainFolder) + cleanResultFolder(t, resultDir) + + for i := range d.hostnames { + saveLocation := fmt.Sprintf("guardian%d", i) + _path := path.Join(d.saveFolder, saveLocation, "secrets.json") + + //read the file into a GuardianStorage struct + gst, err := engine.NewGuardianStorageFromFile(_path) + if err != nil { + t.Fatalf("failed to read guardian storage from file: %v", err) + } + + // store into result dir: + filename := fmt.Sprintf("guardian%d.json", i) + filepath := path.Join(resultDir, filename) + bts, err := json.MarshalIndent(gst, "", " ") + if err != nil { + t.Fatalf("failed to marshal guardian storage: %v", err) + } + if err := os.WriteFile(filepath, bts, 0644); err != nil { + t.Fatalf("failed to write guardian storage to file: %v", err) + } } } From dbad25dfc845f8ff8d1d566bedba45a95ff27994 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 27 Oct 2025 14:43:12 +0000 Subject: [PATCH 3/4] improv generation of lkg/dkg on localhost for testing --- .../internal/cmd/lkg/local_key_generation.go | 33 +++- node/pkg/tss/internal/cmd/scripts_test.go | 155 +++++------------- 2 files changed, 69 insertions(+), 119 deletions(-) diff --git a/node/pkg/tss/internal/cmd/lkg/local_key_generation.go b/node/pkg/tss/internal/cmd/lkg/local_key_generation.go index 0137e63a1c..6db5a6514e 100644 --- a/node/pkg/tss/internal/cmd/lkg/local_key_generation.go +++ b/node/pkg/tss/internal/cmd/lkg/local_key_generation.go @@ -21,9 +21,10 @@ import ( "github.com/xlabs/multi-party-sig/pkg/math/sample" "github.com/xlabs/multi-party-sig/pkg/party" "github.com/xlabs/multi-party-sig/protocols/frost" + "github.com/xlabs/multi-party-sig/protocols/frost/sign" ) -var cnfgPath = flag.String("cnfg", "", "path to config file in json format used to run the protocol") +var cnfgPath = flag.String("cnfg", "/workspaces/wormhole/node/pkg/tss/internal/cmd/lkg/lkg.json", "path to config file in json format used to run the protocol") func main() { flag.Parse() @@ -62,7 +63,8 @@ type dkgPlayer struct { self *engine.Identity ids engine.IdentitiesKeep - selfCert []byte + selfCert []byte + certKeyPEM []byte // same for all guardians // generated here. loadDistributionKey []byte @@ -90,9 +92,8 @@ func Run(cnfg *cmd.SetupConfigs) { // this function simulates the results of running a DKG protocol. func simulateDKG(all []*dkgPlayer, threshold int) { group := curve.Secp256k1{} - secret := sample.Scalar(rand.Reader, group) - f := polynomial.NewPolynomial(group, threshold, secret) - publicKey := secret.ActOnBase() + + publicKey, f := makefrostKey(group, threshold) privateShares := make(map[party.ID]curve.Scalar, len(all)) for _, p := range all { @@ -135,7 +136,7 @@ func simulateDKG(all []*dkgPlayer, threshold int) { Configurations: engine.Configurations{}, Self: p.self, TlsX509: p.selfCert, - PrivateKey: nil, // each guardian stores this by themselves. + PrivateKey: p.certKeyPEM, IdentitiesKeep: p.ids, Threshold: threshold, // SavedSecretParameters: , @@ -156,19 +157,32 @@ func simulateDKG(all []*dkgPlayer, threshold int) { panic("") } - if err := os.MkdirAll(all[i].whereToStore, 0600); err != nil { + if err := os.MkdirAll(all[i].whereToStore, 0700); err != nil { panic("Failed to create directory: " + err.Error()) } fname := path.Join(all[i].whereToStore, "secrets.json") - if err := os.WriteFile(fname, bts, 0777); err != nil { + if err := os.WriteFile(fname, bts, 0600); err != nil { panic("Failed to write to disk: " + err.Error()) } } } +func makefrostKey(group curve.Secp256k1, threshold int) (curve.Point, *polynomial.Polynomial) { + for range 128 { + secret := sample.Scalar(rand.Reader, group) + f := polynomial.NewPolynomial(group, threshold, secret) + publicKey := secret.ActOnBase() + if sign.PublicKeyValidForContract(publicKey) { + return publicKey, f + } + } + + panic("could not generate a valid frost key after 128 attempts") +} + func setupPlayers(cnfg *cmd.SetupConfigs) ([]*dkgPlayer, error) { if err := cnfg.Validate(); err != nil { return nil, err @@ -203,12 +217,13 @@ func setupPlayers(cnfg *cmd.SetupConfigs) ([]*dkgPlayer, error) { // peerContext := tss.NewPeerContext(sortedPids) - gspecific := mp[string(id.Pid.GetID())] + gspecific := mp[string(id.KeyPEM)] p := &dkgPlayer{ self: id, whereToStore: cnfg.SaveLocation[index], selfCert: gspecific.TlsX509, + certKeyPEM: cnfg.Secrets[index], loadDistributionKey: tmp, ids: engine.IdentitiesKeep{ diff --git a/node/pkg/tss/internal/cmd/scripts_test.go b/node/pkg/tss/internal/cmd/scripts_test.go index 24795201ed..9c87467db6 100644 --- a/node/pkg/tss/internal/cmd/scripts_test.go +++ b/node/pkg/tss/internal/cmd/scripts_test.go @@ -93,63 +93,27 @@ func TestMain(t *testing.T) { } t.Run("CreateDKGConfigs", tt.createDKGConfigs) - //get file location: - tt = dkgTest{ - hostnames: hostnames, + hostnames: hostnames, + // for ease of debug, not using full path. saveFolder: path.Join(getCurrentFilePath(t), "dkg"), // workingdir forLocalDKG: true, storeIntoInternalTestData: true, } t.Run("RunDKG", tt.RunDKG) - // t.Run("shoveKeysToPosition", shoveKeys) - // t.Run("storeGuardiansForTest", storeTestGuardians) + tt = dkgTest{ + hostnames: hostnames, + // for ease of debug, not using full path. + saveFolder: path.Join(getCurrentFilePath(t), "lkg"), // workingdir + forLocalDKG: false, + storeIntoInternalTestData: false, + } + t.Run("CreateLKGConfigs", tt.createLKGConfigs) // t.Run("scpSecretsToServers", sendToServers) } -func storeTestGuardians(t *testing.T) { - cnfg := loadConfigs(t) - - mainFolder := "tss5" - resultDir := path.Join("..", "..", "..", "internal", "testutils", "testdata", mainFolder) - cleanResultFolder(t, resultDir) - - // if err := os.MkdirAll(_path, 0755); err != nil { - // t.Fatalf("failed to create directory: %v", err) - // } - for i := range cnfg.Peers { - // guardian := cnfg.Peers[i] - saveLocation := cnfg.SaveLocation[i] - if saveLocation == "" { - t.Fatalf("guardian %d has empty WhereToSaveSecrets", i) - } - - _path := path.Join("setkey", "keys", specificKeysFolder, saveLocation) - lkgpath := path.Join(_path, "secrets.json") - - //read the file into a GuardianStorage struct - gst, err := engine.NewGuardianStorageFromFile(lkgpath) - if err != nil { - t.Fatalf("failed to read guardian storage from file: %v", err) - } - - fileIndex := gst.Self.CommunicationIndex - fmt.Println("guardian index:", fileIndex) - - bts, err := json.MarshalIndent(gst, "", " ") - if err != nil { - t.Fatalf("failed to marshal guardian storage: %v", err) - } - guardianFileName := fmt.Sprintf("guardian%d.json", fileIndex) - guardianFilePath := path.Join(resultDir, guardianFileName) - if err := os.WriteFile(guardianFilePath, bts, 0644); err != nil { - t.Fatalf("failed to write guardian storage to file: %v", err) - } - } -} - func cleanResultFolder(t *testing.T, resultDir string) { // make sure the directory exists and EMPTY if err := os.MkdirAll(resultDir, 0755); err != nil { @@ -254,57 +218,51 @@ func loadConfigs(t *testing.T) SetupConfigs { return cnfg } -func shoveKeys(t *testing.T) { - cnfg := loadConfigs(t) - // TODO - // var secretkeypath = flag.String("key", "", "path to the secret key PEM file") - // var lkgSecrets = flag.String("lkg", "", "path to the LKG secrets json file") +func (d dkgTest) createLKGConfigs(t *testing.T) { + cnfg := d.createLKG(t) - for i := range cnfg.Peers { + // store + bts, err := json.MarshalIndent(cnfg, "", " ") + if err != nil { + t.Fatalf("failed to marshal config: %v", err) + } - saveLocation := cnfg.SaveLocation[i] - if saveLocation == "" { - t.Fatalf("guardian %d has empty WhereToSaveSecrets", i) - } + if err := os.WriteFile(path.Join(d.saveFolder, "lkg.json"), bts, 0644); err != nil { + t.Fatalf("failed to write file: %v", err) + } +} - _path := path.Join(".", "setkey", "keys", specificKeysFolder, saveLocation) +func (d dkgTest) createDKGConfigs(t *testing.T) { + mainCnf := d.createLKG(t) - secretKey := cnfg.Secrets[i] - keypath := path.Join(_path, "key.pem") - if err := os.WriteFile( - keypath, - secretKey, - 0644, - ); err != nil { - t.Fatalf("failed to write file: %v", err) + for i := range d.hostnames { + output := fmt.Sprintf("guardian%d", i) + cnfg := SetupConfigs{ + NumParticipants: mainCnf.NumParticipants, + WantedThreshold: mainCnf.WantedThreshold, + Self: mainCnf.Peers[i], + SelfSecret: mainCnf.Secrets[i], + StorageLocation: output, + Peers: mainCnf.Peers, } - lkgpath := path.Join(_path, "secrets.json") - - args := []string{ - "run", "./setkey", - "--key=" + keypath, - "--lkg=" + lkgpath, + bts, err := json.MarshalIndent(cnfg, "", " ") + if err != nil { + t.Fatalf("failed to marshal config: %v", err) } - cmd := exec.Command("go", args...) - - // Link the binary's stdout/stderr to your Go program's output - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + if err := os.MkdirAll(d.saveFolder, 0777); err != nil { + t.Fatalf("failed to create directory: %v", err) + } - if err := cmd.Run(); err != nil { - t.Fatalf("failed to run command: %v", err) + savepath := path.Join(d.saveFolder, strconv.Itoa(i)+".json") + if err := os.WriteFile(savepath, bts, 0644); err != nil { + t.Fatalf("failed to write file: %v", err) } } - - // setkey.Main([]string{ - // "-key", "../lkg/lkg.json", - // "-lkg", saveFile, - // }) } -func (d dkgTest) createDKGConfigs(t *testing.T) { +func (d dkgTest) createLKG(t *testing.T) SetupConfigs { hostnames := d.hostnames mainCnf := SetupConfigs{ @@ -321,6 +279,8 @@ func (d dkgTest) createDKGConfigs(t *testing.T) { port += i hostname = "localhost" mainCnf.SaveLocation[i] = fmt.Sprintf("guardian%d", i) + } else { + mainCnf.SaveLocation[i] = extractRegion(hostname) } sk, cert := createTLSCert(hostname) mainCnf.Peers[i] = Identifier{ @@ -331,32 +291,7 @@ func (d dkgTest) createDKGConfigs(t *testing.T) { mainCnf.Secrets[i] = internal.PrivateKeyToPem(sk) } - - for i := range hostnames { - output := fmt.Sprintf("guardian%d", i) - cnfg := SetupConfigs{ - NumParticipants: mainCnf.NumParticipants, - WantedThreshold: mainCnf.WantedThreshold, - Self: mainCnf.Peers[i], - SelfSecret: mainCnf.Secrets[i], - StorageLocation: output, - Peers: mainCnf.Peers, - } - - bts, err := json.MarshalIndent(cnfg, "", " ") - if err != nil { - t.Fatalf("failed to marshal config: %v", err) - } - - if err := os.MkdirAll(d.saveFolder, 0777); err != nil { - t.Fatalf("failed to create directory: %v", err) - } - - savepath := path.Join(d.saveFolder, strconv.Itoa(i)+".json") - if err := os.WriteFile(savepath, bts, 0644); err != nil { - t.Fatalf("failed to write file: %v", err) - } - } + return mainCnf } func (d dkgTest) RunDKG(t *testing.T) { From 724252baf2fc7ab3046284f0a6dfe22cb8f11e70 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Tue, 28 Oct 2025 07:38:31 +0000 Subject: [PATCH 4/4] removed cnfgPath from LKG.go --- node/pkg/tss/internal/cmd/lkg/local_key_generation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/pkg/tss/internal/cmd/lkg/local_key_generation.go b/node/pkg/tss/internal/cmd/lkg/local_key_generation.go index 6db5a6514e..76e4b4d08e 100644 --- a/node/pkg/tss/internal/cmd/lkg/local_key_generation.go +++ b/node/pkg/tss/internal/cmd/lkg/local_key_generation.go @@ -24,7 +24,7 @@ import ( "github.com/xlabs/multi-party-sig/protocols/frost/sign" ) -var cnfgPath = flag.String("cnfg", "/workspaces/wormhole/node/pkg/tss/internal/cmd/lkg/lkg.json", "path to config file in json format used to run the protocol") +var cnfgPath = flag.String("cnfg", "", "path to config file in json format used to run the protocol") func main() { flag.Parse()