Skip to content
Open
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
5 changes: 3 additions & 2 deletions cmd/mpcium/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,13 @@ func runNode(ctx context.Context, c *cli.Command) error {
timeoutConsumer := eventconsumer.NewTimeOutConsumer(
natsConn,
singingResultQueue,
identityStore,
)

timeoutConsumer.Run()
defer timeoutConsumer.Close()
keygenConsumer := eventconsumer.NewKeygenConsumer(natsConn, keygenBroker, pubsub, peerRegistry, genKeyResultQueue)
signingConsumer := eventconsumer.NewSigningConsumer(natsConn, signingBroker, pubsub, peerRegistry, singingResultQueue)
keygenConsumer := eventconsumer.NewKeygenConsumer(natsConn, keygenBroker, pubsub, peerRegistry, genKeyResultQueue, identityStore)
signingConsumer := eventconsumer.NewSigningConsumer(natsConn, signingBroker, pubsub, peerRegistry, singingResultQueue, identityStore)

// Make the node ready before starting the signing consumer
if err := peerRegistry.Ready(); err != nil {
Expand Down
34 changes: 32 additions & 2 deletions e2e/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"testing"
"time"
Expand Down Expand Up @@ -59,6 +60,9 @@ type E2ETestSuite struct {
signingResults map[string]*event.SigningResultEvent
resharingResults map[string]*event.ResharingResultEvent
config TestConfig

resultErrorsMu sync.Mutex
resultErrors []string
}

func NewE2ETestSuite(testDir string) *E2ETestSuite {
Expand Down Expand Up @@ -193,9 +197,18 @@ func (s *E2ETestSuite) SetupMPCClient(t *testing.T) {
t.Fatalf("Failed to create local signer: %v", err)
}

// Verify node-signed result events using the identity files generated by
// setup_test_identities.sh (distributed to every test node's identity dir).
nodeKeyLookup, err := client.NewNodeKeyLookup(filepath.Join(s.testDir, "test_node0", "identity"))
if err != nil {
t.Fatalf("Failed to create node key lookup: %v", err)
}

mpcClient := client.NewMPCClient(client.Options{
NatsConn: s.natsConn,
Signer: localSigner,
NatsConn: s.natsConn,
Signer: localSigner,
NodeKeyLookup: nodeKeyLookup,
RequiredNodeSignatures: s.config.MPCThreshold + 1,
})
s.mpcClient = mpcClient
t.Log("MPC client created")
Expand Down Expand Up @@ -670,3 +683,20 @@ func (s *E2ETestSuite) CleanupTestEnvironment(t *testing.T) {

t.Log("Test environment cleanup completed")
}

// recordResultError is safe to call from result callbacks that may fire after the subtest that registered them has ended.
func (s *E2ETestSuite) recordResultError(format string, args ...any) {
s.resultErrorsMu.Lock()
defer s.resultErrorsMu.Unlock()
s.resultErrors = append(s.resultErrors, fmt.Sprintf(format, args...))
}

func (s *E2ETestSuite) AssertNoResultErrors(t *testing.T) {
// Wait out the client's result aggregation window so late insufficient-signature errors are caught.
time.Sleep(16 * time.Second)
s.resultErrorsMu.Lock()
defer s.resultErrorsMu.Unlock()
for _, msg := range s.resultErrors {
t.Errorf("error result received: %s", msg)
}
}
6 changes: 3 additions & 3 deletions e2e/go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
module github.com/fystack/mpcium/e2e

go 1.23.0
go 1.23.8

require (
github.com/dgraph-io/badger/v4 v4.7.0
github.com/fystack/mpcium v0.0.0-00010101000000-000000000000
github.com/google/uuid v1.6.0
github.com/hashicorp/consul/api v1.26.1
github.com/hashicorp/consul/api v1.32.1
github.com/nats-io/nats.go v1.31.0
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -91,7 +91,7 @@ require (
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.31.0 // indirect
Expand Down
12 changes: 6 additions & 6 deletions e2e/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=
github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
github.com/hashicorp/consul/api v1.32.1 h1:0+osr/3t/aZNAdJX558crU3PEjVrG4x6715aZHRgceE=
github.com/hashicorp/consul/api v1.32.1/go.mod h1:mXUWLnxftwTmDv4W3lzxYCPD199iNLLUyLfLGFJbtl4=
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -402,8 +402,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
Expand Down
3 changes: 2 additions & 1 deletion e2e/keygen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func TestKeyGeneration(t *testing.T) {

// Ensure cleanup happens even if test fails
defer func() {
suite.AssertNoResultErrors(t)
t.Log("Performing post-test cleanup...")
suite.Cleanup(t)
}()
Expand Down Expand Up @@ -92,7 +93,7 @@ func testKeyGeneration(t *testing.T, suite *E2ETestSuite) {
suite.keygenResults[result.WalletID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Keygen succeeded for wallet %s", result.WalletID)
}
Expand Down
9 changes: 5 additions & 4 deletions e2e/reshare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestResharing(t *testing.T) {

// Ensure cleanup happens even if test fails
defer func() {
suite.AssertNoResultErrors(t)
t.Log("Performing post-test cleanup...")
suite.Cleanup(t)
}()
Expand All @@ -36,10 +37,10 @@ func TestResharing(t *testing.T) {
suite.RunMakeClean()
suite.SetupInfrastructure(t)
suite.SetupTestNodes(t)
require.NoError(t, suite.LoadConfig(), "Failed to load config after setup")
suite.RegisterPeers(t)
suite.StartNodes(t)
suite.SetupMPCClient(t)
suite.LoadConfig()
})

// Key generation phase
Expand Down Expand Up @@ -84,7 +85,7 @@ func testKeyGenerationForResharing(t *testing.T, suite *E2ETestSuite) {
suite.keygenResults[result.WalletID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Keygen succeeded for wallet %s", result.WalletID)
}
Expand Down Expand Up @@ -171,7 +172,7 @@ func testResharingAllNodes(t *testing.T, suite *E2ETestSuite) {
suite.resharingResults[result.WalletID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Resharing failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Resharing failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Resharing succeeded for wallet %s", result.WalletID)
}
Expand Down Expand Up @@ -352,7 +353,7 @@ func testSigningAfterResharing(t *testing.T, suite *E2ETestSuite) {
signingResults[result.TxID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Signing failed for wallet %s (tx: %s): %s (%s)", result.WalletID, result.TxID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Signing failed for wallet %s (tx: %s): %s (%s)", result.WalletID, result.TxID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Signing succeeded for wallet %s (tx: %s)", result.WalletID, result.TxID)
}
Expand Down
5 changes: 3 additions & 2 deletions e2e/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func TestSigning(t *testing.T) {

// Ensure cleanup happens even if test fails
defer func() {
suite.AssertNoResultErrors(t)
t.Log("Performing post-test cleanup...")
suite.Cleanup(t)
}()
Expand Down Expand Up @@ -142,7 +143,7 @@ func testKeyGenerationForSigning(t *testing.T, suite *E2ETestSuite) {
suite.keygenResults[result.WalletID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Keygen succeeded for wallet %s", result.WalletID)
}
Expand Down Expand Up @@ -224,7 +225,7 @@ func testSigningAllNodes(t *testing.T, suite *E2ETestSuite) {
signingResults[result.TxID] = &result

if result.ResultType == event.ResultTypeError {
t.Logf("Signing failed for wallet %s (tx: %s): %s (%s)", result.WalletID, result.TxID, result.ErrorReason, result.ErrorCode)
suite.recordResultError("Signing failed for wallet %s (tx: %s): %s (%s)", result.WalletID, result.TxID, result.ErrorReason, result.ErrorCode)
} else {
t.Logf("Signing succeeded for wallet %s (tx: %s)", result.WalletID, result.TxID)
}
Expand Down
10 changes: 8 additions & 2 deletions examples/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,15 @@ func main() {
logger.Fatal("Failed to create local signer", err)
}

nodeKeyLookup, err := client.NewNodeKeyLookup("./node0/identity")
if err != nil {
logger.Fatal("Failed to create node key lookup", err)
}

mpcClient := client.NewMPCClient(client.Options{
NatsConn: natsConn,
Signer: localSigner,
NatsConn: natsConn,
Signer: localSigner,
NodeKeyLookup: nodeKeyLookup,
})

var walletStartTimes sync.Map
Expand Down
10 changes: 8 additions & 2 deletions examples/reshare/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,15 @@ func main() {
logger.Fatal("Failed to create local signer", err)
}

nodeKeyLookup, err := client.NewNodeKeyLookup("./node0/identity")
if err != nil {
logger.Fatal("Failed to create node key lookup", err)
}

mpcClient := client.NewMPCClient(client.Options{
NatsConn: natsConn,
Signer: localSigner,
NatsConn: natsConn,
Signer: localSigner,
NodeKeyLookup: nodeKeyLookup,
})

// 3) Listen for signing results
Expand Down
10 changes: 8 additions & 2 deletions examples/sign/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,15 @@ func main() {
logger.Fatal("Failed to create local signer", err)
}

nodeKeyLookup, err := client.NewNodeKeyLookup("./node0/identity")
if err != nil {
logger.Fatal("Failed to create node key lookup", err)
}

mpcClient := client.NewMPCClient(client.Options{
NatsConn: natsConn,
Signer: localSigner,
NatsConn: natsConn,
Signer: localSigner,
NodeKeyLookup: nodeKeyLookup,
})

// 2) Once wallet exists, immediately fire a SignTransaction
Expand Down
Loading
Loading