mirror of https://github.com/certusone/dc4bc.git
feat: updated flow
This commit is contained in:
parent
4ed9afc8dd
commit
33ecea0a9a
138
fsm/fsm/fsm.go
138
fsm/fsm/fsm.go
|
@ -41,7 +41,7 @@ func (e *Event) String() string {
|
||||||
return string(*e)
|
return string(*e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Event) IsEmpty() bool {
|
func (e Event) IsEmpty() bool {
|
||||||
return e.String() == ""
|
return e.String() == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ type FSM struct {
|
||||||
// May be mapping must require pair source + event?
|
// May be mapping must require pair source + event?
|
||||||
transitions map[trKey]*trEvent
|
transitions map[trKey]*trEvent
|
||||||
|
|
||||||
autoTransitions map[State]*trEvent
|
autoTransitions map[trAutoKeyEvent]*trEvent
|
||||||
|
|
||||||
callbacks Callbacks
|
callbacks Callbacks
|
||||||
|
|
||||||
|
@ -94,6 +94,11 @@ type trEvent struct {
|
||||||
runMode EventRunMode
|
runMode EventRunMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type trAutoKeyEvent struct {
|
||||||
|
state State
|
||||||
|
runMode EventRunMode
|
||||||
|
}
|
||||||
|
|
||||||
type EventDesc struct {
|
type EventDesc struct {
|
||||||
Name Event
|
Name Event
|
||||||
|
|
||||||
|
@ -138,7 +143,7 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
||||||
currentState: initialState,
|
currentState: initialState,
|
||||||
initialState: initialState,
|
initialState: initialState,
|
||||||
transitions: make(map[trKey]*trEvent),
|
transitions: make(map[trKey]*trEvent),
|
||||||
autoTransitions: make(map[State]*trEvent),
|
autoTransitions: make(map[trAutoKeyEvent]*trEvent),
|
||||||
finStates: make(map[State]bool),
|
finStates: make(map[State]bool),
|
||||||
callbacks: make(map[Event]Callback),
|
callbacks: make(map[Event]Callback),
|
||||||
}
|
}
|
||||||
|
@ -217,14 +222,15 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
||||||
panic("{AutoRunMode} not set for auto event")
|
panic("{AutoRunMode} not set for auto event")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := f.autoTransitions[sourceState]; ok {
|
trAutoKey := trAutoKeyEvent{sourceState, event.AutoRunMode}
|
||||||
|
if _, ok := f.autoTransitions[trAutoKey]; ok {
|
||||||
panic(fmt.Sprintf(
|
panic(fmt.Sprintf(
|
||||||
"auto event \"%s\" already exists for state \"%s\"",
|
"auto event \"%s\" already exists for state \"%s\"",
|
||||||
event.Name,
|
event.Name,
|
||||||
sourceState,
|
sourceState,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
f.autoTransitions[sourceState] = trEvent
|
f.autoTransitions[trAutoKey] = trEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
allSources[sourceState] = true
|
allSources[sourceState] = true
|
||||||
|
@ -247,7 +253,7 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := allEvents[event]; !ok {
|
if _, ok := allEvents[event]; !ok {
|
||||||
panic("callback has empty event")
|
panic(fmt.Sprintf("callback has unused event \"%s\"", event))
|
||||||
}
|
}
|
||||||
|
|
||||||
f.callbacks[event] = callback
|
f.callbacks[event] = callback
|
||||||
|
@ -273,7 +279,7 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
||||||
func (f *FSM) DoInternal(event Event, args ...interface{}) (resp *Response, err error) {
|
func (f *FSM) DoInternal(event Event, args ...interface{}) (resp *Response, err error) {
|
||||||
trEvent, ok := f.transitions[trKey{f.currentState, event}]
|
trEvent, ok := f.transitions[trKey{f.currentState, event}]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprintf("cannot execute event \"%s\" for state \"%s\"", event, f.currentState))
|
return nil, errors.New(fmt.Sprintf("cannot execute internal event \"%s\" for state \"%s\"", event, f.currentState))
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.do(trEvent, args...)
|
return f.do(trEvent, args...)
|
||||||
|
@ -290,41 +296,55 @@ func (f *FSM) Do(event Event, args ...interface{}) (resp *Response, err error) {
|
||||||
|
|
||||||
return f.do(trEvent, args...)
|
return f.do(trEvent, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check and execute auto event
|
||||||
|
func (f *FSM) processAutoEvent(mode EventRunMode, args ...interface{}) (exists bool, outEvent Event, response interface{}, err error) {
|
||||||
|
autoEvent, exists := f.autoTransitions[trAutoKeyEvent{f.State(), mode}]
|
||||||
|
if !exists {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.isCallbackExists(autoEvent.event) {
|
||||||
|
outEvent, response, err = f.execCallback(autoEvent.event, args...)
|
||||||
|
// Do not try change state on error
|
||||||
|
if err != nil {
|
||||||
|
return exists, "", response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if outEvent.IsEmpty() || autoEvent.event == outEvent {
|
||||||
|
err = f.SetState(autoEvent.event)
|
||||||
|
} else {
|
||||||
|
err = f.SetState(outEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err error) {
|
func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err error) {
|
||||||
var outEvent Event
|
var outEvent Event
|
||||||
// f.eventMu.Lock()
|
// f.eventMu.Lock()
|
||||||
// defer f.eventMu.Unlock()
|
// defer f.eventMu.Unlock()
|
||||||
|
|
||||||
|
resp = &Response{}
|
||||||
|
|
||||||
// Process auto event
|
// Process auto event
|
||||||
if autoEvent, ok := f.autoTransitions[f.State()]; ok {
|
isAutoEventExecuted, outEvent, data, err := f.processAutoEvent(EventRunBefore, args...)
|
||||||
autoEventResp := &Response{
|
|
||||||
State: f.State(),
|
if isAutoEventExecuted {
|
||||||
|
resp.State = f.State()
|
||||||
|
if data != nil {
|
||||||
|
resp.Data = data
|
||||||
}
|
}
|
||||||
if autoEvent.runMode == EventRunBefore {
|
|
||||||
if callback, ok := f.callbacks[autoEvent.event]; ok {
|
if err != nil {
|
||||||
outEvent, autoEventResp.Data, err = callback(autoEvent.event, args...)
|
return resp, err
|
||||||
if err != nil {
|
|
||||||
return autoEventResp, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if outEvent.IsEmpty() || autoEvent.event == outEvent {
|
|
||||||
err = f.SetState(autoEvent.event)
|
|
||||||
} else {
|
|
||||||
err = f.SetState(outEvent)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return autoEventResp, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
outEvent = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = &Response{
|
if f.isCallbackExists(trEvent.event) {
|
||||||
State: f.State(),
|
outEvent, resp.Data, err = f.execCallback(trEvent.event, args...)
|
||||||
}
|
|
||||||
|
|
||||||
if callback, ok := f.callbacks[trEvent.event]; ok {
|
|
||||||
outEvent, resp.Data, err = callback(trEvent.event, args...)
|
|
||||||
// Do not try change state on error
|
// Do not try change state on error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
|
@ -334,36 +354,32 @@ func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err err
|
||||||
// Set state when callback executed
|
// Set state when callback executed
|
||||||
if outEvent.IsEmpty() || trEvent.event == outEvent {
|
if outEvent.IsEmpty() || trEvent.event == outEvent {
|
||||||
err = f.SetState(trEvent.event)
|
err = f.SetState(trEvent.event)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err = f.SetState(outEvent)
|
err = f.SetState(outEvent)
|
||||||
}
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
// Process auto event
|
|
||||||
if autoEvent, ok := f.autoTransitions[f.State()]; ok {
|
|
||||||
autoEventResp := &Response{
|
|
||||||
State: f.State(),
|
|
||||||
}
|
}
|
||||||
if autoEvent.runMode == EventRunAfter {
|
|
||||||
if callback, ok := f.callbacks[autoEvent.event]; ok {
|
|
||||||
outEvent, autoEventResp.Data, err = callback(autoEvent.event, args...)
|
|
||||||
if err != nil {
|
|
||||||
return autoEventResp, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if outEvent.IsEmpty() || autoEvent.event == outEvent {
|
|
||||||
err = f.SetState(autoEvent.event)
|
|
||||||
} else {
|
|
||||||
err = f.SetState(outEvent)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return autoEventResp, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outEvent = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.State = f.State()
|
resp.State = f.State()
|
||||||
|
|
||||||
|
// Process auto event
|
||||||
|
isAutoEventExecuted, outEvent, data, err = f.processAutoEvent(EventRunAfter, args...)
|
||||||
|
|
||||||
|
if isAutoEventExecuted {
|
||||||
|
resp.State = f.State()
|
||||||
|
if data != nil {
|
||||||
|
resp.Data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +398,7 @@ func (f *FSM) SetState(event Event) error {
|
||||||
|
|
||||||
trEvent, ok := f.transitions[trKey{f.currentState, event}]
|
trEvent, ok := f.transitions[trKey{f.currentState, event}]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New(fmt.Sprintf("cannot execute event \"%s\" for state \"%s\"", event, f.currentState))
|
return errors.New(fmt.Sprintf("cannot set state by event \"%s\" for state \"%s\"", event, f.currentState))
|
||||||
}
|
}
|
||||||
|
|
||||||
f.currentState = trEvent.dstState
|
f.currentState = trEvent.dstState
|
||||||
|
@ -457,6 +473,16 @@ func (f *FSM) StatesSourcesList() (states []State) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FSM) isCallbackExists(event Event) bool {
|
||||||
|
_, exists := f.callbacks[event]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FSM) execCallback(event Event, args ...interface{}) (Event, interface{}, error) {
|
||||||
|
callback, _ := f.callbacks[event]
|
||||||
|
return callback(event, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FSM) IsFinState(state State) bool {
|
func (f *FSM) IsFinState(state State) bool {
|
||||||
_, exists := f.finStates[state]
|
_, exists := f.finStates[state]
|
||||||
return exists
|
return exists
|
||||||
|
|
|
@ -160,17 +160,3 @@ func (p *FSMPool) MachineByState(state fsm.State) (MachineProvider, error) {
|
||||||
}
|
}
|
||||||
return machine, nil
|
return machine, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (p *FSMPool) Do(machine MachineProvider, event fsm.Event, args ...interface{}) (resp *fsm.Response, err error) {
|
|
||||||
panic("llslsl")
|
|
||||||
resp, err = machine.Do(event, args...)
|
|
||||||
if err != nil {
|
|
||||||
return resp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if machine.IsFinState(resp.State) {
|
|
||||||
log.Println("Final!!!!")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -11,94 +11,27 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pub keys
|
// Init
|
||||||
|
|
||||||
func (m *DKGProposalFSM) actionPubKeyConfirmationReceived(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
func (m *DKGProposalFSM) actionInitDKGProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||||
m.payloadMu.Lock()
|
if m.payload.DKGProposalPayload != nil {
|
||||||
defer m.payloadMu.Unlock()
|
|
||||||
|
|
||||||
if len(args) != 1 {
|
|
||||||
err = errors.New("{arg0} required {DKGProposalPubKeyConfirmationRequest}")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
request, ok := args[0].(requests.DKGProposalPubKeyConfirmationRequest)
|
m.payload.DKGProposalPayload = &internal.DKGConfirmation{
|
||||||
|
Quorum: make(internal.DKGProposalQuorum),
|
||||||
if !ok {
|
|
||||||
err = errors.New("cannot cast {arg0} to type {DKGProposalPubKeyConfirmationRequest}")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = request.Validate(); err != nil {
|
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
||||||
return
|
m.payload.DKGProposalPayload.Quorum[participant.ParticipantId] = &internal.DKGProposalParticipant{
|
||||||
}
|
Title: participant.Title,
|
||||||
|
Status: internal.CommitAwaitConfirmation,
|
||||||
if !m.payload.DKGQuorumExists(request.ParticipantId) {
|
UpdatedAt: participant.UpdatedAt,
|
||||||
err = errors.New("{ParticipantId} not exist in quorum")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dkgProposalParticipant := m.payload.DKGQuorumGet(request.ParticipantId)
|
|
||||||
|
|
||||||
if dkgProposalParticipant.Status != internal.PubKeyAwaitConfirmation {
|
|
||||||
err = errors.New(fmt.Sprintf("cannot confirm pubkey with {Status} = {\"%s\"}", dkgProposalParticipant.Status))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(dkgProposalParticipant.PubKey, request.PubKey)
|
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
|
||||||
dkgProposalParticipant.Status = internal.PubKeyConfirmed
|
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DKGProposalFSM) actionValidateDkgProposalPubKeys(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
|
||||||
var (
|
|
||||||
isContainsError, isContainsExpired bool
|
|
||||||
)
|
|
||||||
|
|
||||||
m.payloadMu.Lock()
|
|
||||||
defer m.payloadMu.Unlock()
|
|
||||||
|
|
||||||
tm := time.Now()
|
|
||||||
|
|
||||||
unconfirmedParticipants := m.payload.DKGQuorumCount()
|
|
||||||
for _, participant := range m.payload.DKGProposalPayload.Quorum {
|
|
||||||
if participant.Status == internal.PubKeyAwaitConfirmation {
|
|
||||||
if participant.UpdatedAt.Add(config.DkgConfirmationDeadline).Before(tm) {
|
|
||||||
isContainsExpired = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if participant.Status == internal.PubKeyConfirmationError {
|
|
||||||
isContainsError = true
|
|
||||||
} else if participant.Status == internal.PubKeyConfirmed {
|
|
||||||
unconfirmedParticipants--
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
copy(m.payload.DKGProposalPayload.Quorum[participant.ParticipantId].PubKey, participant.DkgPubKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isContainsError {
|
// Remove m.payload.SignatureProposalPayload?
|
||||||
outEvent = eventDKGSetPubKeysConfirmationCanceledByErrorInternal
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if isContainsExpired {
|
|
||||||
outEvent = eventDKGSetPubKeysConfirmationCanceledByTimeoutInternal
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// The are no declined and timed out participants, check for all confirmations
|
|
||||||
if unconfirmedParticipants > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
outEvent = eventDKGSetPubKeysConfirmedInternal
|
|
||||||
|
|
||||||
for _, participant := range m.payload.DKGProposalPayload.Quorum {
|
|
||||||
participant.Status = internal.CommitAwaitConfirmation
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -138,7 +71,7 @@ func (m *DKGProposalFSM) actionCommitConfirmationReceived(inEvent fsm.Event, arg
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(dkgProposalParticipant.Commit, request.Commit)
|
copy(dkgProposalParticipant.Commit, request.Commit)
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
dkgProposalParticipant.UpdatedAt = request.CreatedAt
|
||||||
dkgProposalParticipant.Status = internal.CommitConfirmed
|
dkgProposalParticipant.Status = internal.CommitConfirmed
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
||||||
|
@ -230,7 +163,7 @@ func (m *DKGProposalFSM) actionDealConfirmationReceived(inEvent fsm.Event, args
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(dkgProposalParticipant.Deal, request.Deal)
|
copy(dkgProposalParticipant.Deal, request.Deal)
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
dkgProposalParticipant.UpdatedAt = request.CreatedAt
|
||||||
dkgProposalParticipant.Status = internal.DealConfirmed
|
dkgProposalParticipant.Status = internal.DealConfirmed
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
||||||
|
@ -322,7 +255,7 @@ func (m *DKGProposalFSM) actionResponseConfirmationReceived(inEvent fsm.Event, a
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(dkgProposalParticipant.Response, request.Response)
|
copy(dkgProposalParticipant.Response, request.Response)
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
dkgProposalParticipant.UpdatedAt = request.CreatedAt
|
||||||
dkgProposalParticipant.Status = internal.ResponseConfirmed
|
dkgProposalParticipant.Status = internal.ResponseConfirmed
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
||||||
|
@ -414,7 +347,7 @@ func (m *DKGProposalFSM) actionMasterKeyConfirmationReceived(inEvent fsm.Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(dkgProposalParticipant.MasterKey, request.MasterKey)
|
copy(dkgProposalParticipant.MasterKey, request.MasterKey)
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
dkgProposalParticipant.UpdatedAt = request.CreatedAt
|
||||||
dkgProposalParticipant.Status = internal.MasterKeyConfirmed
|
dkgProposalParticipant.Status = internal.MasterKeyConfirmed
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
||||||
|
@ -525,21 +458,6 @@ func (m *DKGProposalFSM) actionConfirmationError(inEvent fsm.Event, args ...inte
|
||||||
|
|
||||||
// TODO: Move to methods
|
// TODO: Move to methods
|
||||||
switch inEvent {
|
switch inEvent {
|
||||||
case EventDKGPubKeyConfirmationError:
|
|
||||||
switch dkgProposalParticipant.Status {
|
|
||||||
case internal.PubKeyAwaitConfirmation:
|
|
||||||
dkgProposalParticipant.Status = internal.PubKeyConfirmationError
|
|
||||||
case internal.PubKeyConfirmed:
|
|
||||||
err = errors.New("{Status} already confirmed")
|
|
||||||
case internal.PubKeyConfirmationError:
|
|
||||||
err = errors.New(fmt.Sprintf("{Status} already has {\"%s\"}", internal.PubKeyConfirmationError))
|
|
||||||
default:
|
|
||||||
err = errors.New(fmt.Sprintf(
|
|
||||||
"{Status} now is \"%s\" and cannot set to {\"%s\"}",
|
|
||||||
dkgProposalParticipant.Status,
|
|
||||||
internal.PubKeyConfirmationError,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
case EventDKGCommitConfirmationError:
|
case EventDKGCommitConfirmationError:
|
||||||
switch dkgProposalParticipant.Status {
|
switch dkgProposalParticipant.Status {
|
||||||
case internal.CommitAwaitConfirmation:
|
case internal.CommitAwaitConfirmation:
|
||||||
|
@ -609,7 +527,7 @@ func (m *DKGProposalFSM) actionConfirmationError(inEvent fsm.Event, args ...inte
|
||||||
}
|
}
|
||||||
|
|
||||||
dkgProposalParticipant.Error = request.Error
|
dkgProposalParticipant.Error = request.Error
|
||||||
dkgProposalParticipant.UpdatedAt = &request.CreatedAt
|
dkgProposalParticipant.UpdatedAt = request.CreatedAt
|
||||||
|
|
||||||
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
m.payload.DKGQuorumUpdate(request.ParticipantId, dkgProposalParticipant)
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,7 @@ import (
|
||||||
const (
|
const (
|
||||||
FsmName = "dkg_proposal_fsm"
|
FsmName = "dkg_proposal_fsm"
|
||||||
|
|
||||||
StateDkgInitial = StateDkgPubKeysAwaitConfirmations
|
StateDkgInitial = StateDkgCommitsAwaitConfirmations
|
||||||
|
|
||||||
StateDkgPubKeysAwaitConfirmations = fsm.State("state_dkg_pub_keys_await_confirmations")
|
|
||||||
// Canceled
|
|
||||||
StateDkgPubKeysAwaitCanceled = fsm.State("state_dkg_pub_keys_await_canceled")
|
|
||||||
StateDkgPubKeysAwaitCanceledByTimeout = fsm.State("state_dkg_pub_keys_await_canceled_by_timeout")
|
|
||||||
// Confirmed
|
|
||||||
// StateDkgPubKeysAwaitConfirmed = fsm.State("state_dkg_pub_keys_await_confirmed")
|
|
||||||
|
|
||||||
// Sending dkg commits
|
// Sending dkg commits
|
||||||
StateDkgCommitsAwaitConfirmations = fsm.State("state_dkg_commits_await_confirmations")
|
StateDkgCommitsAwaitConfirmations = fsm.State("state_dkg_commits_await_confirmations")
|
||||||
|
@ -24,7 +17,7 @@ const (
|
||||||
StateDkgCommitsAwaitCanceled = fsm.State("state_dkg_commits_await_canceled")
|
StateDkgCommitsAwaitCanceled = fsm.State("state_dkg_commits_await_canceled")
|
||||||
StateDkgCommitsAwaitCanceledByTimeout = fsm.State("state_dkg_commits_await_canceled_by_timeout")
|
StateDkgCommitsAwaitCanceledByTimeout = fsm.State("state_dkg_commits_await_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
StateDkgCommitsAwaitConfirmed = fsm.State("state_dkg_commits_await_confirmed")
|
StateDkgCommitsCollected = fsm.State("state_dkg_commits_collected")
|
||||||
|
|
||||||
// Sending dkg deals
|
// Sending dkg deals
|
||||||
StateDkgDealsAwaitConfirmations = fsm.State("state_dkg_deals_await_confirmations")
|
StateDkgDealsAwaitConfirmations = fsm.State("state_dkg_deals_await_confirmations")
|
||||||
|
@ -32,31 +25,23 @@ const (
|
||||||
StateDkgDealsAwaitCanceled = fsm.State("state_dkg_deals_await_canceled")
|
StateDkgDealsAwaitCanceled = fsm.State("state_dkg_deals_await_canceled")
|
||||||
StateDkgDealsAwaitCanceledByTimeout = fsm.State("state_dkg_deals_await_canceled_by_timeout")
|
StateDkgDealsAwaitCanceledByTimeout = fsm.State("state_dkg_deals_await_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
//StateDkgDealsAwaitConfirmed = fsm.State("state_dkg_deals_await_confirmed")
|
//StateDkgDealsCollected = fsm.State("state_dkg_deals_collected")
|
||||||
|
|
||||||
StateDkgResponsesAwaitConfirmations = fsm.State("state_dkg_responses_await_confirmations")
|
StateDkgResponsesAwaitConfirmations = fsm.State("state_dkg_responses_await_confirmations")
|
||||||
// Canceled
|
// Canceled
|
||||||
StateDkgResponsesAwaitCanceled = fsm.State("state_dkg_responses_await_canceled")
|
StateDkgResponsesAwaitCanceled = fsm.State("state_dkg_responses_await_canceled")
|
||||||
StateDkgResponsesAwaitCanceledByTimeout = fsm.State("state_dkg_responses_sending_canceled_by_timeout")
|
StateDkgResponsesAwaitCanceledByTimeout = fsm.State("state_dkg_responses_sending_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
StateDkgResponsesAwaitConfirmed = fsm.State("state_dkg_responses_await_confirmed")
|
StateDkgResponsesCollected = fsm.State("state_dkg_responses_collected")
|
||||||
|
|
||||||
StateDkgMasterKeyAwaitConfirmations = fsm.State("state_dkg_master_key_await_confirmations")
|
StateDkgMasterKeyAwaitConfirmations = fsm.State("state_dkg_master_key_await_confirmations")
|
||||||
StateDkgMasterKeyAwaitCanceled = fsm.State("state_dkg_master_key_await_canceled")
|
StateDkgMasterKeyAwaitCanceled = fsm.State("state_dkg_master_key_await_canceled")
|
||||||
StateDkgMasterKeyAwaitCanceledByTimeout = fsm.State("state_dkg_master_key_await_canceled_by_timeout")
|
StateDkgMasterKeyAwaitCanceledByTimeout = fsm.State("state_dkg_master_key_await_canceled_by_timeout")
|
||||||
|
|
||||||
|
StateDkgMasterKeyCollected = fsm.State("state_dkg_master_key_collected")
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
|
eventAutoDKGInitialInternal = fsm.Event("event_dkg_init")
|
||||||
eventAutoDKGInitialInternal = fsm.Event("event_dkg_init_internal")
|
|
||||||
|
|
||||||
EventDKGPubKeyConfirmationReceived = fsm.Event("event_dkg_pub_key_confirm_received")
|
|
||||||
EventDKGPubKeyConfirmationError = fsm.Event("event_dkg_pub_key_confirm_canceled_by_error")
|
|
||||||
|
|
||||||
eventAutoDKGValidatePubKeysConfirmationInternal = fsm.Event("event_dkg_pub_keys_validate_internal")
|
|
||||||
|
|
||||||
eventDKGSetPubKeysConfirmationCanceledByTimeoutInternal = fsm.Event("event_dkg_pub_keys_confirm_canceled_by_timeout_internal")
|
|
||||||
eventDKGSetPubKeysConfirmationCanceledByErrorInternal = fsm.Event("event_dkg_pub_keys_confirm_canceled_by_error_internal")
|
|
||||||
eventDKGSetPubKeysConfirmedInternal = fsm.Event("event_dkg_pub_keys_confirmed_internal")
|
|
||||||
|
|
||||||
EventDKGCommitConfirmationReceived = fsm.Event("event_dkg_commit_confirm_received")
|
EventDKGCommitConfirmationReceived = fsm.Event("event_dkg_commit_confirm_received")
|
||||||
EventDKGCommitConfirmationError = fsm.Event("event_dkg_commit_confirm_canceled_by_error")
|
EventDKGCommitConfirmationError = fsm.Event("event_dkg_commit_confirm_canceled_by_error")
|
||||||
|
@ -109,18 +94,11 @@ func New() internal.DumpedMachineProvider {
|
||||||
|
|
||||||
// {Name: eventAutoDKGInitialInternal, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitConfirmations, IsInternal: true, IsAuto: true, AutoRunMode: fsm.EventRunBefore},
|
// {Name: eventAutoDKGInitialInternal, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitConfirmations, IsInternal: true, IsAuto: true, AutoRunMode: fsm.EventRunBefore},
|
||||||
|
|
||||||
// Pub keys sending
|
// StateDkgCommitsCollected = fsm.State("state_dkg_commits_collected")
|
||||||
{Name: EventDKGPubKeyConfirmationReceived, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitConfirmations},
|
|
||||||
// Canceled
|
|
||||||
{Name: EventDKGPubKeyConfirmationError, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitCanceled},
|
|
||||||
|
|
||||||
{Name: eventAutoDKGValidatePubKeysConfirmationInternal, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitConfirmations, IsInternal: true, IsAuto: true},
|
// {Name: eventAutoDKGInitInternal, SrcState: []fsm.State{StateDkgInitial}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true, IsAuto: true, AutoRunMode: fsm.EventRunBefore},
|
||||||
|
|
||||||
{Name: eventDKGSetPubKeysConfirmationCanceledByTimeoutInternal, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitCanceledByTimeout, IsInternal: true},
|
{Name: eventAutoDKGInitialInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true, IsAuto: true, AutoRunMode: fsm.EventRunBefore},
|
||||||
// Confirmed
|
|
||||||
{Name: eventDKGSetPubKeysConfirmedInternal, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true},
|
|
||||||
|
|
||||||
// Switch to commits required
|
|
||||||
|
|
||||||
// Commits
|
// Commits
|
||||||
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations},
|
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations},
|
||||||
|
@ -166,10 +144,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
// {Name: EventDKGMasterKeyRequiredInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
// {Name: EventDKGMasterKeyRequiredInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
||||||
},
|
},
|
||||||
fsm.Callbacks{
|
fsm.Callbacks{
|
||||||
|
eventAutoDKGInitialInternal: machine.actionInitDKGProposal,
|
||||||
EventDKGPubKeyConfirmationReceived: machine.actionPubKeyConfirmationReceived,
|
|
||||||
EventDKGPubKeyConfirmationError: machine.actionConfirmationError,
|
|
||||||
eventAutoDKGValidatePubKeysConfirmationInternal: machine.actionValidateDkgProposalPubKeys,
|
|
||||||
|
|
||||||
EventDKGCommitConfirmationReceived: machine.actionCommitConfirmationReceived,
|
EventDKGCommitConfirmationReceived: machine.actionCommitConfirmationReceived,
|
||||||
EventDKGCommitConfirmationError: machine.actionConfirmationError,
|
EventDKGCommitConfirmationError: machine.actionConfirmationError,
|
||||||
|
|
|
@ -7,19 +7,20 @@ import (
|
||||||
|
|
||||||
type SignatureConfirmation struct {
|
type SignatureConfirmation struct {
|
||||||
Quorum SignatureProposalQuorum
|
Quorum SignatureProposalQuorum
|
||||||
CreatedAt *time.Time
|
CreatedAt time.Time
|
||||||
ExpiresAt *time.Time
|
ExpiresAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignatureProposalParticipant struct {
|
type SignatureProposalParticipant struct {
|
||||||
// Public title for address, such as name, nickname, organization
|
// Public title for address, such as name, nickname, organization
|
||||||
ParticipantId int
|
ParticipantId int
|
||||||
Title string
|
Title string
|
||||||
PublicKey *rsa.PublicKey
|
PubKey *rsa.PublicKey
|
||||||
// For validation user confirmation: sign(InvitationSecret, PublicKey) => user
|
DkgPubKey []byte
|
||||||
|
// For validation user confirmation: sign(InvitationSecret, PubKey) => user
|
||||||
InvitationSecret string
|
InvitationSecret string
|
||||||
Status ParticipantStatus
|
Status ParticipantStatus
|
||||||
UpdatedAt *time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique alias for map iteration - Public Key Fingerprint
|
// Unique alias for map iteration - Public Key Fingerprint
|
||||||
|
@ -33,9 +34,6 @@ const (
|
||||||
SignatureConfirmationConfirmed
|
SignatureConfirmationConfirmed
|
||||||
SignatureConfirmationDeclined
|
SignatureConfirmationDeclined
|
||||||
SignatureConfirmationError
|
SignatureConfirmationError
|
||||||
PubKeyAwaitConfirmation
|
|
||||||
PubKeyConfirmed
|
|
||||||
PubKeyConfirmationError
|
|
||||||
CommitAwaitConfirmation
|
CommitAwaitConfirmation
|
||||||
CommitConfirmed
|
CommitConfirmed
|
||||||
CommitConfirmationError
|
CommitConfirmationError
|
||||||
|
@ -59,7 +57,7 @@ type DKGProposalParticipant struct {
|
||||||
MasterKey []byte
|
MasterKey []byte
|
||||||
Status ParticipantStatus
|
Status ParticipantStatus
|
||||||
Error error
|
Error error
|
||||||
UpdatedAt *time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type DKGProposalQuorum map[int]*DKGProposalParticipant
|
type DKGProposalQuorum map[int]*DKGProposalParticipant
|
||||||
|
@ -83,12 +81,6 @@ func (s ParticipantStatus) String() string {
|
||||||
str = "SignatureConfirmationDeclined"
|
str = "SignatureConfirmationDeclined"
|
||||||
case SignatureConfirmationError:
|
case SignatureConfirmationError:
|
||||||
str = "SignatureConfirmationError"
|
str = "SignatureConfirmationError"
|
||||||
case PubKeyAwaitConfirmation:
|
|
||||||
str = "PubKeyAwaitConfirmation"
|
|
||||||
case PubKeyConfirmed:
|
|
||||||
str = "PubKeyConfirmed"
|
|
||||||
case PubKeyConfirmationError:
|
|
||||||
str = "PubKeyConfirmationError"
|
|
||||||
case CommitAwaitConfirmation:
|
case CommitAwaitConfirmation:
|
||||||
str = "CommitAwaitConfirmation"
|
str = "CommitAwaitConfirmation"
|
||||||
case CommitConfirmed:
|
case CommitConfirmed:
|
||||||
|
|
|
@ -17,14 +17,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
testTransactionId = "d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testExternalParticipants struct {
|
type testExternalParticipants struct {
|
||||||
Title string
|
Title string
|
||||||
PrivKey *rsa.PrivateKey
|
PrivKey *rsa.PrivateKey
|
||||||
PubKey *rsa.PublicKey
|
PubKey *rsa.PublicKey
|
||||||
|
DkgPubKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,7 +31,7 @@ var (
|
||||||
|
|
||||||
testParticipantsListRequest = requests.SignatureProposalParticipantsListRequest{
|
testParticipantsListRequest = requests.SignatureProposalParticipantsListRequest{
|
||||||
Participants: []*requests.SignatureProposalParticipantsEntry{},
|
Participants: []*requests.SignatureProposalParticipantsEntry{},
|
||||||
CreatedAt: &tm,
|
CreatedAt: tm,
|
||||||
}
|
}
|
||||||
|
|
||||||
testFSMDump []byte
|
testFSMDump []byte
|
||||||
|
@ -59,10 +56,15 @@ func init() {
|
||||||
|
|
||||||
fingerprint := base64.StdEncoding.EncodeToString(hash[:])
|
fingerprint := base64.StdEncoding.EncodeToString(hash[:])
|
||||||
|
|
||||||
|
pubKeyMock := make([]byte, 128)
|
||||||
|
|
||||||
|
rand.Read(pubKeyMock)
|
||||||
|
|
||||||
participant := &testExternalParticipants{
|
participant := &testExternalParticipants{
|
||||||
Title: fmt.Sprintf("User %d", i),
|
Title: fmt.Sprintf("User %d", i),
|
||||||
PrivKey: key,
|
PrivKey: key,
|
||||||
PubKey: &key.PublicKey,
|
PubKey: &key.PublicKey,
|
||||||
|
DkgPubKey: pubKeyMock,
|
||||||
}
|
}
|
||||||
testParticipants[fingerprint] = participant
|
testParticipants[fingerprint] = participant
|
||||||
}
|
}
|
||||||
|
@ -72,8 +74,9 @@ func init() {
|
||||||
for _, participant := range testParticipants {
|
for _, participant := range testParticipants {
|
||||||
|
|
||||||
participantsForRequest = append(participantsForRequest, &requests.SignatureProposalParticipantsEntry{
|
participantsForRequest = append(participantsForRequest, &requests.SignatureProposalParticipantsEntry{
|
||||||
Title: participant.Title,
|
Title: participant.Title,
|
||||||
PubKey: x509.MarshalPKCS1PublicKey(participant.PubKey),
|
PubKey: x509.MarshalPKCS1PublicKey(participant.PubKey),
|
||||||
|
DkgPubKey: participant.DkgPubKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
testParticipantsListRequest.Participants = participantsForRequest
|
testParticipantsListRequest.Participants = participantsForRequest
|
||||||
|
@ -197,7 +200,7 @@ func Test_SignatureProposal_Positive(t *testing.T) {
|
||||||
participantsMap[participant.ParticipantId] = participant
|
participantsMap[participant.ParticipantId] = participant
|
||||||
}
|
}
|
||||||
|
|
||||||
tm = tm.Add(10 * time.Hour)
|
tm = tm.Add(1 * time.Hour)
|
||||||
|
|
||||||
participantsCount := len(participantsMap)
|
participantsCount := len(participantsMap)
|
||||||
|
|
||||||
|
@ -222,10 +225,10 @@ func Test_SignatureProposal_Positive(t *testing.T) {
|
||||||
t.Fatalf("cannot encrypt {DecryptedInvitation} with private key")
|
t.Fatalf("cannot encrypt {DecryptedInvitation} with private key")
|
||||||
}
|
}
|
||||||
|
|
||||||
fsmResponse, dump, err = testFSMInstance.Do(spf.EventConfirmProposal, requests.SignatureProposalParticipantRequest{
|
fsmResponse, dump, err = testFSMInstance.Do(spf.EventConfirmSignatureProposal, requests.SignatureProposalParticipantRequest{
|
||||||
PubKeyFingerprint: participant.PubKeyFingerprint,
|
PubKeyFingerprint: participant.PubKeyFingerprint,
|
||||||
DecryptedInvitation: string(encrypted),
|
DecryptedInvitation: string(encrypted),
|
||||||
CreatedAt: &tm,
|
CreatedAt: tm,
|
||||||
})
|
})
|
||||||
|
|
||||||
compareErrNil(t, err)
|
compareErrNil(t, err)
|
||||||
|
@ -237,45 +240,11 @@ func Test_SignatureProposal_Positive(t *testing.T) {
|
||||||
if participantCounter > 0 {
|
if participantCounter > 0 {
|
||||||
compareState(t, spf.StateAwaitParticipantsConfirmations, fsmResponse.State)
|
compareState(t, spf.StateAwaitParticipantsConfirmations, fsmResponse.State)
|
||||||
} else {
|
} else {
|
||||||
compareState(t, dpf.StateDkgInitial, fsmResponse.State)
|
compareState(t, spf.StateSignatureProposalCollected, fsmResponse.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PubKeys
|
|
||||||
|
|
||||||
for _, participant := range participantsMap {
|
|
||||||
participantCounter--
|
|
||||||
testFSMInstance, err = FromDump(dump)
|
|
||||||
|
|
||||||
compareErrNil(t, err)
|
|
||||||
|
|
||||||
compareFSMInstanceNotNil(t, testFSMInstance)
|
|
||||||
|
|
||||||
if _, ok := testParticipants[participant.PubKeyFingerprint]; !ok {
|
|
||||||
t.Fatalf("not found external user data for response fingerprint")
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKeyMock := make([]byte, 128)
|
|
||||||
_, err := rand.Read(pubKeyMock)
|
|
||||||
if err != nil {
|
|
||||||
compareErrNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fsmResponse, dump, err = testFSMInstance.Do(dpf.EventDKGPubKeyConfirmationReceived, requests.DKGProposalPubKeyConfirmationRequest{
|
|
||||||
ParticipantId: participant.ParticipantId,
|
|
||||||
PubKey: pubKeyMock,
|
|
||||||
CreatedAt: tm,
|
|
||||||
})
|
|
||||||
|
|
||||||
compareErrNil(t, err)
|
|
||||||
|
|
||||||
compareDumpNotZero(t, dump)
|
|
||||||
|
|
||||||
compareFSMResponseNotNil(t, fsmResponse)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
compareState(t, dpf.StateDkgCommitsAwaitConfirmations, fsmResponse.State)
|
compareState(t, dpf.StateDkgCommitsAwaitConfirmations, fsmResponse.State)
|
||||||
|
|
||||||
// Commits
|
// Commits
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
// init -> awaitingConfirmations
|
// init -> awaitingConfirmations
|
||||||
// args: payload, signing id, participants list
|
// args: payload, signing id, participants list
|
||||||
func (m *SignatureProposalFSM) actionInitProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||||
m.payloadMu.Lock()
|
m.payloadMu.Lock()
|
||||||
defer m.payloadMu.Unlock()
|
defer m.payloadMu.Unlock()
|
||||||
|
|
||||||
|
@ -54,7 +54,8 @@ func (m *SignatureProposalFSM) actionInitProposal(inEvent fsm.Event, args ...int
|
||||||
m.payload.SignatureProposalPayload.Quorum[participantId] = &internal.SignatureProposalParticipant{
|
m.payload.SignatureProposalPayload.Quorum[participantId] = &internal.SignatureProposalParticipant{
|
||||||
ParticipantId: index,
|
ParticipantId: index,
|
||||||
Title: participant.Title,
|
Title: participant.Title,
|
||||||
PublicKey: parsedPubKey,
|
PubKey: parsedPubKey,
|
||||||
|
DkgPubKey: participant.DkgPubKey,
|
||||||
InvitationSecret: secret,
|
InvitationSecret: secret,
|
||||||
Status: internal.SignatureConfirmationAwaitConfirmation,
|
Status: internal.SignatureConfirmationAwaitConfirmation,
|
||||||
UpdatedAt: request.CreatedAt,
|
UpdatedAt: request.CreatedAt,
|
||||||
|
@ -72,7 +73,7 @@ func (m *SignatureProposalFSM) actionInitProposal(inEvent fsm.Event, args ...int
|
||||||
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
|
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
|
||||||
|
|
||||||
for pubKeyFingerprint, proposal := range m.payload.SignatureProposalPayload.Quorum {
|
for pubKeyFingerprint, proposal := range m.payload.SignatureProposalPayload.Quorum {
|
||||||
encryptedInvitationSecret, err := encryptWithPubKey(proposal.PublicKey, proposal.InvitationSecret)
|
encryptedInvitationSecret, err := encryptWithPubKey(proposal.PubKey, proposal.InvitationSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return inEvent, nil, errors.New("cannot encryptWithPubKey")
|
return inEvent, nil, errors.New("cannot encryptWithPubKey")
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ func (m *SignatureProposalFSM) actionProposalResponseByParticipant(inEvent fsm.E
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if signatureProposalParticipant.UpdatedAt.Add(config.SignatureProposalConfirmationDeadline).Before(*request.CreatedAt) {
|
if signatureProposalParticipant.UpdatedAt.Add(config.SignatureProposalConfirmationDeadline).Before(request.CreatedAt) {
|
||||||
outEvent = eventSetValidationCanceledByTimeout
|
outEvent = eventSetValidationCanceledByTimeout
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -133,7 +134,7 @@ func (m *SignatureProposalFSM) actionProposalResponseByParticipant(inEvent fsm.E
|
||||||
}
|
}
|
||||||
|
|
||||||
switch inEvent {
|
switch inEvent {
|
||||||
case EventConfirmProposal:
|
case EventConfirmSignatureProposal:
|
||||||
signatureProposalParticipant.Status = internal.SignatureConfirmationConfirmed
|
signatureProposalParticipant.Status = internal.SignatureConfirmationConfirmed
|
||||||
case EventDeclineProposal:
|
case EventDeclineProposal:
|
||||||
signatureProposalParticipant.Status = internal.SignatureConfirmationDeclined
|
signatureProposalParticipant.Status = internal.SignatureConfirmationDeclined
|
||||||
|
@ -189,37 +190,24 @@ func (m *SignatureProposalFSM) actionValidateSignatureProposal(inEvent fsm.Event
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outEvent = eventSetProposalValidatedInternal
|
err = m.SetState(eventSetProposalValidatedInternal)
|
||||||
|
if err != nil {
|
||||||
m.actionSetValidatedSignatureProposal(outEvent)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SignatureProposalFSM) actionSetValidatedSignatureProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
|
||||||
// m.payloadMu.Lock()
|
|
||||||
// defer m.payloadMu.Unlock()
|
|
||||||
|
|
||||||
// TODO: Run once after validation
|
|
||||||
if m.payload.DKGProposalPayload != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.payload.DKGProposalPayload = &internal.DKGConfirmation{
|
responseData := make(responses.SignatureProposalParticipantStatusResponse, 0)
|
||||||
Quorum: make(internal.DKGProposalQuorum),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
||||||
m.payload.DKGProposalPayload.Quorum[participant.ParticipantId] = &internal.DKGProposalParticipant{
|
responseEntry := &responses.SignatureProposalParticipantStatusEntry{
|
||||||
Title: participant.Title,
|
ParticipantId: participant.ParticipantId,
|
||||||
Status: internal.PubKeyAwaitConfirmation,
|
Title: participant.Title,
|
||||||
UpdatedAt: participant.UpdatedAt,
|
DkgPubKey: participant.DkgPubKey,
|
||||||
|
Status: uint8(participant.Status),
|
||||||
}
|
}
|
||||||
|
responseData = append(responseData, responseEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove m.payload.SignatureProposalPayload?
|
return eventDoneInternal, responseData, nil
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SignatureProposalFSM) actionSignatureProposalCanceledByTimeout(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
func (m *SignatureProposalFSM) actionSignatureProposalCanceledByTimeout(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||||
|
@ -228,12 +216,11 @@ func (m *SignatureProposalFSM) actionSignatureProposalCanceledByTimeout(inEvent
|
||||||
|
|
||||||
responseData := make(responses.SignatureProposalParticipantStatusResponse, 0)
|
responseData := make(responses.SignatureProposalParticipantStatusResponse, 0)
|
||||||
|
|
||||||
for pubKeyFingerprint, participant := range m.payload.SignatureProposalPayload.Quorum {
|
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
||||||
responseEntry := &responses.SignatureProposalParticipantStatusEntry{
|
responseEntry := &responses.SignatureProposalParticipantStatusEntry{
|
||||||
ParticipantId: participant.ParticipantId,
|
ParticipantId: participant.ParticipantId,
|
||||||
Title: participant.Title,
|
Title: participant.Title,
|
||||||
PubKeyFingerprint: pubKeyFingerprint,
|
Status: uint8(participant.Status),
|
||||||
Status: uint8(participant.Status),
|
|
||||||
}
|
}
|
||||||
responseData = append(responseData, responseEntry)
|
responseData = append(responseData, responseEntry)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package signature_proposal_fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/depools/dc4bc/fsm/fsm"
|
"github.com/depools/dc4bc/fsm/fsm"
|
||||||
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
dpf "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
||||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -21,14 +21,18 @@ const (
|
||||||
// Out state
|
// Out state
|
||||||
|
|
||||||
EventInitProposal = fsm.Event("event_sig_proposal_init")
|
EventInitProposal = fsm.Event("event_sig_proposal_init")
|
||||||
EventConfirmProposal = fsm.Event("event_sig_proposal_confirm_by_participant")
|
EventConfirmSignatureProposal = fsm.Event("event_sig_proposal_confirm_by_participant")
|
||||||
EventDeclineProposal = fsm.Event("event_sig_proposal_decline_by_participant")
|
EventDeclineProposal = fsm.Event("event_sig_proposal_decline_by_participant")
|
||||||
eventAutoValidateProposalInternal = fsm.Event("event_sig_proposal_validate")
|
eventAutoValidateProposalInternal = fsm.Event("event_sig_proposal_validate")
|
||||||
eventSetProposalValidatedInternal = fsm.Event("event_sig_proposal_set_validated")
|
eventSetProposalValidatedInternal = fsm.Event("event_sig_proposal_set_validated")
|
||||||
|
|
||||||
|
eventDoneInternal = fsm.Event("event_sig_proposal_done")
|
||||||
|
|
||||||
eventSetValidationCanceledByTimeout = fsm.Event("event_sig_proposal_canceled_timeout")
|
eventSetValidationCanceledByTimeout = fsm.Event("event_sig_proposal_canceled_timeout")
|
||||||
eventSetValidationCanceledByParticipant = fsm.Event("event_sig_proposal_declined_timeout")
|
eventSetValidationCanceledByParticipant = fsm.Event("event_sig_proposal_declined_timeout")
|
||||||
|
|
||||||
|
StateSignatureProposalCollected = fsm.State("state_sig_proposal_collected")
|
||||||
|
|
||||||
// Switch to next fsm
|
// Switch to next fsm
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -52,7 +56,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
{Name: EventInitProposal, SrcState: []fsm.State{StateParticipantsConfirmationsInit}, DstState: StateAwaitParticipantsConfirmations},
|
{Name: EventInitProposal, SrcState: []fsm.State{StateParticipantsConfirmationsInit}, DstState: StateAwaitParticipantsConfirmations},
|
||||||
|
|
||||||
// Validate by participants
|
// Validate by participants
|
||||||
{Name: EventConfirmProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
|
{Name: EventConfirmSignatureProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
|
||||||
// Is decline event should auto change state to default, or it process will initiated by client (external emit)?
|
// Is decline event should auto change state to default, or it process will initiated by client (external emit)?
|
||||||
// Now set for external emitting.
|
// Now set for external emitting.
|
||||||
{Name: EventDeclineProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
|
{Name: EventDeclineProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
|
||||||
|
@ -62,17 +66,19 @@ func New() internal.DumpedMachineProvider {
|
||||||
|
|
||||||
// eventProposalValidate internal or from client?
|
// eventProposalValidate internal or from client?
|
||||||
// yay
|
// yay
|
||||||
|
|
||||||
|
{Name: eventSetProposalValidatedInternal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateSignatureProposalCollected, IsInternal: true},
|
||||||
|
|
||||||
// Exit point
|
// Exit point
|
||||||
{Name: eventSetProposalValidatedInternal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: dkg_proposal_fsm.StateDkgPubKeysAwaitConfirmations, IsInternal: true},
|
{Name: eventDoneInternal, SrcState: []fsm.State{StateSignatureProposalCollected}, DstState: dpf.StateDkgInitial, IsInternal: true},
|
||||||
// nan
|
// nan
|
||||||
{Name: eventSetValidationCanceledByTimeout, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateValidationCanceledByTimeout, IsInternal: true},
|
{Name: eventSetValidationCanceledByTimeout, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateValidationCanceledByTimeout, IsInternal: true},
|
||||||
},
|
},
|
||||||
fsm.Callbacks{
|
fsm.Callbacks{
|
||||||
EventInitProposal: machine.actionInitProposal,
|
EventInitProposal: machine.actionInitSignatureProposal,
|
||||||
EventConfirmProposal: machine.actionProposalResponseByParticipant,
|
EventConfirmSignatureProposal: machine.actionProposalResponseByParticipant,
|
||||||
EventDeclineProposal: machine.actionProposalResponseByParticipant,
|
EventDeclineProposal: machine.actionProposalResponseByParticipant,
|
||||||
eventAutoValidateProposalInternal: machine.actionValidateSignatureProposal,
|
eventAutoValidateProposalInternal: machine.actionValidateSignatureProposal,
|
||||||
eventSetProposalValidatedInternal: machine.actionSetValidatedSignatureProposal,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return machine
|
return machine
|
||||||
|
|
|
@ -2,14 +2,6 @@ package requests
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// States: "state_dkg_pub_keys_await_confirmations"
|
|
||||||
// Events: "event_dkg_pub_key_confirm_received"
|
|
||||||
type DKGProposalPubKeyConfirmationRequest struct {
|
|
||||||
ParticipantId int
|
|
||||||
PubKey []byte
|
|
||||||
CreatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// States: "state_dkg_commits_sending_await_confirmations"
|
// States: "state_dkg_commits_sending_await_confirmations"
|
||||||
// Events: "event_dkg_commit_confirm_received"
|
// Events: "event_dkg_commit_confirm_received"
|
||||||
type DKGProposalCommitConfirmationRequest struct {
|
type DKGProposalCommitConfirmationRequest struct {
|
||||||
|
|
|
@ -2,22 +2,6 @@ package requests
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
func (r *DKGProposalPubKeyConfirmationRequest) Validate() error {
|
|
||||||
if r.ParticipantId < 0 {
|
|
||||||
return errors.New("{ParticipantId} cannot be a negative number")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.PubKey) == 0 {
|
|
||||||
return errors.New("{PubKey} cannot zero length")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.CreatedAt.IsZero() {
|
|
||||||
return errors.New("{CreatedAt} is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *DKGProposalCommitConfirmationRequest) Validate() error {
|
func (r *DKGProposalCommitConfirmationRequest) Validate() error {
|
||||||
if r.ParticipantId < 0 {
|
if r.ParticipantId < 0 {
|
||||||
return errors.New("{ParticipantId} cannot be a negative number")
|
return errors.New("{ParticipantId} cannot be a negative number")
|
||||||
|
|
|
@ -8,13 +8,14 @@ import "time"
|
||||||
// Events: "event_sig_proposal_init"
|
// Events: "event_sig_proposal_init"
|
||||||
type SignatureProposalParticipantsListRequest struct {
|
type SignatureProposalParticipantsListRequest struct {
|
||||||
Participants []*SignatureProposalParticipantsEntry
|
Participants []*SignatureProposalParticipantsEntry
|
||||||
CreatedAt *time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignatureProposalParticipantsEntry struct {
|
type SignatureProposalParticipantsEntry struct {
|
||||||
// Public title for address, such as name, nickname, organization
|
// Public title for address, such as name, nickname, organization
|
||||||
Title string
|
Title string
|
||||||
PubKey []byte
|
PubKey []byte
|
||||||
|
DkgPubKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// States: "__idle"
|
// States: "__idle"
|
||||||
|
@ -24,5 +25,5 @@ type SignatureProposalParticipantRequest struct {
|
||||||
// Key for link invitations to participants
|
// Key for link invitations to participants
|
||||||
PubKeyFingerprint string
|
PubKeyFingerprint string
|
||||||
DecryptedInvitation string
|
DecryptedInvitation string
|
||||||
CreatedAt *time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,13 @@ func (r *SignatureProposalParticipantsListRequest) Validate() error {
|
||||||
if len(participant.PubKey) < 10 {
|
if len(participant.PubKey) < 10 {
|
||||||
return errors.New("{PubKey} too short")
|
return errors.New("{PubKey} too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(participant.DkgPubKey) < 10 {
|
||||||
|
return errors.New("{DkgPubKey} too short")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.CreatedAt == nil {
|
if r.CreatedAt.IsZero() {
|
||||||
return errors.New("{CreatedAt} cannot be a nil")
|
return errors.New("{CreatedAt} cannot be a nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +45,7 @@ func (r *SignatureProposalParticipantRequest) Validate() error {
|
||||||
return errors.New("{DecryptedInvitation} cannot zero length")
|
return errors.New("{DecryptedInvitation} cannot zero length")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.CreatedAt == nil {
|
if r.CreatedAt.IsZero() {
|
||||||
return errors.New("{CreatedAt} cannot be a nil")
|
return errors.New("{CreatedAt} cannot be a nil")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
package responses
|
package responses
|
||||||
|
|
||||||
type DKGProposalPubKeyParticipantResponse []*DKGProposalPubKeyParticipantEntry
|
|
||||||
|
|
||||||
type DKGProposalPubKeyParticipantEntry struct {
|
|
||||||
ParticipantId int
|
|
||||||
Title string
|
|
||||||
PubKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type DKGProposalCommitParticipantResponse []*DKGProposalCommitParticipantEntry
|
type DKGProposalCommitParticipantResponse []*DKGProposalCommitParticipantEntry
|
||||||
|
|
||||||
type DKGProposalCommitParticipantEntry struct {
|
type DKGProposalCommitParticipantEntry struct {
|
||||||
|
|
|
@ -22,8 +22,8 @@ type SignatureProposalParticipantInvitationEntry struct {
|
||||||
type SignatureProposalParticipantStatusResponse []*SignatureProposalParticipantStatusEntry
|
type SignatureProposalParticipantStatusResponse []*SignatureProposalParticipantStatusEntry
|
||||||
|
|
||||||
type SignatureProposalParticipantStatusEntry struct {
|
type SignatureProposalParticipantStatusEntry struct {
|
||||||
ParticipantId int
|
ParticipantId int
|
||||||
Title string
|
Title string
|
||||||
PubKeyFingerprint string
|
DkgPubKey []byte
|
||||||
Status uint8
|
Status uint8
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue