695 lines
19 KiB
Go
695 lines
19 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/rwadurian/mpc-system/pkg/config"
|
|
"github.com/rwadurian/mpc-system/pkg/crypto"
|
|
"github.com/rwadurian/mpc-system/pkg/logger"
|
|
"github.com/rwadurian/mpc-system/pkg/tss"
|
|
grpcclient "github.com/rwadurian/mpc-system/services/server-party/adapters/output/grpc"
|
|
"github.com/rwadurian/mpc-system/services/server-party/application/use_cases"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func main() {
|
|
// Parse flags
|
|
configPath := flag.String("config", "", "Path to config file")
|
|
flag.Parse()
|
|
|
|
// Load configuration
|
|
cfg, err := config.Load(*configPath)
|
|
if err != nil {
|
|
fmt.Printf("Failed to load config: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Initialize logger
|
|
if err := logger.Init(&logger.Config{
|
|
Level: cfg.Logger.Level,
|
|
Encoding: cfg.Logger.Encoding,
|
|
}); err != nil {
|
|
fmt.Printf("Failed to initialize logger: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer logger.Sync()
|
|
|
|
logger.Info("Starting Server Party API Service",
|
|
zap.String("environment", cfg.Server.Environment),
|
|
zap.Int("http_port", cfg.Server.HTTPPort))
|
|
|
|
// Initialize crypto service with master key from environment
|
|
masterKeyHex := os.Getenv("MPC_CRYPTO_MASTER_KEY")
|
|
if masterKeyHex == "" {
|
|
masterKeyHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
}
|
|
masterKey, err := hex.DecodeString(masterKeyHex)
|
|
if err != nil {
|
|
logger.Fatal("Invalid master key format", zap.Error(err))
|
|
}
|
|
cryptoService, err := crypto.NewCryptoService(masterKey)
|
|
if err != nil {
|
|
logger.Fatal("Failed to create crypto service", zap.Error(err))
|
|
}
|
|
|
|
// Get API key for authentication
|
|
apiKey := os.Getenv("MPC_API_KEY")
|
|
if apiKey == "" {
|
|
logger.Warn("MPC_API_KEY not set, API will be unprotected")
|
|
}
|
|
|
|
// Get gRPC service addresses from environment
|
|
coordinatorAddr := os.Getenv("SESSION_COORDINATOR_ADDR")
|
|
if coordinatorAddr == "" {
|
|
coordinatorAddr = "session-coordinator:50051"
|
|
}
|
|
routerAddr := os.Getenv("MESSAGE_ROUTER_ADDR")
|
|
if routerAddr == "" {
|
|
routerAddr = "message-router:50051"
|
|
}
|
|
|
|
// Initialize gRPC clients
|
|
sessionClient, err := grpcclient.NewSessionCoordinatorClient(coordinatorAddr)
|
|
if err != nil {
|
|
logger.Fatal("Failed to connect to session coordinator", zap.Error(err))
|
|
}
|
|
defer sessionClient.Close()
|
|
|
|
messageRouter, err := grpcclient.NewMessageRouterClient(routerAddr)
|
|
if err != nil {
|
|
logger.Fatal("Failed to connect to message router", zap.Error(err))
|
|
}
|
|
defer messageRouter.Close()
|
|
|
|
// Create shutdown context
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Start HTTP server
|
|
errChan := make(chan error, 1)
|
|
go func() {
|
|
if err := startHTTPServer(cfg, sessionClient, messageRouter, cryptoService, apiKey); err != nil {
|
|
errChan <- fmt.Errorf("HTTP server error: %w", err)
|
|
}
|
|
}()
|
|
|
|
// Wait for shutdown signal
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
select {
|
|
case sig := <-sigChan:
|
|
logger.Info("Received shutdown signal", zap.String("signal", sig.String()))
|
|
case err := <-errChan:
|
|
logger.Error("Server error", zap.Error(err))
|
|
}
|
|
|
|
// Graceful shutdown
|
|
logger.Info("Shutting down...")
|
|
cancel()
|
|
|
|
time.Sleep(5 * time.Second)
|
|
logger.Info("Shutdown complete")
|
|
|
|
_ = ctx
|
|
}
|
|
|
|
func startHTTPServer(
|
|
cfg *config.Config,
|
|
sessionClient use_cases.SessionCoordinatorClient,
|
|
messageRouter use_cases.MessageRouterClient,
|
|
cryptoService *crypto.CryptoService,
|
|
apiKey string,
|
|
) error {
|
|
if cfg.Server.Environment == "production" {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
|
|
router := gin.New()
|
|
router.Use(gin.Recovery())
|
|
router.Use(gin.Logger())
|
|
|
|
// Health check
|
|
router.GET("/health", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": "healthy",
|
|
"service": "server-party-api",
|
|
})
|
|
})
|
|
|
|
// API routes with optional authentication
|
|
api := router.Group("/api/v1")
|
|
if apiKey != "" {
|
|
api.Use(apiKeyAuth(apiKey))
|
|
}
|
|
|
|
{
|
|
// Generate user share - synchronous endpoint that returns the share
|
|
// This is the main endpoint for mpc-service to call
|
|
api.POST("/keygen/generate-user-share", func(c *gin.Context) {
|
|
var req struct {
|
|
SessionID string `json:"session_id" binding:"required"`
|
|
PartyID string `json:"party_id" binding:"required"`
|
|
JoinToken string `json:"join_token" binding:"required"`
|
|
// Optional: encryption key for the share (provided by user)
|
|
UserPublicKey string `json:"user_public_key"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
sessionID, err := uuid.Parse(req.SessionID)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session_id format"})
|
|
return
|
|
}
|
|
|
|
logger.Info("Generating user share",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID))
|
|
|
|
// Execute keygen synchronously and return the share
|
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Minute)
|
|
defer cancel()
|
|
|
|
result, err := generateUserShare(
|
|
ctx,
|
|
sessionClient,
|
|
messageRouter,
|
|
cryptoService,
|
|
sessionID,
|
|
req.PartyID,
|
|
req.JoinToken,
|
|
req.UserPublicKey,
|
|
)
|
|
if err != nil {
|
|
logger.Error("Failed to generate user share",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID),
|
|
zap.Error(err))
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "keygen failed",
|
|
"details": err.Error(),
|
|
"session_id": req.SessionID,
|
|
"party_id": req.PartyID,
|
|
})
|
|
return
|
|
}
|
|
|
|
logger.Info("User share generated successfully",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID))
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"session_id": req.SessionID,
|
|
"party_id": req.PartyID,
|
|
"party_index": result.PartyIndex,
|
|
"share_data": result.ShareData,
|
|
"public_key": result.PublicKey,
|
|
})
|
|
})
|
|
|
|
// Sign with user share - synchronous endpoint
|
|
api.POST("/sign/with-user-share", func(c *gin.Context) {
|
|
var req struct {
|
|
SessionID string `json:"session_id" binding:"required"`
|
|
PartyID string `json:"party_id" binding:"required"`
|
|
JoinToken string `json:"join_token" binding:"required"`
|
|
ShareData string `json:"share_data" binding:"required"`
|
|
MessageHash string `json:"message_hash" binding:"required"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
sessionID, err := uuid.Parse(req.SessionID)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session_id format"})
|
|
return
|
|
}
|
|
|
|
shareData, err := hex.DecodeString(req.ShareData)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid share_data format (expected hex)"})
|
|
return
|
|
}
|
|
|
|
messageHash, err := hex.DecodeString(req.MessageHash)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid message_hash format (expected hex)"})
|
|
return
|
|
}
|
|
|
|
logger.Info("Signing with user share",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID))
|
|
|
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Minute)
|
|
defer cancel()
|
|
|
|
result, err := signWithUserShare(
|
|
ctx,
|
|
sessionClient,
|
|
messageRouter,
|
|
cryptoService,
|
|
sessionID,
|
|
req.PartyID,
|
|
req.JoinToken,
|
|
shareData,
|
|
messageHash,
|
|
)
|
|
if err != nil {
|
|
logger.Error("Failed to sign with user share",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID),
|
|
zap.Error(err))
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "signing failed",
|
|
"details": err.Error(),
|
|
"session_id": req.SessionID,
|
|
"party_id": req.PartyID,
|
|
})
|
|
return
|
|
}
|
|
|
|
logger.Info("Signing completed successfully",
|
|
zap.String("session_id", req.SessionID),
|
|
zap.String("party_id", req.PartyID))
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"success": true,
|
|
"session_id": req.SessionID,
|
|
"party_id": req.PartyID,
|
|
"signature": result.Signature,
|
|
"r": result.R,
|
|
"s": result.S,
|
|
"v": result.V,
|
|
})
|
|
})
|
|
}
|
|
|
|
logger.Info("Starting HTTP server", zap.Int("port", cfg.Server.HTTPPort))
|
|
return router.Run(fmt.Sprintf(":%d", cfg.Server.HTTPPort))
|
|
}
|
|
|
|
func apiKeyAuth(expectedKey string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
apiKey := c.GetHeader("X-API-Key")
|
|
if apiKey == "" {
|
|
apiKey = c.Query("api_key")
|
|
}
|
|
if apiKey != expectedKey {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid or missing API key"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// UserShareResult contains the result of user share generation
|
|
type UserShareResult struct {
|
|
PartyIndex int
|
|
ShareData string // hex encoded
|
|
PublicKey string // hex encoded
|
|
}
|
|
|
|
// generateUserShare generates a share for the user without storing it
|
|
func generateUserShare(
|
|
ctx context.Context,
|
|
sessionClient use_cases.SessionCoordinatorClient,
|
|
messageRouter use_cases.MessageRouterClient,
|
|
cryptoService *crypto.CryptoService,
|
|
sessionID uuid.UUID,
|
|
partyID string,
|
|
joinToken string,
|
|
userPublicKey string,
|
|
) (*UserShareResult, error) {
|
|
// 1. Join session via coordinator
|
|
sessionInfo, err := sessionClient.JoinSession(ctx, sessionID, partyID, joinToken)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to join session: %w", err)
|
|
}
|
|
|
|
if sessionInfo.SessionType != "keygen" {
|
|
return nil, fmt.Errorf("invalid session type: expected keygen, got %s", sessionInfo.SessionType)
|
|
}
|
|
|
|
// 2. Find self in participants and build party index map
|
|
var selfIndex int
|
|
partyIndexMap := make(map[string]int)
|
|
for _, p := range sessionInfo.Participants {
|
|
partyIndexMap[p.PartyID] = p.PartyIndex
|
|
if p.PartyID == partyID {
|
|
selfIndex = p.PartyIndex
|
|
}
|
|
}
|
|
|
|
// 3. Subscribe to messages
|
|
msgChan, err := messageRouter.SubscribeMessages(ctx, sessionID, partyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to subscribe to messages: %w", err)
|
|
}
|
|
|
|
// 4. Run TSS Keygen protocol
|
|
saveData, publicKey, err := runKeygenProtocol(
|
|
ctx,
|
|
sessionID,
|
|
partyID,
|
|
selfIndex,
|
|
sessionInfo.Participants,
|
|
sessionInfo.ThresholdN,
|
|
sessionInfo.ThresholdT,
|
|
msgChan,
|
|
partyIndexMap,
|
|
messageRouter,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("keygen protocol failed: %w", err)
|
|
}
|
|
|
|
// 5. Encrypt share (optionally with user's public key if provided)
|
|
var encryptedShare []byte
|
|
if userPublicKey != "" {
|
|
// TODO: Encrypt with user's public key for end-to-end encryption
|
|
encryptedShare, err = cryptoService.EncryptShare(saveData, partyID)
|
|
} else {
|
|
encryptedShare, err = cryptoService.EncryptShare(saveData, partyID)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to encrypt share: %w", err)
|
|
}
|
|
|
|
// 6. Report completion to coordinator
|
|
if err := sessionClient.ReportCompletion(ctx, sessionID, partyID, publicKey); err != nil {
|
|
logger.Error("failed to report completion", zap.Error(err))
|
|
// Don't fail - share is generated
|
|
}
|
|
|
|
return &UserShareResult{
|
|
PartyIndex: selfIndex,
|
|
ShareData: hex.EncodeToString(encryptedShare),
|
|
PublicKey: hex.EncodeToString(publicKey),
|
|
}, nil
|
|
}
|
|
|
|
// SigningResult contains the result of signing
|
|
type SigningResult struct {
|
|
Signature string
|
|
R string
|
|
S string
|
|
V int
|
|
}
|
|
|
|
// signWithUserShare signs using the user's share
|
|
func signWithUserShare(
|
|
ctx context.Context,
|
|
sessionClient use_cases.SessionCoordinatorClient,
|
|
messageRouter use_cases.MessageRouterClient,
|
|
cryptoService *crypto.CryptoService,
|
|
sessionID uuid.UUID,
|
|
partyID string,
|
|
joinToken string,
|
|
shareData []byte,
|
|
messageHash []byte,
|
|
) (*SigningResult, error) {
|
|
// 1. Join session via coordinator
|
|
sessionInfo, err := sessionClient.JoinSession(ctx, sessionID, partyID, joinToken)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to join session: %w", err)
|
|
}
|
|
|
|
if sessionInfo.SessionType != "sign" {
|
|
return nil, fmt.Errorf("invalid session type: expected sign, got %s", sessionInfo.SessionType)
|
|
}
|
|
|
|
// 2. Decrypt share
|
|
decryptedShare, err := cryptoService.DecryptShare(shareData, partyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decrypt share: %w", err)
|
|
}
|
|
|
|
// 3. Find self in participants
|
|
var selfIndex int
|
|
partyIndexMap := make(map[string]int)
|
|
for _, p := range sessionInfo.Participants {
|
|
partyIndexMap[p.PartyID] = p.PartyIndex
|
|
if p.PartyID == partyID {
|
|
selfIndex = p.PartyIndex
|
|
}
|
|
}
|
|
|
|
// 4. Subscribe to messages
|
|
msgChan, err := messageRouter.SubscribeMessages(ctx, sessionID, partyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to subscribe to messages: %w", err)
|
|
}
|
|
|
|
// 5. Run TSS Signing protocol
|
|
signature, r, s, v, err := runSigningProtocol(
|
|
ctx,
|
|
sessionID,
|
|
partyID,
|
|
selfIndex,
|
|
sessionInfo.Participants,
|
|
sessionInfo.ThresholdN,
|
|
sessionInfo.ThresholdT,
|
|
msgChan,
|
|
partyIndexMap,
|
|
messageRouter,
|
|
decryptedShare,
|
|
messageHash,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("signing protocol failed: %w", err)
|
|
}
|
|
|
|
// 6. Report completion to coordinator
|
|
if err := sessionClient.ReportCompletion(ctx, sessionID, partyID, signature); err != nil {
|
|
logger.Error("failed to report completion", zap.Error(err))
|
|
}
|
|
|
|
return &SigningResult{
|
|
Signature: hex.EncodeToString(signature),
|
|
R: hex.EncodeToString(r),
|
|
S: hex.EncodeToString(s),
|
|
V: v,
|
|
}, nil
|
|
}
|
|
|
|
// runKeygenProtocol runs the TSS keygen protocol
|
|
func runKeygenProtocol(
|
|
ctx context.Context,
|
|
sessionID uuid.UUID,
|
|
partyID string,
|
|
selfIndex int,
|
|
participants []use_cases.ParticipantInfo,
|
|
n, t int,
|
|
msgChan <-chan *use_cases.MPCMessage,
|
|
partyIndexMap map[string]int,
|
|
messageRouter use_cases.MessageRouterClient,
|
|
) ([]byte, []byte, error) {
|
|
logger.Info("Running keygen protocol",
|
|
zap.String("session_id", sessionID.String()),
|
|
zap.String("party_id", partyID),
|
|
zap.Int("self_index", selfIndex),
|
|
zap.Int("n", n),
|
|
zap.Int("t", t))
|
|
|
|
// Create message handler adapter
|
|
msgHandler := &messageHandler{
|
|
sessionID: sessionID,
|
|
partyID: partyID,
|
|
messageRouter: messageRouter,
|
|
msgChan: make(chan *tss.ReceivedMessage, 100),
|
|
partyIndexMap: partyIndexMap,
|
|
}
|
|
|
|
// Start message conversion goroutine
|
|
go msgHandler.convertMessages(ctx, msgChan)
|
|
|
|
// Create keygen config
|
|
config := tss.KeygenConfig{
|
|
Threshold: t,
|
|
TotalParties: n,
|
|
Timeout: 10 * time.Minute,
|
|
}
|
|
|
|
// Create party list
|
|
allParties := make([]tss.KeygenParty, len(participants))
|
|
for i, p := range participants {
|
|
allParties[i] = tss.KeygenParty{
|
|
PartyID: p.PartyID,
|
|
PartyIndex: p.PartyIndex,
|
|
}
|
|
}
|
|
|
|
selfParty := tss.KeygenParty{
|
|
PartyID: partyID,
|
|
PartyIndex: selfIndex,
|
|
}
|
|
|
|
// Create keygen session
|
|
session, err := tss.NewKeygenSession(config, selfParty, allParties, msgHandler)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Run keygen
|
|
result, err := session.Start(ctx)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
logger.Info("Keygen completed successfully",
|
|
zap.String("session_id", sessionID.String()),
|
|
zap.String("party_id", partyID))
|
|
|
|
return result.LocalPartySaveData, result.PublicKeyBytes, nil
|
|
}
|
|
|
|
// runSigningProtocol runs the TSS signing protocol
|
|
func runSigningProtocol(
|
|
ctx context.Context,
|
|
sessionID uuid.UUID,
|
|
partyID string,
|
|
selfIndex int,
|
|
participants []use_cases.ParticipantInfo,
|
|
n, t int,
|
|
msgChan <-chan *use_cases.MPCMessage,
|
|
partyIndexMap map[string]int,
|
|
messageRouter use_cases.MessageRouterClient,
|
|
shareData []byte,
|
|
messageHash []byte,
|
|
) ([]byte, []byte, []byte, int, error) {
|
|
logger.Info("Running signing protocol",
|
|
zap.String("session_id", sessionID.String()),
|
|
zap.String("party_id", partyID),
|
|
zap.Int("self_index", selfIndex))
|
|
|
|
// Create message handler adapter
|
|
msgHandler := &messageHandler{
|
|
sessionID: sessionID,
|
|
partyID: partyID,
|
|
messageRouter: messageRouter,
|
|
msgChan: make(chan *tss.ReceivedMessage, 100),
|
|
partyIndexMap: partyIndexMap,
|
|
}
|
|
|
|
// Start message conversion goroutine
|
|
go msgHandler.convertMessages(ctx, msgChan)
|
|
|
|
// Create signing config
|
|
config := tss.SigningConfig{
|
|
Threshold: t,
|
|
TotalSigners: n,
|
|
Timeout: 5 * time.Minute,
|
|
}
|
|
|
|
// Create party list
|
|
allParties := make([]tss.SigningParty, len(participants))
|
|
for i, p := range participants {
|
|
allParties[i] = tss.SigningParty{
|
|
PartyID: p.PartyID,
|
|
PartyIndex: p.PartyIndex,
|
|
}
|
|
}
|
|
|
|
selfParty := tss.SigningParty{
|
|
PartyID: partyID,
|
|
PartyIndex: selfIndex,
|
|
}
|
|
|
|
// Create signing session
|
|
session, err := tss.NewSigningSession(config, selfParty, allParties, shareData, messageHash, msgHandler)
|
|
if err != nil {
|
|
return nil, nil, nil, 0, err
|
|
}
|
|
|
|
// Run signing
|
|
result, err := session.Start(ctx)
|
|
if err != nil {
|
|
return nil, nil, nil, 0, err
|
|
}
|
|
|
|
logger.Info("Signing completed successfully",
|
|
zap.String("session_id", sessionID.String()),
|
|
zap.String("party_id", partyID))
|
|
|
|
// Convert big.Int to []byte
|
|
var rBytes, sBytes []byte
|
|
if result.R != nil {
|
|
rBytes = result.R.Bytes()
|
|
}
|
|
if result.S != nil {
|
|
sBytes = result.S.Bytes()
|
|
}
|
|
|
|
return result.Signature, rBytes, sBytes, result.RecoveryID, nil
|
|
}
|
|
|
|
// messageHandler adapts MPCMessage channel to tss.MessageHandler
|
|
type messageHandler struct {
|
|
sessionID uuid.UUID
|
|
partyID string
|
|
messageRouter use_cases.MessageRouterClient
|
|
msgChan chan *tss.ReceivedMessage
|
|
partyIndexMap map[string]int
|
|
}
|
|
|
|
func (h *messageHandler) SendMessage(ctx context.Context, isBroadcast bool, toParties []string, msgBytes []byte) error {
|
|
return h.messageRouter.RouteMessage(ctx, h.sessionID, h.partyID, toParties, 0, msgBytes)
|
|
}
|
|
|
|
func (h *messageHandler) ReceiveMessages() <-chan *tss.ReceivedMessage {
|
|
return h.msgChan
|
|
}
|
|
|
|
func (h *messageHandler) convertMessages(ctx context.Context, inChan <-chan *use_cases.MPCMessage) {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
close(h.msgChan)
|
|
return
|
|
case msg, ok := <-inChan:
|
|
if !ok {
|
|
close(h.msgChan)
|
|
return
|
|
}
|
|
|
|
fromIndex, exists := h.partyIndexMap[msg.FromParty]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
tssMsg := &tss.ReceivedMessage{
|
|
FromPartyIndex: fromIndex,
|
|
IsBroadcast: msg.IsBroadcast,
|
|
MsgBytes: msg.Payload,
|
|
}
|
|
|
|
select {
|
|
case h.msgChan <- tssMsg:
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|