2020-07-29 05:39:02 -07:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-08-14 05:34:15 -07:00
|
|
|
"crypto/ed25519"
|
2020-07-29 05:39:02 -07:00
|
|
|
"encoding/json"
|
2020-08-18 09:41:43 -07:00
|
|
|
"errors"
|
2020-07-29 05:39:02 -07:00
|
|
|
"fmt"
|
2020-10-02 04:02:53 -07:00
|
|
|
"github.com/depools/dc4bc/fsm/types/responses"
|
2020-07-29 05:39:02 -07:00
|
|
|
"log"
|
|
|
|
"path/filepath"
|
2020-08-04 00:45:32 -07:00
|
|
|
"sync"
|
2020-07-29 05:39:02 -07:00
|
|
|
"time"
|
|
|
|
|
2020-09-09 06:29:18 -07:00
|
|
|
sipf "github.com/depools/dc4bc/fsm/state_machines/signing_proposal_fsm"
|
|
|
|
|
2020-08-21 10:03:42 -07:00
|
|
|
"github.com/depools/dc4bc/client/types"
|
|
|
|
"github.com/depools/dc4bc/fsm/types/requests"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
2020-08-19 09:04:41 -07:00
|
|
|
spf "github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
2020-08-18 09:41:43 -07:00
|
|
|
|
|
|
|
"github.com/depools/dc4bc/fsm/state_machines"
|
|
|
|
|
2020-08-14 05:34:15 -07:00
|
|
|
"github.com/depools/dc4bc/fsm/fsm"
|
2020-08-19 09:04:41 -07:00
|
|
|
dpf "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
2020-08-03 23:34:10 -07:00
|
|
|
"github.com/depools/dc4bc/qr"
|
|
|
|
"github.com/depools/dc4bc/storage"
|
2020-07-29 05:39:02 -07:00
|
|
|
)
|
|
|
|
|
2020-07-29 06:32:03 -07:00
|
|
|
const (
|
|
|
|
pollingPeriod = time.Second
|
2020-07-30 04:23:09 -07:00
|
|
|
QrCodesDir = "/tmp"
|
2020-07-29 06:32:03 -07:00
|
|
|
)
|
2020-07-29 05:39:02 -07:00
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
type Client interface {
|
2020-09-07 01:07:49 -07:00
|
|
|
Poll() error
|
2020-10-05 08:00:54 -07:00
|
|
|
GetLogger() *logger
|
|
|
|
GetPubKey() ed25519.PublicKey
|
|
|
|
GetUsername() string
|
2020-09-07 01:07:49 -07:00
|
|
|
SendMessage(message storage.Message) error
|
|
|
|
ProcessMessage(message storage.Message) error
|
|
|
|
GetOperations() (map[string]*types.Operation, error)
|
2020-09-29 08:16:20 -07:00
|
|
|
GetOperationQRPath(operationID string) (string, error)
|
2020-09-07 01:07:49 -07:00
|
|
|
StartHTTPServer(listenAddr string) error
|
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
type BaseClient struct {
|
2020-08-04 00:45:32 -07:00
|
|
|
sync.Mutex
|
2020-09-04 08:35:22 -07:00
|
|
|
Logger *logger
|
2020-08-14 05:34:15 -07:00
|
|
|
userName string
|
2020-08-19 09:04:41 -07:00
|
|
|
pubKey ed25519.PublicKey
|
2020-07-30 04:23:09 -07:00
|
|
|
ctx context.Context
|
|
|
|
state State
|
|
|
|
storage storage.Storage
|
2020-08-14 05:34:15 -07:00
|
|
|
keyStore KeyStore
|
2020-07-30 04:23:09 -07:00
|
|
|
qrProcessor qr.Processor
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-07-29 06:32:03 -07:00
|
|
|
func NewClient(
|
|
|
|
ctx context.Context,
|
2020-08-14 05:34:15 -07:00
|
|
|
userName string,
|
2020-07-29 06:32:03 -07:00
|
|
|
state State,
|
|
|
|
storage storage.Storage,
|
2020-08-14 05:34:15 -07:00
|
|
|
keyStore KeyStore,
|
2020-07-30 04:23:09 -07:00
|
|
|
qrProcessor qr.Processor,
|
2020-10-05 08:00:54 -07:00
|
|
|
) (Client, error) {
|
2020-08-18 09:41:43 -07:00
|
|
|
keyPair, err := keyStore.LoadKeys(userName, "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to LoadKeys: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
return &BaseClient{
|
2020-07-30 04:23:09 -07:00
|
|
|
ctx: ctx,
|
2020-09-04 08:35:22 -07:00
|
|
|
Logger: newLogger(userName),
|
2020-08-14 05:34:15 -07:00
|
|
|
userName: userName,
|
2020-08-19 09:04:41 -07:00
|
|
|
pubKey: keyPair.Pub,
|
2020-07-30 04:23:09 -07:00
|
|
|
state: state,
|
|
|
|
storage: storage,
|
2020-08-14 05:34:15 -07:00
|
|
|
keyStore: keyStore,
|
2020-07-30 04:23:09 -07:00
|
|
|
qrProcessor: qrProcessor,
|
2020-07-29 06:32:03 -07:00
|
|
|
}, nil
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) GetLogger() *logger {
|
2020-09-07 01:07:49 -07:00
|
|
|
return c.Logger
|
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) GetUsername() string {
|
2020-09-15 06:45:35 -07:00
|
|
|
return c.userName
|
2020-08-19 09:04:41 -07:00
|
|
|
}
|
2020-07-29 05:39:02 -07:00
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) GetPubKey() ed25519.PublicKey {
|
2020-08-19 09:04:41 -07:00
|
|
|
return c.pubKey
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-09-28 01:01:40 -07:00
|
|
|
// Poll is a main client loop, which gets new messages from an append-only log and processes them
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) Poll() error {
|
2020-07-29 05:39:02 -07:00
|
|
|
tk := time.NewTicker(pollingPeriod)
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-tk.C:
|
2020-07-29 06:20:39 -07:00
|
|
|
offset, err := c.state.LoadOffset()
|
2020-07-29 05:39:02 -07:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
messages, err := c.storage.GetMessages(offset)
|
|
|
|
if err != nil {
|
2020-08-09 14:37:53 -07:00
|
|
|
return fmt.Errorf("failed to GetMessages: %w", err)
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, message := range messages {
|
2020-09-15 06:45:35 -07:00
|
|
|
if message.RecipientAddr == "" || message.RecipientAddr == c.GetUsername() {
|
2020-09-04 08:35:22 -07:00
|
|
|
c.Logger.Log("Handling message with offset %d, type %s", message.Offset, message.Event)
|
2020-08-22 05:04:44 -07:00
|
|
|
if err := c.ProcessMessage(message); err != nil {
|
2020-09-09 06:29:18 -07:00
|
|
|
c.Logger.Log("Failed to process message with offset %d: %v", message.Offset, err)
|
2020-08-22 05:04:44 -07:00
|
|
|
} else {
|
2020-09-04 08:35:22 -07:00
|
|
|
c.Logger.Log("Successfully processed message with offset %d, type %s",
|
2020-08-22 05:04:44 -07:00
|
|
|
message.Offset, message.Event)
|
|
|
|
}
|
2020-08-05 08:26:55 -07:00
|
|
|
}
|
2020-08-14 05:34:15 -07:00
|
|
|
}
|
|
|
|
case <-c.ctx.Done():
|
|
|
|
log.Println("Context closed, stop polling...")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-05 08:26:55 -07:00
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) SendMessage(message storage.Message) error {
|
2020-08-19 09:04:41 -07:00
|
|
|
if _, err := c.storage.Send(message); err != nil {
|
|
|
|
return fmt.Errorf("failed to post message: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-05 03:58:52 -07:00
|
|
|
// processSignature saves a broadcasted reconstructed signature to a LevelDB
|
|
|
|
func (c *Client) processSignature(message storage.Message) error {
|
|
|
|
var (
|
|
|
|
signature types.ReconstructedSignature
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if err = json.Unmarshal(message.Data, &signature); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal reconstructed signature: %w", err)
|
|
|
|
}
|
|
|
|
signature.Participant = message.SenderAddr
|
|
|
|
return c.state.SaveSignature(signature)
|
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) ProcessMessage(message storage.Message) error {
|
2020-10-05 03:58:52 -07:00
|
|
|
if fsm.Event(message.Event) == types.SignatureReconstructed {
|
|
|
|
if err := c.processSignature(message); err != nil {
|
|
|
|
return fmt.Errorf("failed to process signature: %w", err)
|
|
|
|
}
|
|
|
|
if err := c.state.SaveOffset(message.Offset + 1); err != nil {
|
|
|
|
return fmt.Errorf("failed to SaveOffset: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-18 09:41:43 -07:00
|
|
|
fsmInstance, err := c.getFSMInstance(message.DkgRoundID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to getFSMInstance: %w", err)
|
|
|
|
}
|
2020-08-21 09:25:09 -07:00
|
|
|
|
2020-09-22 06:15:18 -07:00
|
|
|
// we can't verify a message at this moment, cause we don't have public keys of participantss
|
2020-09-29 07:31:31 -07:00
|
|
|
if fsm.Event(message.Event) != spf.EventInitProposal {
|
2020-08-18 09:41:43 -07:00
|
|
|
if err := c.verifyMessage(fsmInstance, message); err != nil {
|
|
|
|
return fmt.Errorf("failed to verifyMessage %+v: %w", message, err)
|
|
|
|
}
|
|
|
|
}
|
2020-07-29 06:20:39 -07:00
|
|
|
|
2020-08-20 08:08:11 -07:00
|
|
|
fsmReq, err := types.FSMRequestFromMessage(message)
|
2020-08-14 05:34:15 -07:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get FSMRequestFromMessage: %v", err)
|
|
|
|
}
|
2020-07-29 05:39:02 -07:00
|
|
|
|
2020-08-18 09:41:43 -07:00
|
|
|
resp, fsmDump, err := fsmInstance.Do(fsm.Event(message.Event), fsmReq)
|
2020-08-14 05:34:15 -07:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to Do operation in FSM: %w", err)
|
|
|
|
}
|
2020-07-29 06:20:39 -07:00
|
|
|
|
2020-09-04 08:35:22 -07:00
|
|
|
c.Logger.Log("message %s done successfully from %s", message.Event, message.SenderAddr)
|
2020-08-22 05:04:44 -07:00
|
|
|
|
2020-09-22 06:15:18 -07:00
|
|
|
// switch FSM state by hand due to implementation specifics
|
2020-08-21 09:25:09 -07:00
|
|
|
if resp.State == spf.StateSignatureProposalCollected {
|
|
|
|
fsmInstance, err = state_machines.FromDump(fsmDump)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get state_machines from dump: %w", err)
|
|
|
|
}
|
|
|
|
resp, fsmDump, err = fsmInstance.Do(dpf.EventDKGInitProcess, requests.DefaultRequest{
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to Do operation in FSM: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2020-08-26 08:15:38 -07:00
|
|
|
if resp.State == dpf.StateDkgMasterKeyCollected {
|
|
|
|
fsmInstance, err = state_machines.FromDump(fsmDump)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get state_machines from dump: %w", err)
|
|
|
|
}
|
2020-08-27 02:45:05 -07:00
|
|
|
resp, fsmDump, err = fsmInstance.Do(sipf.EventSigningInit, requests.DefaultRequest{
|
2020-08-26 08:15:38 -07:00
|
|
|
CreatedAt: time.Now(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to Do operation in FSM: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2020-08-20 09:50:18 -07:00
|
|
|
|
2020-08-20 08:08:11 -07:00
|
|
|
var operation *types.Operation
|
2020-08-14 05:34:15 -07:00
|
|
|
switch resp.State {
|
|
|
|
// if the new state is waiting for RPC to airgapped machine
|
|
|
|
case
|
2020-08-19 09:04:41 -07:00
|
|
|
spf.StateAwaitParticipantsConfirmations,
|
|
|
|
dpf.StateDkgCommitsAwaitConfirmations,
|
|
|
|
dpf.StateDkgDealsAwaitConfirmations,
|
2020-08-22 05:04:44 -07:00
|
|
|
dpf.StateDkgResponsesAwaitConfirmations,
|
2020-08-26 08:15:38 -07:00
|
|
|
dpf.StateDkgMasterKeyAwaitConfirmations,
|
2020-09-01 01:45:19 -07:00
|
|
|
sipf.StateSigningAwaitPartialSigns,
|
|
|
|
sipf.StateSigningPartialSignsCollected,
|
2020-08-27 02:45:05 -07:00
|
|
|
sipf.StateSigningAwaitConfirmations:
|
2020-08-24 07:41:15 -07:00
|
|
|
if resp.Data != nil {
|
2020-10-02 04:02:53 -07:00
|
|
|
|
|
|
|
// if we are initiator of signing, then we don't need to confirm our participation
|
|
|
|
if data, ok := resp.Data.(responses.SigningProposalParticipantInvitationsResponse); ok {
|
|
|
|
initiator, err := fsmInstance.SigningQuorumGetParticipant(data.InitiatorId)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get SigningQuorumParticipant: %w", err)
|
|
|
|
}
|
|
|
|
if initiator.Addr == c.GetUsername() {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-24 07:41:15 -07:00
|
|
|
bz, err := json.Marshal(resp.Data)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to marshal FSM response: %w", err)
|
|
|
|
}
|
2020-07-29 05:39:02 -07:00
|
|
|
|
2020-08-24 07:41:15 -07:00
|
|
|
operation = &types.Operation{
|
|
|
|
ID: uuid.New().String(),
|
|
|
|
Type: types.OperationType(resp.State),
|
|
|
|
Payload: bz,
|
|
|
|
DKGIdentifier: message.DkgRoundID,
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
}
|
2020-08-14 05:34:15 -07:00
|
|
|
}
|
|
|
|
default:
|
2020-09-04 08:35:22 -07:00
|
|
|
c.Logger.Log("State %s does not require an operation", resp.State)
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
2020-07-29 06:20:39 -07:00
|
|
|
|
2020-10-02 01:50:00 -07:00
|
|
|
// switch FSM state by hand due to implementation specifics
|
|
|
|
if resp.State == sipf.StateSigningPartialSignsCollected {
|
|
|
|
fsmInstance, err = state_machines.FromDump(fsmDump)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed get state_machines from dump: %w", err)
|
|
|
|
}
|
|
|
|
resp, fsmDump, err = fsmInstance.Do(sipf.EventSigningRestart, requests.DefaultRequest{
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to Do operation in FSM: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 05:34:15 -07:00
|
|
|
if operation != nil {
|
2020-08-24 07:41:15 -07:00
|
|
|
if err := c.state.PutOperation(operation); err != nil {
|
|
|
|
return fmt.Errorf("failed to PutOperation: %w", err)
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
}
|
2020-08-14 05:34:15 -07:00
|
|
|
|
2020-08-21 09:25:09 -07:00
|
|
|
if err := c.state.SaveOffset(message.Offset + 1); err != nil {
|
2020-08-14 05:34:15 -07:00
|
|
|
return fmt.Errorf("failed to SaveOffset: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-08-18 09:41:43 -07:00
|
|
|
if err := c.state.SaveFSM(message.DkgRoundID, fsmDump); err != nil {
|
2020-08-14 05:34:15 -07:00
|
|
|
return fmt.Errorf("failed to SaveFSM: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) GetOperations() (map[string]*types.Operation, error) {
|
2020-07-29 05:39:02 -07:00
|
|
|
return c.state.GetOperations()
|
|
|
|
}
|
|
|
|
|
2020-10-05 03:58:52 -07:00
|
|
|
//GetSignatures returns all signatures for the given DKG round that were reconstructed on the airgapped machine and
|
|
|
|
// broadcasted by users
|
|
|
|
func (c *Client) GetSignatures(dkgID string) (map[string][]types.ReconstructedSignature, error) {
|
|
|
|
return c.state.GetSignatures(dkgID)
|
|
|
|
}
|
|
|
|
|
|
|
|
//GetSignatureByDataHash returns a list of reconstructed signatures of the signed data broadcasted by users
|
|
|
|
func (c *Client) GetSignatureByDataHash(dkgID, sigID string) ([]types.ReconstructedSignature, error) {
|
|
|
|
return c.state.GetSignatureByDataHash(dkgID, sigID)
|
|
|
|
}
|
|
|
|
|
2020-09-28 01:01:40 -07:00
|
|
|
// getOperationJSON returns a specific JSON-encoded operation
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) getOperationJSON(operationID string) ([]byte, error) {
|
2020-07-29 05:39:02 -07:00
|
|
|
operation, err := c.state.GetOperationByID(operationID)
|
|
|
|
if err != nil {
|
2020-07-31 07:55:47 -07:00
|
|
|
return nil, fmt.Errorf("failed to get operation: %w", err)
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
operationJSON, err := json.Marshal(operation)
|
|
|
|
if err != nil {
|
2020-07-31 07:55:47 -07:00
|
|
|
return nil, fmt.Errorf("failed to marshal operation: %w", err)
|
|
|
|
}
|
|
|
|
return operationJSON, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetOperationQRPath returns a path to the image with the QR generated
|
|
|
|
// for the specified operation. It is supposed that the user will open
|
|
|
|
// this file herself.
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) GetOperationQRPath(operationID string) (string, error) {
|
2020-07-31 07:55:47 -07:00
|
|
|
operationJSON, err := c.getOperationJSON(operationID)
|
|
|
|
if err != nil {
|
2020-09-29 08:16:20 -07:00
|
|
|
return "", fmt.Errorf("failed to get operation in JSON: %w", err)
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-09-11 04:39:01 -07:00
|
|
|
operationQRPath := filepath.Join(QrCodesDir, fmt.Sprintf("dc4bc_qr_%s", operationID))
|
2020-09-01 08:06:37 -07:00
|
|
|
|
2020-09-29 08:16:20 -07:00
|
|
|
qrPath := fmt.Sprintf("%s.gif", operationQRPath)
|
|
|
|
if err = c.qrProcessor.WriteQR(qrPath, operationJSON); err != nil {
|
|
|
|
return "", err
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
|
|
|
|
2020-09-29 08:16:20 -07:00
|
|
|
return qrPath, nil
|
2020-07-29 05:39:02 -07:00
|
|
|
}
|
2020-07-29 06:20:39 -07:00
|
|
|
|
2020-09-22 06:15:18 -07:00
|
|
|
// handleProcessedOperation handles an operation which was processed by the airgapped machine
|
|
|
|
// It checks that the operation exists in an operation pool, signs the operation, sends it to an append-only log and
|
|
|
|
// deletes it from the pool.
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) handleProcessedOperation(operation types.Operation) error {
|
2020-08-25 05:56:27 -07:00
|
|
|
storedOperation, err := c.state.GetOperationByID(operation.ID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to find matching operation: %w", err)
|
2020-08-14 05:34:15 -07:00
|
|
|
}
|
|
|
|
|
2020-08-25 05:56:27 -07:00
|
|
|
if err := storedOperation.Check(&operation); err != nil {
|
|
|
|
return fmt.Errorf("processed operation does not match stored operation: %w", err)
|
2020-08-07 06:54:44 -07:00
|
|
|
}
|
2020-08-05 08:26:55 -07:00
|
|
|
|
2020-08-25 05:56:27 -07:00
|
|
|
for _, message := range operation.ResultMsgs {
|
2020-09-15 06:45:35 -07:00
|
|
|
message.SenderAddr = c.GetUsername()
|
2020-08-25 05:56:27 -07:00
|
|
|
|
|
|
|
sig, err := c.signMessage(message.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to sign a message: %w", err)
|
|
|
|
}
|
|
|
|
message.Signature = sig
|
|
|
|
|
|
|
|
if _, err := c.storage.Send(message); err != nil {
|
|
|
|
return fmt.Errorf("failed to post message: %w", err)
|
|
|
|
}
|
2020-07-29 06:20:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.state.DeleteOperation(operation.ID); err != nil {
|
|
|
|
return fmt.Errorf("failed to DeleteOperation: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-07 06:54:44 -07:00
|
|
|
|
2020-09-22 06:15:18 -07:00
|
|
|
// getFSMInstance returns a FSM for a necessary DKG round.
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) getFSMInstance(dkgRoundID string) (*state_machines.FSMInstance, error) {
|
2020-08-18 09:41:43 -07:00
|
|
|
var err error
|
|
|
|
fsmInstance, ok, err := c.state.LoadFSM(dkgRoundID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to LoadFSM: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
fsmInstance, err = state_machines.Create(dkgRoundID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to create FSM instance: %w", err)
|
|
|
|
}
|
|
|
|
bz, err := fsmInstance.Dump()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to Dump FSM instance: %w", err)
|
|
|
|
}
|
|
|
|
if err := c.state.SaveFSM(dkgRoundID, bz); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to SaveFSM: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fsmInstance, nil
|
2020-08-07 06:54:44 -07:00
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) signMessage(message []byte) ([]byte, error) {
|
2020-08-14 05:34:15 -07:00
|
|
|
keyPair, err := c.keyStore.LoadKeys(c.userName, "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to LoadKeys: %w", err)
|
|
|
|
}
|
2020-08-07 06:54:44 -07:00
|
|
|
|
2020-08-14 05:34:15 -07:00
|
|
|
return ed25519.Sign(keyPair.Priv, message), nil
|
2020-08-07 06:54:44 -07:00
|
|
|
}
|
|
|
|
|
2020-10-05 08:00:54 -07:00
|
|
|
func (c *BaseClient) verifyMessage(fsmInstance *state_machines.FSMInstance, message storage.Message) error {
|
2020-08-18 09:41:43 -07:00
|
|
|
senderPubKey, err := fsmInstance.GetPubKeyByAddr(message.SenderAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to GetPubKeyByAddr: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ed25519.Verify(senderPubKey, message.Bytes(), message.Signature) {
|
|
|
|
return errors.New("signature is corrupt")
|
|
|
|
}
|
|
|
|
|
2020-08-07 06:54:44 -07:00
|
|
|
return nil
|
2020-08-20 08:08:11 -07:00
|
|
|
}
|