Skip to content

Commit ceda7d5

Browse files
authored
Merge pull request #160 from johnnynanjiang/issue/140-round-1
PR for issue #140 - Missing Wallet Query Interface in SDK to Retrieve Created Wallet Information
2 parents f05b0a2 + e453e3e commit ceda7d5

7 files changed

Lines changed: 95 additions & 6 deletions

File tree

e2e/base_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,20 @@ func (s *E2ETestSuite) LoadConfig() error {
8080
return err
8181
}
8282

83-
return yaml.Unmarshal(data, &s.config)
83+
if err := yaml.Unmarshal(data, &s.config); err != nil {
84+
return err
85+
}
86+
87+
return validateBadgerEncryptionKey(s.config.BadgerPassword)
88+
}
89+
90+
func validateBadgerEncryptionKey(key string) error {
91+
switch len([]byte(key)) {
92+
case 16, 24, 32:
93+
return nil
94+
default:
95+
return fmt.Errorf("badger_password must be 16, 24, or 32 bytes for Badger encryption, got %d bytes", len([]byte(key)))
96+
}
8497
}
8598

8699
func (s *E2ETestSuite) RunMakeClean() error {
@@ -284,6 +297,7 @@ func (s *E2ETestSuite) SeedPreParams(t *testing.T) {
284297
DbPath string `yaml:"db_path"`
285298
}
286299
require.NoError(t, yaml.Unmarshal(configData, &nodeConfig), "Failed to parse node config")
300+
require.NoError(t, validateBadgerEncryptionKey(nodeConfig.BadgerPassword), "Invalid badger_password in %s", configPath)
287301

288302
dbBasePath := nodeConfig.DbPath
289303
if dbBasePath == "" {

e2e/keygen_test.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
func TestKeyGeneration(t *testing.T) {
1616
suite := NewE2ETestSuite(".")
17+
logger.Init("dev", true)
1718

1819
// Comprehensive cleanup before starting tests
1920
t.Log("Performing pre-test cleanup...")
@@ -78,10 +79,23 @@ func testKeyGeneration(t *testing.T, suite *E2ETestSuite) {
7879
if suite.mpcClient == nil {
7980
t.Fatal("MPC client is not initialized. Make sure Setup subtest runs first.")
8081
}
82+
83+
walletID := uuid.New().String()
84+
85+
// Create a new wallet
86+
createWalletAndVerify(t, suite, walletID)
87+
88+
// Create another new wallet with the same wallet ID
89+
createWalletAndVerify(t, suite, walletID)
90+
91+
t.Log("Key generation test completed")
92+
}
93+
94+
func createWalletAndVerify(t *testing.T, suite *E2ETestSuite, walletID string) {
8195
// Generate 1 wallet ID for testing
8296
walletIDs := make([]string, 0, 10)
8397
for i := 0; i < 1; i++ {
84-
walletIDs = append(walletIDs, uuid.New().String())
98+
walletIDs = append(walletIDs, walletID)
8599
suite.walletIDs = append(suite.walletIDs, walletIDs[i])
86100
}
87101

@@ -91,7 +105,11 @@ func testKeyGeneration(t *testing.T, suite *E2ETestSuite) {
91105
err := suite.mpcClient.OnWalletCreationResult(func(result event.KeygenResultEvent) {
92106
logger.Info("On wallet creation result", "event", result)
93107
t.Logf("Received keygen result for wallet %s: %s", result.WalletID, result.ResultType)
94-
suite.keygenResults[result.WalletID] = &result
108+
109+
// For testing replay properly, don't overwrite existing result for the same wallet ID to preserve the first result
110+
if _, exists := suite.keygenResults[result.WalletID]; !exists {
111+
suite.keygenResults[result.WalletID] = &result
112+
}
95113

96114
if result.ResultType == event.ResultTypeError {
97115
t.Logf("Keygen failed for wallet %s: %s (%s)", result.WalletID, result.ErrorReason, result.ErrorCode)
@@ -164,8 +182,6 @@ checkResults:
164182
assert.NotEmpty(t, result.EDDSAPubKey, "EdDSA public key should not be empty for wallet %s", walletID)
165183
}
166184
}
167-
168-
t.Log("Key generation test completed")
169185
}
170186

171187
func verifyKeyConsistency(t *testing.T, suite *E2ETestSuite) {

e2e/multi_client_routing_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/fystack/mpcium/pkg/client"
1313
"github.com/fystack/mpcium/pkg/event"
14+
"github.com/fystack/mpcium/pkg/logger"
1415
"github.com/fystack/mpcium/pkg/types"
1516
"github.com/google/uuid"
1617
"github.com/nats-io/nats.go"
@@ -36,6 +37,7 @@ type multiClientObserver struct {
3637

3738
func TestMultiClientResultRouting(t *testing.T) {
3839
suite := NewE2ETestSuite(".")
40+
logger.Init("dev", true)
3941

4042
t.Log("Performing pre-test cleanup...")
4143
suite.CleanupTestEnvironment(t)

e2e/setup_test_identities.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ echo "🚀 Setting up E2E Test Node Identities..."
2525

2626
# Generate random password for badger encryption
2727
echo "🔐 Generating random password for badger encryption..."
28-
BADGER_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 32)
28+
if [[ "$OSTYPE" == "darwin"* ]]; then
29+
# macOS
30+
BADGER_PASSWORD=$(openssl rand -hex 16)
31+
else
32+
# Linux and others
33+
BADGER_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 32)
34+
fi
35+
if [ ${#BADGER_PASSWORD} -ne 32 ]; then
36+
echo "❌ Generated Badger password must be exactly 32 bytes, got ${#BADGER_PASSWORD}"
37+
exit 1
38+
fi
2939
echo "✅ Generated password: $BADGER_PASSWORD"
3040

3141
# Generate chain_code (32-byte hex value, 64 hex characters)

pkg/eventconsumer/event_consumer.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"sync"
1111
"time"
1212

13+
"github.com/dgraph-io/badger/v4"
1314
"github.com/fystack/mpcium/pkg/event"
1415
"github.com/fystack/mpcium/pkg/identity"
1516
"github.com/fystack/mpcium/pkg/logger"
@@ -158,6 +159,31 @@ func (ec *eventConsumer) handleKeyGenEvent(natMsg *nats.Msg) {
158159

159160
walletID := msg.WalletID
160161

162+
// Attempt to get previously stored wallet creation result (if any) by the wallet ID
163+
storedWalletCreationResult, storedWalletCreationResultError := ec.node.GetWalletCreationResult(walletID)
164+
165+
// Error when retrieving wallet creation result for the wallet ID
166+
if storedWalletCreationResultError != nil && !errors.Is(storedWalletCreationResultError, badger.ErrKeyNotFound) {
167+
ec.handleKeygenSessionError(walletID, storedWalletCreationResultError, "Failed to check stored wallet creation result", natMsg)
168+
return
169+
}
170+
171+
// Replay the wallet creation result if it already exists for the wallet ID
172+
// TODO: to move the following duplicate logic (line 308 and line 341) into a func
173+
if storedWalletCreationResult != nil {
174+
key := event.KeygenResultSubject(natMsg.Header.Get(event.ClientIDHeader), walletID)
175+
if err := ec.genKeyResultQueue.Enqueue(key, storedWalletCreationResult, &messaging.EnqueueOptions{
176+
IdempotententKey: composeKeygenIdempotentKey(walletID, natMsg),
177+
}); err != nil {
178+
logger.Error("Failed to enqueue stored wallet creation result", err, "walletID", walletID)
179+
ec.handleKeygenSessionError(walletID, err, "Failed to enqueue stored wallet creation result", natMsg)
180+
return
181+
}
182+
ec.sendReplyToRemoveMsg(natMsg)
183+
logger.Info("Returned stored wallet creation result for existing wallet", "walletID", walletID)
184+
return
185+
}
186+
161187
// Guard against duplicate keygen sessions for the same walletID.
162188
// Under heavy load, the keygen consumer may NAK and JetStream redelivers,
163189
// creating a second session on the same NATS topics which causes VSS verify failures.
@@ -272,6 +298,13 @@ func (ec *eventConsumer) handleKeyGenEvent(natMsg *nats.Msg) {
272298
return
273299
}
274300

301+
// Store wallet creation result
302+
if storeErr := ec.node.StoreWalletCreationResult(walletID, payload); storeErr != nil {
303+
logger.Error("Failed to store wallet creation result", storeErr, "walletID", walletID)
304+
ec.handleKeygenSessionError(walletID, storeErr, "Failed to store wallet creation result", natMsg)
305+
return
306+
}
307+
275308
key := event.KeygenResultSubject(natMsg.Header.Get(event.ClientIDHeader), walletID)
276309
if err := ec.genKeyResultQueue.Enqueue(
277310
key,

pkg/mpc/node.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,18 @@ func (p *Node) CreateReshareSession(
409409
}
410410
}
411411

412+
const walletCreationResultPrefix = "wallet_creation_result_prefix"
413+
414+
func (p *Node) StoreWalletCreationResult(walletID string, result []byte) error {
415+
key := fmt.Sprintf("%s:%s", walletCreationResultPrefix, walletID)
416+
return p.kvstore.Put(key, result)
417+
}
418+
419+
func (p *Node) GetWalletCreationResult(walletID string) ([]byte, error) {
420+
key := fmt.Sprintf("%s:%s", walletCreationResultPrefix, walletID)
421+
return p.kvstore.Get(key)
422+
}
423+
412424
func ComposeReadyKey(nodeID string) string {
413425
return fmt.Sprintf("ready/%s", nodeID)
414426
}

setup.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export PATH="$(go env GOPATH)/bin:$PATH"
2+
13
NUM_NODES=3
24

35
make build

0 commit comments

Comments
 (0)