mirror of https://github.com/certusone/dc4bc.git
feat: fixes, tests, actions
This commit is contained in:
parent
1b26930d57
commit
8f3152dcf8
129
fsm/fsm/fsm.go
129
fsm/fsm/fsm.go
|
@ -21,6 +21,10 @@ import (
|
|||
const (
|
||||
StateGlobalIdle = State("__idle")
|
||||
StateGlobalDone = State("__done")
|
||||
|
||||
EventRunDefault EventRunMode = iota
|
||||
EventRunBefore
|
||||
EventRunAfter
|
||||
)
|
||||
|
||||
type State string
|
||||
|
@ -39,6 +43,8 @@ func (e *Event) IsEmpty() bool {
|
|||
return e.String() == ""
|
||||
}
|
||||
|
||||
type EventRunMode uint8
|
||||
|
||||
// Response returns result for processing with clientMocks events
|
||||
type Response struct {
|
||||
// Returns machine execution result state
|
||||
|
@ -55,6 +61,8 @@ type FSM struct {
|
|||
// May be mapping must require pair source + event?
|
||||
transitions map[trKey]*trEvent
|
||||
|
||||
autoTransitions map[State]*trEvent
|
||||
|
||||
callbacks Callbacks
|
||||
|
||||
initialEvent Event
|
||||
|
@ -77,10 +85,11 @@ type trKey struct {
|
|||
|
||||
// Transition lightweight event description
|
||||
type trEvent struct {
|
||||
event Event
|
||||
dstState State
|
||||
isInternal bool
|
||||
isStateBefore bool
|
||||
event Event
|
||||
dstState State
|
||||
isInternal bool
|
||||
isAuto bool
|
||||
runMode EventRunMode
|
||||
}
|
||||
|
||||
type EventDesc struct {
|
||||
|
@ -94,8 +103,10 @@ type EventDesc struct {
|
|||
// Internal events, cannot be emitted from external call
|
||||
IsInternal bool
|
||||
|
||||
// Set dst state before execute action
|
||||
IsDstInit bool
|
||||
// Event must run without manual call
|
||||
IsAuto bool
|
||||
|
||||
AutoRunMode EventRunMode
|
||||
}
|
||||
|
||||
type Callback func(event Event, args ...interface{}) (Event, interface{}, error)
|
||||
|
@ -121,12 +132,13 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
|||
}
|
||||
|
||||
f := &FSM{
|
||||
name: machineName,
|
||||
currentState: initialState,
|
||||
initialState: initialState,
|
||||
transitions: make(map[trKey]*trEvent),
|
||||
finStates: make(map[State]bool),
|
||||
callbacks: make(map[Event]Callback),
|
||||
name: machineName,
|
||||
currentState: initialState,
|
||||
initialState: initialState,
|
||||
transitions: make(map[trKey]*trEvent),
|
||||
autoTransitions: make(map[State]*trEvent),
|
||||
finStates: make(map[State]bool),
|
||||
callbacks: make(map[Event]Callback),
|
||||
}
|
||||
|
||||
allEvents := make(map[Event]bool)
|
||||
|
@ -177,19 +189,40 @@ func MustNewFSM(machineName string, initialState State, events []EventDesc, call
|
|||
panic("duplicate dst for pair `source + event`")
|
||||
}
|
||||
|
||||
f.transitions[tKey] = &trEvent{
|
||||
trEvent := &trEvent{
|
||||
tKey.event,
|
||||
event.DstState,
|
||||
event.IsInternal,
|
||||
event.IsDstInit,
|
||||
event.IsAuto,
|
||||
event.AutoRunMode,
|
||||
}
|
||||
|
||||
if trEvent.isAuto && trEvent.runMode == EventRunDefault {
|
||||
trEvent.runMode = EventRunAfter
|
||||
}
|
||||
|
||||
f.transitions[tKey] = trEvent
|
||||
|
||||
// For using provider, event must use with IsGlobal = true
|
||||
if sourceState == initialState {
|
||||
if f.initialEvent != "" {
|
||||
panic("machine entry event already exist")
|
||||
if f.initialEvent == "" {
|
||||
f.initialEvent = event.Name
|
||||
}
|
||||
f.initialEvent = event.Name
|
||||
}
|
||||
|
||||
if event.IsAuto {
|
||||
if event.AutoRunMode != EventRunBefore && event.AutoRunMode != EventRunAfter {
|
||||
panic("{AutoRunMode} not set for auto event")
|
||||
}
|
||||
|
||||
if _, ok := f.autoTransitions[sourceState]; ok {
|
||||
panic(fmt.Sprintf(
|
||||
"auto event \"%s\" already exists for state \"%s\"",
|
||||
event.Name,
|
||||
sourceState,
|
||||
))
|
||||
}
|
||||
f.autoTransitions[sourceState] = trEvent
|
||||
}
|
||||
|
||||
allSources[sourceState] = true
|
||||
|
@ -260,14 +293,28 @@ func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err err
|
|||
// f.eventMu.Lock()
|
||||
// defer f.eventMu.Unlock()
|
||||
|
||||
if trEvent.isStateBefore {
|
||||
err = f.SetState(trEvent.event)
|
||||
if err != nil {
|
||||
resp = &Response{
|
||||
State: f.State(),
|
||||
}
|
||||
return resp, err
|
||||
// Process auto event
|
||||
if autoEvent, ok := f.autoTransitions[f.State()]; ok {
|
||||
autoEventResp := &Response{
|
||||
State: f.State(),
|
||||
}
|
||||
if autoEvent.runMode == EventRunBefore {
|
||||
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 = &Response{
|
||||
|
@ -282,13 +329,35 @@ func (f *FSM) do(trEvent *trEvent, args ...interface{}) (resp *Response, err err
|
|||
}
|
||||
}
|
||||
|
||||
if !trEvent.isStateBefore {
|
||||
if outEvent.IsEmpty() || trEvent.event == outEvent {
|
||||
err = f.SetState(trEvent.event)
|
||||
} else {
|
||||
err = f.SetState(outEvent)
|
||||
}
|
||||
// Set state when callback executed
|
||||
if outEvent.IsEmpty() || trEvent.event == outEvent {
|
||||
err = f.SetState(trEvent.event)
|
||||
} else {
|
||||
err = f.SetState(outEvent)
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
|
|
@ -48,14 +48,14 @@ var (
|
|||
}
|
||||
|
||||
testingCallbacks = Callbacks{
|
||||
eventInit: func(event Event, args ...interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
eventInit: func(event Event, args ...interface{}) (Event, interface{}, error) {
|
||||
return event, nil, nil
|
||||
},
|
||||
eventInternalOut2: func(event Event, args ...interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
eventInternalOut2: func(event Event, args ...interface{}) (Event, interface{}, error) {
|
||||
return event, nil, nil
|
||||
},
|
||||
eventProcess: func(event Event, args ...interface{}) (interface{}, error) {
|
||||
return nil, nil
|
||||
eventProcess: func(event Event, args ...interface{}) (Event, interface{}, error) {
|
||||
return event, nil, nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -3,7 +3,6 @@ package fsm_pool
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
)
|
||||
|
||||
|
@ -23,6 +22,8 @@ type MachineProvider interface {
|
|||
|
||||
GlobalInitialEvent() fsm.Event
|
||||
|
||||
EntryEvent() fsm.Event
|
||||
|
||||
EventsList() []fsm.Event
|
||||
|
||||
StatesSourcesList() []fsm.State
|
||||
|
@ -39,9 +40,10 @@ type FSMStatesMapper map[fsm.State]string
|
|||
type FSMPool struct {
|
||||
fsmInitialEvent fsm.Event
|
||||
// Pool mapper by names
|
||||
mapper FSMMapper
|
||||
events FSMEventsMapper
|
||||
states FSMStatesMapper
|
||||
mapper FSMMapper
|
||||
events FSMEventsMapper
|
||||
states FSMStatesMapper
|
||||
entryEvents map[fsm.State]fsm.Event
|
||||
}
|
||||
|
||||
func Init(machines ...MachineProvider) *FSMPool {
|
||||
|
@ -49,9 +51,10 @@ func Init(machines ...MachineProvider) *FSMPool {
|
|||
panic("cannot initialize empty pool")
|
||||
}
|
||||
p := &FSMPool{
|
||||
mapper: make(FSMMapper),
|
||||
events: make(FSMEventsMapper),
|
||||
states: make(FSMStatesMapper),
|
||||
mapper: make(FSMMapper),
|
||||
events: make(FSMEventsMapper),
|
||||
states: make(FSMStatesMapper),
|
||||
entryEvents: make(map[fsm.State]fsm.Event),
|
||||
}
|
||||
|
||||
allInitStatesMap := make(map[fsm.State]string)
|
||||
|
@ -84,7 +87,7 @@ func Init(machines ...MachineProvider) *FSMPool {
|
|||
}
|
||||
|
||||
// Setup entry event for machines pool if available
|
||||
if initialEvent := machine.GlobalInitialEvent(); initialEvent != "" {
|
||||
if initialEvent := machine.GlobalInitialEvent(); !initialEvent.IsEmpty() {
|
||||
if p.fsmInitialEvent != "" {
|
||||
panic("duplicate entry event initialization")
|
||||
}
|
||||
|
@ -92,6 +95,10 @@ func Init(machines ...MachineProvider) *FSMPool {
|
|||
p.fsmInitialEvent = initialEvent
|
||||
}
|
||||
|
||||
if machineEntryEvent := machine.EntryEvent(); !machineEntryEvent.IsEmpty() {
|
||||
p.entryEvents[machine.InitialState()] = machineEntryEvent
|
||||
}
|
||||
|
||||
p.mapper[machineName] = machine
|
||||
}
|
||||
|
||||
|
@ -153,3 +160,17 @@ func (p *FSMPool) MachineByState(state fsm.State) (MachineProvider, error) {
|
|||
}
|
||||
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
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -44,7 +44,7 @@ const (
|
|||
var (
|
||||
testing1Events = []fsm.EventDesc{
|
||||
// Init
|
||||
{Name: eventFSM1Init, SrcState: []fsm.State{fsm1StateInit}, DstState: fsm1StateStage1, IsDstInit: true},
|
||||
{Name: eventFSM1Init, SrcState: []fsm.State{fsm1StateInit}, DstState: fsm1StateStage1, IsAuto: true, AutoRunMode: fsm.EventRunAfter},
|
||||
{Name: eventFSM1Internal, SrcState: []fsm.State{fsm1StateStage1}, DstState: fsm1StateStage2, IsInternal: true},
|
||||
|
||||
// Cancellation events
|
||||
|
@ -73,21 +73,24 @@ func NewFSM1() MachineProvider {
|
|||
return machine
|
||||
}
|
||||
|
||||
func (m *testMachineFSM1) actionFSM1SetUpData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
||||
func (m *testMachineFSM1) actionFSM1SetUpData(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
m.data = testVal1
|
||||
return m.DoInternal(eventFSM1Internal)
|
||||
outEvent = eventFSM1Internal
|
||||
return
|
||||
}
|
||||
|
||||
func (m *testMachineFSM1) actionFSM1ProcessData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
||||
func (m *testMachineFSM1) actionFSM1ProcessData(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
if len(args) == 1 {
|
||||
if val, ok := args[0].(int); ok {
|
||||
m.data -= val
|
||||
}
|
||||
}
|
||||
return m.data, nil
|
||||
|
||||
response = m.data
|
||||
return
|
||||
}
|
||||
|
||||
func (m *testMachineFSM1) actionFSM1EmitOut2(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
||||
func (m *testMachineFSM1) actionFSM1EmitOut2(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,13 @@ package dkg_proposal_fsm
|
|||
import (
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
FsmName = "dkg_proposal_fsm"
|
||||
|
||||
StateDkgInitial = signature_proposal_fsm.StateValidationCompleted
|
||||
StateDkgInitial = StateDkgPubKeysAwaitConfirmations
|
||||
|
||||
StateDkgPubKeysAwaitConfirmations = fsm.State("state_dkg_pub_keys_await_confirmations")
|
||||
// Cancelled
|
||||
|
@ -43,7 +42,7 @@ const (
|
|||
StateDkgResponsesAwaitConfirmed = fsm.State("state_dkg_responses_await_confirmed")
|
||||
|
||||
// Events
|
||||
EventDKGPubKeysSendingRequiredInternal = fsm.Event("event_dkg_pub_key_sending_required_internal")
|
||||
eventDKGPubKeysSendingRequiredAuto = fsm.Event("event_dkg_pub_key_sending_required_internal")
|
||||
|
||||
EventDKGPubKeyConfirmationReceived = fsm.Event("event_dkg_pub_key_confirm_received")
|
||||
EventDKGPubKeyConfirmationError = fsm.Event("event_dkg_pub_key_confirm_canceled_by_error")
|
||||
|
@ -88,7 +87,7 @@ func New() internal.DumpedMachineProvider {
|
|||
|
||||
// Init
|
||||
// Switch to pub keys required
|
||||
{Name: EventDKGPubKeysSendingRequiredInternal, SrcState: []fsm.State{StateDkgInitial}, DstState: StateDkgPubKeysAwaitConfirmations, IsInternal: true},
|
||||
// {Name: eventDKGPubKeysSendingRequiredAuto, SrcState: []fsm.State{StateDkgInitial}, DstState: StateDkgPubKeysAwaitConfirmations, IsInternal: true, IsAuto: true, AutoRunMode: fsm.EventRunAfter},
|
||||
|
||||
// Pub keys sending
|
||||
{Name: EventDKGPubKeyConfirmationReceived, SrcState: []fsm.State{StateDkgPubKeysAwaitConfirmations}, DstState: StateDkgPubKeysAwaitConfirmations},
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
dpf "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
||||
spf "github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
||||
"github.com/depools/dc4bc/fsm/types/requests"
|
||||
"github.com/depools/dc4bc/fsm/types/responses"
|
||||
|
@ -93,41 +95,58 @@ func TestCreate_Negative(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_Workflow(t *testing.T) {
|
||||
testFSMInstance, err := Create(testTransactionId)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got {%s}", err)
|
||||
func compareErrNil(t *testing.T, got error) {
|
||||
if got != nil {
|
||||
t.Fatalf("expected nil error, got {%s}", got)
|
||||
}
|
||||
}
|
||||
|
||||
if testFSMInstance == nil {
|
||||
func compareFSMInstanceNotNil(t *testing.T, got *FSMInstance) {
|
||||
if got == nil {
|
||||
t.Fatalf("expected {*FSMInstance}")
|
||||
}
|
||||
}
|
||||
|
||||
func compareDumpNotZero(t *testing.T, got []byte) {
|
||||
if len(got) == 0 {
|
||||
t.Fatalf("expected non zero dump, when executed without error")
|
||||
}
|
||||
}
|
||||
|
||||
func compareFSMResponseNotNil(t *testing.T, got *fsm.Response) {
|
||||
if got == nil {
|
||||
t.Fatalf("expected {*fsm.FSMResponse} got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func compareState(t *testing.T, expected fsm.State, got fsm.State) {
|
||||
if got != expected {
|
||||
t.Fatalf("expected state {%s} got {%s}", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Workflow(t *testing.T) {
|
||||
testFSMInstance, err := Create(testTransactionId)
|
||||
|
||||
compareErrNil(t, err)
|
||||
|
||||
compareFSMInstanceNotNil(t, testFSMInstance)
|
||||
|
||||
if testFSMInstance.machine.Name() != spf.FsmName {
|
||||
t.Fatalf("expected machine name {%s}", spf.FsmName)
|
||||
}
|
||||
|
||||
if testFSMInstance.machine.State() != spf.StateParticipantsConfirmationsInit {
|
||||
t.Fatalf("expected inital state {%s}", spf.StateParticipantsConfirmationsInit)
|
||||
}
|
||||
compareState(t, spf.StateParticipantsConfirmationsInit, testFSMInstance.machine.State())
|
||||
|
||||
fsmResponse, dump, err := testFSMInstance.Do(spf.EventInitProposal, testParticipantsListRequest)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got {%s}", err)
|
||||
}
|
||||
compareErrNil(t, err)
|
||||
|
||||
if len(dump) == 0 {
|
||||
t.Fatalf("expected non zero dump, when executed without error")
|
||||
}
|
||||
compareDumpNotZero(t, dump)
|
||||
|
||||
if fsmResponse == nil {
|
||||
t.Fatalf("expected {*fsm.FSMResponse}")
|
||||
}
|
||||
compareFSMResponseNotNil(t, fsmResponse)
|
||||
|
||||
if fsmResponse.State != spf.StateAwaitParticipantsConfirmations {
|
||||
t.Fatalf("expected state {%s}", spf.StateAwaitParticipantsConfirmations)
|
||||
}
|
||||
compareState(t, spf.StateAwaitParticipantsConfirmations, fsmResponse.State)
|
||||
|
||||
testParticipantsListResponse, ok := fsmResponse.Data.(responses.SignatureProposalParticipantInvitationsResponse)
|
||||
|
||||
|
@ -163,17 +182,17 @@ func Test_Workflow(t *testing.T) {
|
|||
|
||||
tm = tm.Add(10 * time.Second)
|
||||
|
||||
for _, participant := range participantsMap {
|
||||
participantsCount := len(participantsMap)
|
||||
|
||||
participantCounter := participantsCount
|
||||
|
||||
for _, participant := range participantsMap {
|
||||
participantCounter--
|
||||
testFSMInstance, err = FromDump(dump)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got {%s}", err)
|
||||
}
|
||||
compareErrNil(t, err)
|
||||
|
||||
if testFSMInstance == nil {
|
||||
t.Fatalf("expected {*FSMInstance}")
|
||||
}
|
||||
compareFSMInstanceNotNil(t, testFSMInstance)
|
||||
|
||||
if _, ok := testParticipants[participant.PubKeyFingerprint]; !ok {
|
||||
t.Fatalf("not found external user data for response fingerprint")
|
||||
|
@ -191,6 +210,24 @@ func Test_Workflow(t *testing.T) {
|
|||
DecryptedInvitation: string(encrypted),
|
||||
CreatedAt: &tm,
|
||||
})
|
||||
|
||||
compareErrNil(t, err)
|
||||
|
||||
compareDumpNotZero(t, dump)
|
||||
|
||||
compareFSMResponseNotNil(t, fsmResponse)
|
||||
|
||||
if participantCounter > 0 {
|
||||
if fsmResponse.State != spf.StateAwaitParticipantsConfirmations {
|
||||
t.Fatalf("expected state {%s} got {%s}", spf.StateAwaitParticipantsConfirmations, fsmResponse.State)
|
||||
}
|
||||
} else {
|
||||
if fsmResponse.State != dpf.StateDkgInitial {
|
||||
t.Fatalf("expected state {%s} got {%s}", dpf.StateDkgInitial, fsmResponse.State)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println(fsmResponse.State, err)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package signature_proposal_fsm
|
|||
|
||||
import (
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||
"sync"
|
||||
)
|
||||
|
@ -17,6 +18,7 @@ const (
|
|||
StateValidationCanceledByParticipant = fsm.State("state_sig_proposal_canceled_by_participant")
|
||||
StateValidationCanceledByTimeout = fsm.State("state_sig_proposal_canceled_by_timeout")
|
||||
|
||||
// Out state
|
||||
StateValidationCompleted = fsm.State("state_sig_proposal_completed")
|
||||
|
||||
EventInitProposal = fsm.Event("event_sig_proposal_init")
|
||||
|
@ -60,7 +62,7 @@ func New() internal.DumpedMachineProvider {
|
|||
// eventProposalValidate internal or from client?
|
||||
// yay
|
||||
// Exit point
|
||||
{Name: eventSetProposalValidatedInternal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: fsm.State("state_dkg_pub_keys_sending_required"), IsInternal: true},
|
||||
{Name: eventSetProposalValidatedInternal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: dkg_proposal_fsm.StateDkgPubKeysAwaitConfirmations, IsInternal: true},
|
||||
// nan
|
||||
{Name: eventSetValidationCanceledByTimeout, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateValidationCanceledByTimeout, IsInternal: true},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue