Merge pull request #17 from depools/feat/client-fsm

Feat/client fsm
This commit is contained in:
Mike Mozhaev 2020-08-13 14:01:07 +03:00 committed by GitHub
commit d98bb5f186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 15 deletions

View File

@ -4,13 +4,18 @@ import (
"context"
"encoding/json"
"fmt"
dkgFSM "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
"go.dedis.ch/kyber/v3"
"log"
"path/filepath"
"sync"
"time"
fsmStateMachines "github.com/depools/dc4bc/fsm/state_machines"
"github.com/depools/dc4bc/qr"
"github.com/depools/dc4bc/storage"
sign "go.dedis.ch/kyber/v3/sign/schnorr"
"go.dedis.ch/kyber/v3/util/key"
)
const (
@ -21,15 +26,19 @@ const (
type Client struct {
sync.Mutex
ctx context.Context
fsm interface{}
fsm *fsmStateMachines.FSMInstance
state State
storage storage.Storage
qrProcessor qr.Processor
// these just a template
suite key.Suite
authKeyPair *key.Pair
}
func NewClient(
ctx context.Context,
fsm interface{},
fsm *fsmStateMachines.FSMInstance,
state State,
storage storage.Storage,
qrProcessor qr.Processor,
@ -69,10 +78,34 @@ func (c *Client) Poll() error {
for _, message := range messages {
log.Println("Message:", message)
// Feed the message to the FSM, get a possibly empty operation.
fsmReq, err := FSMRequestFromBytes(message.Data)
if err != nil {
return fmt.Errorf("failed to get FSMRequest from message data: %w", err)
}
resp, fsmDump, err := c.fsm.Do(fsmReq.Event, fsmReq.Args...)
if err != nil {
return fmt.Errorf("failed to Do operation in FSM: %w", err)
}
var operation *Operation
// I.e., if FSM returned an Operation for us.
switch resp.State {
// if the new state is waiting for RPC to airgapped machine
case dkgFSM.StateDkgPubKeysAwaitConfirmations, dkgFSM.StateDkgCommitsAwaitConfirmations,
dkgFSM.StateDkgDealsAwaitConfirmations, dkgFSM.StateDkgResponsesAwaitConfirmations:
bz, err := json.Marshal(resp.Data)
if err != nil {
return fmt.Errorf("failed to marshal FSM response: %w", err)
}
operation = &Operation{
Type: OperationType(resp.State),
Payload: bz,
}
default:
log.Printf("State %s does not require an operation", resp.State)
}
if operation != nil {
if err := c.state.PutOperation(operation); err != nil {
return fmt.Errorf("failed to PutOperation: %w", err)
@ -83,7 +116,7 @@ func (c *Client) Poll() error {
return fmt.Errorf("failed to SaveOffset: %w", err)
}
if err := c.state.SaveFSM(c.fsm); err != nil {
if err := c.state.SaveFSM(fsmDump); err != nil {
return fmt.Errorf("failed to SaveFSM: %w", err)
}
}
@ -155,7 +188,15 @@ func (c *Client) handleProcessedOperation(operation Operation) error {
return fmt.Errorf("processed operation does not match stored operation: %w", err)
}
var message storage.Message
sig, err := c.signMessage(operation.Result)
if err != nil {
return fmt.Errorf("failed to sign a message: %w", err)
}
message := storage.Message{
Data: operation.Result,
Signature: sig,
}
if _, err := c.storage.Send(message); err != nil {
return fmt.Errorf("failed to post message: %w", err)
}
@ -166,3 +207,22 @@ func (c *Client) handleProcessedOperation(operation Operation) error {
return nil
}
// it's just a template
func (c *Client) signMessage(msg []byte) ([]byte, error) {
//s, err := sign.Sign(c.suite, c.authKeyPair.Private, msg)
//if err != nil {
// return nil, fmt.Errorf("failed to sign a message: %w", err)
//}
return nil, nil
}
// it's just a template
func (c *Client) verifyMessage(participant string, msg, signature []byte) error {
return sign.Verify(c.suite, c.getPublicKeyOfParticipant(participant), msg, signature)
}
// func should return public key of participant for checking his message signature
func (c *Client) getPublicKeyOfParticipant(participant string) kyber.Point {
return nil
}

View File

@ -13,14 +13,15 @@ import (
const (
offsetKey = "offset"
operationsKey = "operations"
fsmStateKey = "fsm_state"
)
type State interface {
SaveOffset(uint64) error
LoadOffset() (uint64, error)
SaveFSM(interface{}) error
LoadFSM() (interface{}, error)
SaveFSM([]byte) error
LoadFSM() ([]byte, error)
PutOperation(operation *Operation) error
DeleteOperation(operationID string) error
@ -95,13 +96,16 @@ func (s *LevelDBState) LoadOffset() (uint64, error) {
}
// TODO: implement.
func (s *LevelDBState) SaveFSM(interface{}) error {
func (s *LevelDBState) SaveFSM(fsmState []byte) error {
if err := s.stateDb.Put([]byte(fsmStateKey), fsmState, nil); err != nil {
return fmt.Errorf("failed to save fsm state: %w", err)
}
return nil
}
// TODO: implement.
func (s *LevelDBState) LoadFSM() (interface{}, error) {
return nil, nil
func (s *LevelDBState) LoadFSM() ([]byte, error) {
return s.stateDb.Get([]byte(fsmStateKey), nil)
}
func (s *LevelDBState) PutOperation(operation *Operation) error {

View File

@ -2,7 +2,9 @@ package client
import (
"bytes"
"encoding/json"
"fmt"
"github.com/depools/dc4bc/fsm/fsm"
"time"
)
@ -35,3 +37,19 @@ func (o *Operation) Check(o2 *Operation) error {
return nil
}
type FSMRequest struct {
Event fsm.Event
Args []interface{}
}
func FSMRequestFromBytes(data []byte) (FSMRequest, error) {
var (
r FSMRequest
err error
)
if err = json.Unmarshal(data, &r); err != nil {
return r, err
}
return r, err
}

View File

@ -64,7 +64,7 @@ func (mr *MockStateMockRecorder) LoadOffset() *gomock.Call {
}
// SaveFSM mocks base method
func (m *MockState) SaveFSM(arg0 interface{}) error {
func (m *MockState) SaveFSM(arg0 []byte) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveFSM", arg0)
ret0, _ := ret[0].(error)
@ -72,16 +72,16 @@ func (m *MockState) SaveFSM(arg0 interface{}) error {
}
// SaveFSM indicates an expected call of SaveFSM
func (mr *MockStateMockRecorder) SaveFSM(arg0 interface{}) *gomock.Call {
func (mr *MockStateMockRecorder) SaveFSM(arg0 []byte) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveFSM", reflect.TypeOf((*MockState)(nil).SaveFSM), arg0)
}
// LoadFSM mocks base method
func (m *MockState) LoadFSM() (interface{}, error) {
func (m *MockState) LoadFSM() ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadFSM")
ret0, _ := ret[0].(interface{})
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}