Merge pull request #13 from depools/feat-dkg-proposal

feat: dkg_proposal
This commit is contained in:
Dmitriy 2020-08-07 10:58:23 +03:00 committed by GitHub
commit b86868ea92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 672 additions and 148 deletions

View File

@ -13,9 +13,9 @@ func main() {
fsmMachine, err := state_machines.New([]byte{})
log.Println(fsmMachine, err)
resp, dump, err := fsmMachine.Do(
"proposal_init",
"event_proposal_init",
"d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257",
requests.ProposalParticipantsListRequest{
requests.SignatureProposalParticipantsListRequest{
{
"John Doe",
[]byte("pubkey123123"),
@ -41,7 +41,7 @@ func processResponse(resp *fsm.Response) {
switch resp.State {
// Await proposals
case fsm.State("validate_proposal"):
data, ok := resp.Data.(responses.ProposalParticipantInvitationsResponse)
data, ok := resp.Data.(responses.SignatureProposalParticipantInvitationsResponse)
if !ok {
log.Printf("undefined response type for state \"%s\"\n", resp.State)
return
@ -57,7 +57,7 @@ func processResponse(resp *fsm.Response) {
}
}
func sendInvitations(invitations responses.ProposalParticipantInvitationsResponse) {
func sendInvitations(invitations responses.SignatureProposalParticipantInvitationsResponse) {
for _, invitation := range invitations {
log.Printf(
"Dear %s, please encrypt value \"%s\" with your key, fingerprint: %s\n",

View File

@ -73,8 +73,10 @@ type trKey struct {
// Transition lightweight event description
type trEvent struct {
event Event
dstState State
isInternal bool
isDstInit bool
}
type EventDesc struct {
@ -87,6 +89,9 @@ type EventDesc struct {
// Internal events, cannot be emitted from external call
IsInternal bool
// Set dst state before execute action
IsDstInit bool
}
type Callback func(event Event, args ...interface{}) (interface{}, error)
@ -168,7 +173,12 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
panic("duplicate dst for pair `source + event`")
}
f.transitions[tKey] = &trEvent{event.DstState, event.IsInternal}
f.transitions[tKey] = &trEvent{
tKey.event,
event.DstState,
event.IsInternal,
event.IsDstInit,
}
// For using provider, event must use with IsGlobal = true
if sourceState == initialState {
@ -221,34 +231,58 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
return f
}
func (f *FSM) Do(event Event, args ...interface{}) (resp *Response, err error) {
f.eventMu.Lock()
defer f.eventMu.Unlock()
func (f *FSM) DoInternal(event Event, args ...interface{}) (resp *Response, err error) {
trEvent, ok := f.transitions[trKey{f.currentState, event}]
if !ok {
return nil, errors.New("cannot execute event for this state")
return nil, errors.New(fmt.Sprintf("cannot execute event \"%s\" for state \"%s\"", event, f.currentState))
}
return f.do(trEvent, args...)
}
func (f *FSM) Do(event Event, args ...interface{}) (resp *Response, err error) {
trEvent, ok := f.transitions[trKey{f.currentState, event}]
if !ok {
return nil, errors.New(fmt.Sprintf("cannot execute event \"%s\" for state \"%s\"", event, f.currentState))
}
if trEvent.isInternal {
return nil, errors.New("event is internal")
}
return f.do(trEvent, args...)
}
func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err error) {
// f.eventMu.Lock()
// defer f.eventMu.Unlock()
if trEvent.isDstInit {
err = f.SetState(trEvent.event)
if err != nil {
resp = &Response{
State: f.State(),
}
return resp, err
}
}
resp = &Response{
State: f.State(),
}
if callback, ok := f.callbacks[event]; ok {
resp.Data, err = callback(event, args...)
if callback, ok := f.callbacks[trEvent.event]; ok {
resp.Data, err = callback(trEvent.event, args...)
// Do not try change state on error
if err != nil {
return resp, err
}
}
err = f.setState(event)
if err == nil {
resp.State = f.currentState
if !trEvent.isDstInit {
err = f.SetState(trEvent.event)
}
resp.State = f.State()
return
}
@ -259,9 +293,9 @@ func (f *FSM) State() State {
return f.currentState
}
// setState allows the user to move to the given state from currentState state.
// SetState allows the user to move to the given state from currentState state.
// The call does not trigger any callbacks, if defined.
func (f *FSM) setState(event Event) error {
func (f *FSM) SetState(event Event) error {
f.stateMu.Lock()
defer f.stateMu.Unlock()

View File

@ -2,6 +2,7 @@ package fsm_pool
import (
"errors"
"fmt"
"github.com/depools/dc4bc/fsm/fsm"
)
@ -15,6 +16,8 @@ type MachineProvider interface {
InitialState() fsm.State
State() fsm.State
// Process event
Do(event fsm.Event, args ...interface{}) (*fsm.Response, error)
@ -75,7 +78,7 @@ func Init(machines ...MachineProvider) *FSMPool {
machineEvents := machine.EventsList()
for _, event := range machineEvents {
if _, exists := p.events[event]; exists {
panic("duplicate public event")
panic(fmt.Sprintf("duplicate public event \"%s\"", event))
}
p.events[event] = machineName
}
@ -106,7 +109,7 @@ func Init(machines ...MachineProvider) *FSMPool {
}
}
if name, exists := p.states[state]; exists && name != machineName {
panic("duplicate state for machines")
panic(fmt.Sprintf("duplicate state for machines \"%s\"", state))
}
p.states[state] = machineName
@ -120,8 +123,6 @@ func Init(machines ...MachineProvider) *FSMPool {
}
func (p *FSMPool) EntryPointMachine() (MachineProvider, error) {
// StateGlobalIdle
// TODO: Short code
entryStateMachineName := p.events[p.fsmInitialEvent]
machine, exists := p.mapper[entryStateMachineName]
@ -142,6 +143,7 @@ func (p *FSMPool) MachineByEvent(event fsm.Event) (MachineProvider, error) {
return machine, nil
}
// Out states now is not returns machine
func (p *FSMPool) MachineByState(state fsm.State) (MachineProvider, error) {
eventMachineName := p.states[state]
machine, exists := p.mapper[eventMachineName]

View File

@ -1,18 +1,284 @@
package fsm_pool
/*
import (
"github.com/depools/dc4bc/fsm/fsm"
"testing"
)
var (
)
func init() {
type testMachineFSM1 struct {
*fsm.FSM
data int
}
func Test_InitPool(t *testing.T) {
const (
testVal1 = 100
testVal2 = 17
)
} */
const (
fsm1Name = "fsm1"
// Init process from global idle state
fsm1StateInit = fsm.StateGlobalIdle
// Set up data
fsm1StateStage1 = fsm.State("state_fsm1_stage1")
// Process data
fsm1StateStage2 = fsm.State("state_fsm1_stage2")
// Cancelled with internal event
fsm1StateCanceledByInternal = fsm.State("state_fsm1_canceled")
// Cancelled with external event
fsm1StateCanceled2 = fsm.State("state_fsm1_canceled2")
// Out endpoint to switch
fsm1StateOutToFSM2 = fsm.State("state_fsm1_out_to_fsm2")
// Events
eventFSM1Init = fsm.Event("event_fsm1_init")
eventFSM1Cancel = fsm.Event("event_fsm1_cancel")
eventFSM1Process = fsm.Event("event_fsm1_process")
// Internal events
eventFSM1Internal = fsm.Event("event_internal_fsm1")
eventFSM1CancelByInternal = fsm.Event("event_internal_fsm1_cancel")
eventFSM1InternalOut2 = fsm.Event("event_internal_fsm1_out")
)
var (
testing1Events = []fsm.EventDesc{
// Init
{Name: eventFSM1Init, SrcState: []fsm.State{fsm1StateInit}, DstState: fsm1StateStage1, IsDstInit: true},
{Name: eventFSM1Internal, SrcState: []fsm.State{fsm1StateStage1}, DstState: fsm1StateStage2, IsInternal: true},
// Cancellation events
{Name: eventFSM1CancelByInternal, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateCanceledByInternal, IsInternal: true},
{Name: eventFSM1Cancel, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateCanceled2},
// Out
{Name: eventFSM1Process, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateOutToFSM2},
{Name: eventFSM1InternalOut2, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateOutToFSM2, IsInternal: true},
}
)
func NewFSM1() MachineProvider {
machine := &testMachineFSM1{}
machine.FSM = fsm.MustNewFSM(
fsm1Name,
fsm1StateInit,
testing1Events,
fsm.Callbacks{
eventFSM1Init: machine.actionFSM1SetUpData,
eventFSM1InternalOut2: machine.actionFSM1EmitOut2,
eventFSM1Process: machine.actionFSM1ProcessData,
},
)
return machine
}
func (m *testMachineFSM1) actionFSM1SetUpData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
m.data = testVal1
return m.DoInternal(eventFSM1Internal)
}
func (m *testMachineFSM1) actionFSM1ProcessData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
if len(args) == 1 {
if val, ok := args[0].(int); ok {
m.data -= val
}
}
return m.data, nil
}
func (m *testMachineFSM1) actionFSM1EmitOut2(event fsm.Event, args ...interface{}) (response interface{}, err error) {
return
}
// Second test machine
type testMachineFSM2 struct {
*fsm.FSM
data int
}
const (
fsm2Name = "fsm2"
// Init process from global idle state
fsm2StateInit = fsm1StateOutToFSM2
// Process data
fsm2StateStage1 = fsm.State("state_fsm2_stage1")
fsm2StateStage2 = fsm.State("state_fsm2_stage2")
// Cancelled with internal event
fsm2StateCanceledByInternal = fsm.State("state_fsm2_canceled")
// Out endpoint to switch
fsm2StateOutToFSM3 = fsm.State("state_fsm2_out_to_fsm3")
// Events
eventFSM2Init = fsm.Event("event_fsm2_init")
eventFSM2Process = fsm.Event("event_fsm2_process")
// Internal events
eventFSM2Internal = fsm.Event("event_internal_fsm2")
eventFSM2CancelByInternal = fsm.Event("event_internal_fsm2_cancel")
eventFSM2InternalOut = fsm.Event("event_internal_fsm2_out")
)
var (
testing2Events = []fsm.EventDesc{
// Init
{Name: eventFSM2Init, SrcState: []fsm.State{fsm2StateInit}, DstState: fsm2StateStage1},
{Name: eventFSM2Internal, SrcState: []fsm.State{fsm2StateStage1}, DstState: fsm2StateStage2, IsInternal: true},
// Cancellation events
{Name: eventFSM2CancelByInternal, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm2StateCanceledByInternal, IsInternal: true},
// Out
{Name: eventFSM2Process, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm.StateGlobalDone},
{Name: eventFSM2InternalOut, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm.StateGlobalDone, IsInternal: true},
}
testing2Callbacks = fsm.Callbacks{}
)
func NewFSM2() MachineProvider {
machine := &testMachineFSM1{}
machine.FSM = fsm.MustNewFSM(
fsm2Name,
fsm2StateInit,
testing2Events,
testing2Callbacks,
)
return machine
}
func (m *testMachineFSM2) actionFSM2SetUpData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
return
}
func (m *testMachineFSM2) actionFSM2ProcessData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
return
}
func (m *testMachineFSM2) actionFSM2EmitOut2(event fsm.Event, args ...interface{}) (response interface{}, err error) {
return
}
var testPoolProvider *FSMPool
func init() {
testPoolProvider = Init(
NewFSM1(),
NewFSM2(),
)
}
func TestFSMPool_Init_EventsMap(t *testing.T) {
if len(testPoolProvider.events) == 0 {
t.Errorf("expected initialized events map")
}
}
func TestFSMPool_Init_StatesMap(t *testing.T) {
if len(testPoolProvider.states) == 0 {
t.Errorf("expected initialized states map")
}
}
func TestFSMPool_EntryPointMachine(t *testing.T) {
m, err := testPoolProvider.EntryPointMachine()
if err != nil || m.Name() != fsm1Name {
t.Errorf("expected entry point machine")
}
}
func TestFSMPool_MachineByState(t *testing.T) {
fsm1States := []fsm.State{
fsm1StateInit,
fsm1StateStage1,
fsm1StateStage2,
}
for _, state := range fsm1States {
machine, err := testPoolProvider.MachineByState(state)
if err != nil || machine.Name() != fsm1Name {
t.Errorf("expected machine fsm1 for state \"%s\"", state)
continue
}
}
fsm2States := []fsm.State{
fsm2StateInit,
fsm2StateStage1,
fsm2StateStage2,
}
for _, state := range fsm2States {
machine, err := testPoolProvider.MachineByState(state)
if err != nil || machine.Name() != fsm2Name {
t.Errorf("expected machine fsm2 for state \"%s\"", state)
continue
}
}
}
func TestFSMPool_MachineByEvent(t *testing.T) {
fsm1Events := []fsm.Event{
eventFSM1Init,
eventFSM1Cancel,
eventFSM1Process,
}
for _, event := range fsm1Events {
machine, err := testPoolProvider.MachineByEvent(event)
if err != nil || machine.Name() != fsm1Name {
t.Errorf("expected machine fsm1 for event \"%s\"", event)
continue
}
}
fsm2Events := []fsm.Event{
eventFSM2Init,
eventFSM2Process,
}
for _, event := range fsm2Events {
machine, err := testPoolProvider.MachineByEvent(event)
if err != nil || machine.Name() != fsm2Name {
t.Errorf("expected machine fsm2 for event \"%s\"", event)
continue
}
}
}
func TestFSMPool_WorkFlow(t *testing.T) {
machine, err := testPoolProvider.MachineByState(fsm1StateInit)
if err != nil || machine.Name() != fsm1Name {
t.Fatalf("expected machine fsm1 for state \"%s\"", fsm1StateInit)
}
if machine.State() != fsm1StateInit {
t.Fatalf("expected machine state \"%s\", got \"%s\"", fsm1StateInit, machine.State())
}
resp, err := machine.Do(eventFSM1Init)
if err != nil {
t.Fatalf("expected response without error, got \"%s\"", err)
}
if resp.State != fsm1StateStage2 {
t.Fatalf("expected machine state \"%s\", got \"%s\"", fsm1StateStage2, resp.State)
}
resp, err = machine.Do(eventFSM1Process, testVal2)
data, ok := resp.Data.(int)
if !ok {
t.Fatalf("expected response data int, got \"%s\"", resp.Data)
}
if data != (testVal1 - testVal2) {
t.Fatalf("expected response data value, got \"%d\"", data)
}
}

View File

@ -1 +0,0 @@
package dkg_commit_fsm

View File

@ -1 +0,0 @@
package dkg_deals_fsm

View File

@ -0,0 +1,54 @@
package dkg_proposal_fsm
import (
"github.com/depools/dc4bc/fsm/fsm"
"log"
)
// Pub keys
func (s *DKGProposalFSM) actionDKGPubKeysSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeysSent")
return
}
func (s *DKGProposalFSM) actionDKGPubKeyConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeyConfirmationReceived")
return
}
func (s *DKGProposalFSM) actionDKGPubKeyConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeyConfirmationError")
return
}
// Commits
func (s *DKGProposalFSM) actionDKGCommitsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitsSent")
return
}
func (s *DKGProposalFSM) actionDKGCommitConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitConfirmationReceived")
return
}
func (s *DKGProposalFSM) actionDKGCommitConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitConfirmationError")
return
}
// Deals
func (s *DKGProposalFSM) actionDKGDealsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealsSent")
return
}
func (s *DKGProposalFSM) actionDKGDealConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealConfirmationReceived")
return
}
func (s *DKGProposalFSM) actionDKGDealConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealConfirmationError")
return
}

View File

@ -1 +1,133 @@
package dkg_proposal_fsm
import (
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool"
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
)
const (
fsmName = "dkg_proposal_fsm"
StateDkgInitial = signature_proposal_fsm.StateValidationCompleted
// Sending dkg pub keys
StateDkgPubKeysSendingRequired = fsm.State("state_dkg_pub_keys_sending_required")
StateDkgPubKeysSendingAwaitConfirmations = fsm.State("state_dkg_pub_keys_sending_await_confirmations")
// Cancelled
StateDkgPubKeysSendingCancelled = fsm.State("state_dkg_pub_keys_sending_cancelled")
StateDkgPubKeysSendingCancelledByTimeout = fsm.State("state_dkg_pub_keys_sending_cancelled_by_timeout")
// Confirmed
StateDkgPubKeysSendingConfirmed = fsm.State("state_dkg_pub_keys_sending_confirmed")
// Sending dkg commits
StateDkgCommitsSendingRequired = fsm.State("state_dkg_commits_sending_required")
StateDkgCommitsSendingAwaitConfirmations = fsm.State("state_dkg_commits_sending_await_confirmations")
// Cancelled
StateDkgCommitsSendingCancelled = fsm.State("state_dkg_commits_sending_cancelled")
StateDkgCommitsSendingCancelledByTimeout = fsm.State("state_dkg_commits_sending_cancelled_by_timeout")
// Confirmed
StateDkgCommitsSendingConfirmed = fsm.State("state_dkg_commits_sending_confirmed")
// Sending dkg deals
StateDkgDealsSendingRequired = fsm.State("state_dkg_deals_sending_required")
StateDkgDealsSendingAwaitConfirmations = fsm.State("state_dkg_deals_sending_await_confirmations")
// Cancelled
StateDkgDealsSendingCancelled = fsm.State("state_dkg_deals_sending_cancelled")
StateDkgDealsSendingCancelledByTimeout = fsm.State("state_dkg_deals_sending_cancelled_by_timeout")
// Confirmed
StateDkgDealsSendingConfirmed = fsm.State("state_dkg_deals_sending_confirmed")
// Events
EventDKGPubKeysSendingRequiredInternal = fsm.Event("event_dkg_pub_key_sending_required_internal")
EventDKGPubKeysSent = fsm.Event("event_dkg_pub_keys_sent")
EventDKGPubKeyConfirmationReceived = fsm.Event("event_dkg_pub_key_confirm_received")
EventDKGPubKeyConfirmationError = fsm.Event("event_dkg_pub_key_confirm_canceled_by_error")
EventDKGPubKeysConfirmationCancelByTimeoutInternal = fsm.Event("event_dkg_pub_keys_confirm_canceled_by_timeout_internal")
EventDKGPubKeysConfirmedInternal = fsm.Event("event_dkg_pub_keys_confirmed_internal")
EventDKGCommitsSendingRequiredInternal = fsm.Event("event_dkg_commits_sending_required_internal")
EventDKGCommitsSent = fsm.Event("event_dkg_commits_sent")
EventDKGCommitConfirmationReceived = fsm.Event("event_dkg_commit_confirm_received")
EventDKGCommitConfirmationError = fsm.Event("event_dkg_commit_confirm_canceled_by_error")
EventDKGCommitsConfirmationCancelByTimeoutInternal = fsm.Event("event_dkg_commits_confirm_canceled_by_timeout_internal")
EventDKGCommitsConfirmedInternal = fsm.Event("event_dkg_commits_confirmed_internal")
EventDKGDealsSendingRequiredInternal = fsm.Event("event_dkg_deals_sending_required_internal")
EventDKGDealsSent = fsm.Event("event_dkg_deals_sent")
EventDKGDealConfirmationReceived = fsm.Event("event_dkg_deal_confirm_received")
EventDKGDealConfirmationError = fsm.Event("event_dkg_deal_confirm_canceled_by_error")
EventDKGDealsConfirmationCancelByTimeoutInternal = fsm.Event("event_dkg_deals_confirm_canceled_by_timeout_internal")
EventDKGMasterKeyRequiredInternal = fsm.Event("event_dkg_master_key_required_internal")
)
type DKGProposalFSM struct {
*fsm.FSM
}
func New() fsm_pool.MachineProvider {
machine := &DKGProposalFSM{}
machine.FSM = fsm.MustNewFSM(
fsmName,
StateDkgInitial,
[]fsm.EventDesc{
// Init
// Switch to pub keys required
{Name: EventDKGPubKeysSendingRequiredInternal, SrcState: []fsm.State{StateDkgInitial}, DstState: StateDkgPubKeysSendingRequired, IsInternal: true},
// Pub keys sending
{Name: EventDKGPubKeysSent, SrcState: []fsm.State{StateDkgPubKeysSendingRequired}, DstState: StateDkgPubKeysSendingAwaitConfirmations},
{Name: EventDKGPubKeyConfirmationReceived, SrcState: []fsm.State{StateDkgPubKeysSendingAwaitConfirmations}, DstState: StateDkgPubKeysSendingAwaitConfirmations},
// Cancelled
{Name: EventDKGPubKeyConfirmationError, SrcState: []fsm.State{StateDkgPubKeysSendingAwaitConfirmations}, DstState: StateDkgPubKeysSendingCancelled},
{Name: EventDKGPubKeysConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgPubKeysSendingAwaitConfirmations}, DstState: StateDkgPubKeysSendingCancelledByTimeout, IsInternal: true},
// Confirmed
{Name: EventDKGPubKeysConfirmedInternal, SrcState: []fsm.State{StateDkgPubKeysSendingAwaitConfirmations}, DstState: StateDkgPubKeysSendingConfirmed, IsInternal: true},
// Switch to commits required
{Name: EventDKGCommitsSendingRequiredInternal, SrcState: []fsm.State{StateDkgPubKeysSendingConfirmed}, DstState: StateDkgCommitsSendingRequired, IsInternal: true},
// Commits
{Name: EventDKGCommitsSent, SrcState: []fsm.State{StateDkgCommitsSendingRequired}, DstState: StateDkgCommitsSendingAwaitConfirmations},
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgCommitsSendingAwaitConfirmations},
// Cancelled
{Name: EventDKGCommitConfirmationError, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgCommitsSendingCancelled},
{Name: EventDKGCommitsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgCommitsSendingCancelledByTimeout, IsInternal: true},
// Confirmed
{Name: EventDKGCommitsConfirmedInternal, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgCommitsSendingConfirmed, IsInternal: true},
// Switch to deals required
{Name: EventDKGDealsSendingRequiredInternal, SrcState: []fsm.State{StateDkgDealsSendingConfirmed}, DstState: StateDkgDealsSendingRequired, IsInternal: true},
// Deals
{Name: EventDKGDealsSent, SrcState: []fsm.State{StateDkgDealsSendingRequired}, DstState: StateDkgDealsSendingAwaitConfirmations},
{Name: EventDKGDealConfirmationReceived, SrcState: []fsm.State{StateDkgDealsSendingAwaitConfirmations}, DstState: StateDkgDealsSendingAwaitConfirmations},
// Cancelled
{Name: EventDKGDealConfirmationError, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgDealsSendingCancelled},
{Name: EventDKGDealsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: StateDkgDealsSendingCancelledByTimeout, IsInternal: true},
// Done
{Name: EventDKGMasterKeyRequiredInternal, SrcState: []fsm.State{StateDkgCommitsSendingAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
},
fsm.Callbacks{
EventDKGPubKeysSent: machine.actionDKGPubKeysSent,
EventDKGPubKeyConfirmationReceived: machine.actionDKGPubKeyConfirmationReceived,
EventDKGPubKeyConfirmationError: machine.actionDKGPubKeyConfirmationError,
EventDKGCommitsSent: machine.actionDKGCommitsSent,
EventDKGCommitConfirmationReceived: machine.actionDKGCommitConfirmationReceived,
EventDKGCommitConfirmationError: machine.actionDKGCommitConfirmationError,
EventDKGDealsSent: machine.actionDKGDealsSent,
EventDKGDealConfirmationReceived: machine.actionDKGDealConfirmationReceived,
EventDKGDealConfirmationError: machine.actionDKGDealConfirmationError,
},
)
return machine
}

View File

@ -1,8 +1,8 @@
package internal
type MachineStatePayload struct {
ProposalPayload ProposalConfirmationPrivateQuorum
SigningPayload map[string]interface{}
ConfirmationProposalPayload ConfirmationProposalPrivateQuorum
DKGProposalPayload DKGProposalPrivateQuorum
}
// Using combine response for modify data with chain

View File

@ -4,8 +4,9 @@ import "time"
type ProposalParticipantPrivate struct {
// Public title for address, such as name, nickname, organization
Title string
PublicKey []byte
ParticipantId int
Title string
PublicKey []byte
// For validation user confirmation: sign(InvitationSecret, PublicKey) => user
InvitationSecret string
ConfirmedAt *time.Time
@ -14,4 +15,14 @@ type ProposalParticipantPrivate struct {
// Unique alias for map iteration - Public Key Fingerprint
// Excludes array merge and rotate operations
type ProposalConfirmationPrivateQuorum map[string]ProposalParticipantPrivate
type ConfirmationProposalPrivateQuorum map[string]ProposalParticipantPrivate
type ProposalDKGParticipantPrivate struct {
Title string
PublicKey []byte
Commit []byte
Deal []byte
UpdatedAt *time.Time
}
type DKGProposalPrivateQuorum map[int]ProposalParticipantPrivate

View File

@ -3,11 +3,11 @@ package state_machines
import (
"encoding/json"
"errors"
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool"
"github.com/depools/dc4bc/fsm/state_machines/internal"
"github.com/depools/dc4bc/fsm/state_machines/signature_construct_fsm"
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
)
@ -30,7 +30,7 @@ var (
func init() {
fsmPoolProvider = fsm_pool.Init(
signature_proposal_fsm.New(),
signature_construct_fsm.New(),
dkg_proposal_fsm.New(),
)
}

View File

@ -1,39 +0,0 @@
package signature_construct_fsm
import (
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool"
)
const (
fsmName = "signature_construct_fsm"
stateConstructorEntryPoint = "process_sig"
awaitConstructor = "validate_process_sig" // waiting participants
eventInitSignatureConstructor = "process_sig_init"
eventInitSignatureFinishTmp = "process_sig_fin"
)
type SignatureConstructFSM struct {
*fsm.FSM
}
func New() fsm_pool.MachineProvider {
machine := &SignatureConstructFSM{}
machine.FSM = fsm.MustNewFSM(
fsmName,
stateConstructorEntryPoint,
[]fsm.EventDesc{
// {Name: "", SrcState: []string{""}, DstState: ""},
// Init
{Name: eventInitSignatureConstructor, SrcState: []fsm.State{stateConstructorEntryPoint}, DstState: awaitConstructor},
{Name: eventInitSignatureFinishTmp, SrcState: []fsm.State{awaitConstructor}, DstState: "dkg_proposal_fsm"},
},
fsm.Callbacks{},
)
return machine
}

View File

@ -45,7 +45,7 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
return
}
request, ok := args[2].(requests.ProposalParticipantsListRequest)
request, ok := args[2].(requests.SignatureProposalParticipantsListRequest)
if !ok {
err = errors.New("cannot cast participants list")
@ -56,15 +56,16 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
return
}
payload.ProposalPayload = make(internal.ProposalConfirmationPrivateQuorum)
payload.ConfirmationProposalPayload = make(internal.ConfirmationProposalPrivateQuorum)
for _, participant := range request {
for participantIntId, participant := range request {
participantId := createFingerprint(&participant.PublicKey)
secret, err := generateRandomString(32)
if err != nil {
return nil, errors.New("cannot generateRandomString")
}
payload.ProposalPayload[participantId] = internal.ProposalParticipantPrivate{
payload.ConfirmationProposalPayload[participantId] = internal.ProposalParticipantPrivate{
ParticipantId: participantIntId,
Title: participant.Title,
PublicKey: participant.PublicKey,
InvitationSecret: secret,
@ -74,16 +75,16 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
// Make response
responseData := make(responses.ProposalParticipantInvitationsResponse, 0)
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
for participantId, proposal := range payload.ProposalPayload {
for pubKeyFingerprint, proposal := range payload.ConfirmationProposalPayload {
encryptedInvitationSecret, err := encryptWithPubKey(proposal.PublicKey, proposal.InvitationSecret)
if err != nil {
return nil, errors.New("cannot encryptWithPubKey")
}
responseEntry := &responses.ProposalParticipantInvitationEntryResponse{
responseEntry := &responses.SignatureProposalParticipantInvitationEntry{
Title: proposal.Title,
PubKeyFingerprint: participantId,
PubKeyFingerprint: pubKeyFingerprint,
EncryptedInvitation: encryptedInvitationSecret,
}
responseData = append(responseData, responseEntry)

View File

@ -11,10 +11,10 @@ import (
// Request and response mutators
func ProposalParticipantsQuorumToResponse(list *internal.ProposalConfirmationPrivateQuorum) responses.ProposalParticipantInvitationsResponse {
var response responses.ProposalParticipantInvitationsResponse
func ProposalParticipantsQuorumToResponse(list *internal.ConfirmationProposalPrivateQuorum) responses.SignatureProposalParticipantInvitationsResponse {
var response responses.SignatureProposalParticipantInvitationsResponse
for quorumId, parcipant := range *list {
response = append(response, &responses.ProposalParticipantInvitationEntryResponse{
response = append(response, &responses.SignatureProposalParticipantInvitationEntry{
Title: parcipant.Title,
PubKeyFingerprint: quorumId,
// TODO: Add encryption

View File

@ -9,21 +9,23 @@ const (
fsmName = "signature_proposal_fsm"
signingIdLen = 32
stateAwaitProposalConfirmation = fsm.State("validate_proposal") // waiting participants
StateAwaitParticipantsConfirmations = fsm.State("state_validation_await_participants_confirmations") // waiting participants
stateValidationCanceledByParticipant = fsm.State("validation_canceled_by_participant")
stateValidationCanceledByTimeout = fsm.State("validation_canceled_by_timeout")
StateValidationCanceledByParticipant = fsm.State("state_validation_canceled_by_participant")
StateValidationCanceledByTimeout = fsm.State("state_validation_canceled_by_timeout")
stateProposed = "proposed"
StateValidationCompleted = fsm.State("state_validation_completed")
eventInitProposal = fsm.Event("proposal_init")
eventConfirmProposal = fsm.Event("proposal_confirm_by_participant")
eventDeclineProposal = fsm.Event("proposal_decline_by_participant")
eventValidateProposal = fsm.Event("proposal_validate")
eventSetProposalValidated = fsm.Event("proposal_set_validated")
EventInitProposal = fsm.Event("event_proposal_init")
EventConfirmProposal = fsm.Event("event_proposal_confirm_by_participant")
EventDeclineProposal = fsm.Event("event_proposal_decline_by_participant")
EventValidateProposal = fsm.Event("event_proposal_validate")
EventSetProposalValidated = fsm.Event("event_proposal_set_validated")
eventSetValidationCanceledByTimeout = fsm.Event("proposal_canceled_timeout")
eventSwitchProposedToSigning = fsm.Event("switch_state_to_signing")
// Switch to next fsm
)
type SignatureProposalFSM struct {
@ -40,28 +42,28 @@ func New() fsm_pool.MachineProvider {
// {Name: "", SrcState: []string{""}, DstState: ""},
// Init
{Name: eventInitProposal, SrcState: []fsm.State{fsm.StateGlobalIdle}, DstState: stateAwaitProposalConfirmation},
{Name: EventInitProposal, SrcState: []fsm.State{fsm.StateGlobalIdle}, DstState: StateAwaitParticipantsConfirmations},
// Validate by participants
{Name: eventConfirmProposal, SrcState: []fsm.State{stateAwaitProposalConfirmation}, DstState: stateAwaitProposalConfirmation},
{Name: EventConfirmProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
// Is decline event should auto change state to default, or it process will initiated by client (external emit)?
// Now set for external emitting.
{Name: eventDeclineProposal, SrcState: []fsm.State{stateAwaitProposalConfirmation}, DstState: stateValidationCanceledByParticipant},
{Name: EventDeclineProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateValidationCanceledByParticipant},
{Name: eventValidateProposal, SrcState: []fsm.State{stateAwaitProposalConfirmation}, DstState: stateAwaitProposalConfirmation},
{Name: EventValidateProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
// eventProposalValidate internal or from client?
// yay
// Exit point
{Name: eventSetProposalValidated, SrcState: []fsm.State{stateAwaitProposalConfirmation}, DstState: "process_sig", IsInternal: true},
{Name: EventSetProposalValidated, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: fsm.State("state_dkg_pub_keys_sending_required"), IsInternal: true},
// nan
{Name: eventSetValidationCanceledByTimeout, SrcState: []fsm.State{stateAwaitProposalConfirmation}, DstState: stateValidationCanceledByTimeout, IsInternal: true},
{Name: eventSetValidationCanceledByTimeout, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateValidationCanceledByTimeout, IsInternal: true},
},
fsm.Callbacks{
eventInitProposal: machine.actionInitProposal,
eventConfirmProposal: machine.actionConfirmProposalByParticipant,
eventDeclineProposal: machine.actionDeclineProposalByParticipant,
eventValidateProposal: machine.actionValidateProposal,
EventInitProposal: machine.actionInitProposal,
EventConfirmProposal: machine.actionConfirmProposalByParticipant,
EventDeclineProposal: machine.actionDeclineProposalByParticipant,
EventValidateProposal: machine.actionValidateProposal,
},
)
return machine

View File

@ -0,0 +1,16 @@
package requests
// Event: "event_dkg_pub_keys_sent"
type DKGProposalPubKeysSendingRequest struct {
PubKeys map[int][]byte
}
// Event: "event_dkg_commits_sent"
type DKGProposalCommitsSendingRequest struct {
Commits map[int][]byte
}
// Event: "event_dkg_deals_sent"
type DKGProposalDealsSendingRequest struct {
Deals map[int][]byte
}

View File

@ -0,0 +1 @@
package requests

View File

@ -1,49 +1,17 @@
package requests
import (
"errors"
"github.com/depools/dc4bc/fsm/config"
)
// Requests
type ProposalParticipantsListRequest []ProposalParticipantsEntryRequest
type SignatureProposalParticipantsListRequest []SignatureProposalParticipantsEntry
type ProposalParticipantsEntryRequest struct {
type SignatureProposalParticipantsEntry struct {
// Public title for address, such as name, nickname, organization
Title string
PublicKey []byte
}
func (r *ProposalParticipantsListRequest) Validate() error {
if len(*r) < config.ParticipantsMinCount {
return errors.New("too few participants")
}
for _, participant := range *r {
if len(participant.Title) < 3 {
return errors.New("title too short")
}
if len(participant.Title) > 150 {
return errors.New("title too long")
}
if len(participant.PublicKey) < 10 {
return errors.New("pub key too short")
}
}
return nil
}
type ProposalParticipantConfirmationRequest struct {
// Public title for address, such as name, nickname, organization
ParticipantId string
type SignatureProposalParticipantRequest struct {
// Key for link invitations to participants
PubKeyFingerprint string
EncryptedInvitation string
}
func (r *ProposalParticipantConfirmationRequest) Validate() error {
return nil
}

View File

@ -0,0 +1,32 @@
package requests
import (
"errors"
"github.com/depools/dc4bc/fsm/config"
)
func (r *SignatureProposalParticipantsListRequest) Validate() error {
if len(*r) < config.ParticipantsMinCount {
return errors.New("too few participants")
}
for _, participant := range *r {
if len(participant.Title) < 3 {
return errors.New("title too short")
}
if len(participant.Title) > 150 {
return errors.New("title too long")
}
if len(participant.PublicKey) < 10 {
return errors.New("pub key too short")
}
}
return nil
}
func (r *SignatureProposalParticipantRequest) Validate() error {
return nil
}

View File

@ -0,0 +1,25 @@
package responses
type DKGProposalPubKeyParticipantResponse []*DKGProposalPubKeyParticipantEntry
type DKGProposalPubKeyParticipantEntry struct {
ParticipantId int
Title string
PubKey []byte
}
type DKGProposalCommitParticipantResponse []*DKGProposalCommitParticipantEntry
type DKGProposalCommitParticipantEntry struct {
ParticipantId int
Title string
Commit []byte
}
type DKGProposalDealParticipantResponse []*DKGProposalDealParticipantEntry
type DKGProposalDealParticipantEntry struct {
ParticipantId int
Title string
Deal []byte
}

View File

@ -2,9 +2,19 @@ package responses
// Responses
type ProposalParticipantInvitationsResponse []*ProposalParticipantInvitationEntryResponse
const (
ProposalConfirmationStatusIdle = iota
ProposalConfirmationStatusAccepted
ProposalConfirmationStatusCanceled
ProposalConfirmationStatusTimeout
)
type ProposalParticipantInvitationEntryResponse struct {
// States: "validate_proposal"
type SignatureProposalParticipantInvitationsResponse []*SignatureProposalParticipantInvitationEntry
type SignatureProposalParticipantInvitationEntry struct {
ParticipantId int
// Public title for address, such as name, nickname, organization
Title string
// Key for link invitations to participants
@ -12,3 +22,14 @@ type ProposalParticipantInvitationEntryResponse struct {
// Encrypted with public key secret
EncryptedInvitation string
}
// Public lists for proposal confirmation process
// States: "validation_canceled_by_participant", "validation_canceled_by_timeout",
type SignatureProposalParticipantStatusResponse []*SignatureProposalParticipantStatusEntry
type SignatureProposalParticipantStatusEntry struct {
ParticipantId int
Title string
PubKeyFingerprint string
Status int
}