mirror of https://github.com/certusone/dc4bc.git
wip
This commit is contained in:
parent
19640adcf0
commit
3b4e09f6cb
|
@ -7,4 +7,5 @@ const (
|
|||
ParticipantsMinCount = 3
|
||||
SignatureProposalConfirmationDeadline = time.Hour * 24
|
||||
DkgConfirmationDeadline = time.Hour * 24
|
||||
SigningConfirmationDeadline = time.Hour * 24
|
||||
)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
|
||||
Events
|
|
@ -15,7 +15,7 @@ const (
|
|||
// Sending dkg commits
|
||||
StateDkgCommitsAwaitConfirmations = fsm.State("state_dkg_commits_await_confirmations")
|
||||
// Canceled
|
||||
StateDkgCommitsAwaitCanceled = fsm.State("state_dkg_commits_await_canceled")
|
||||
StateDkgCommitsAwaitCanceledByError = fsm.State("state_dkg_commits_await_canceled_by_error")
|
||||
StateDkgCommitsAwaitCanceledByTimeout = fsm.State("state_dkg_commits_await_canceled_by_timeout")
|
||||
// Confirmed
|
||||
StateDkgCommitsCollected = fsm.State("state_dkg_commits_collected")
|
||||
|
@ -23,20 +23,20 @@ const (
|
|||
// Sending dkg deals
|
||||
StateDkgDealsAwaitConfirmations = fsm.State("state_dkg_deals_await_confirmations")
|
||||
// Canceled
|
||||
StateDkgDealsAwaitCanceled = fsm.State("state_dkg_deals_await_canceled")
|
||||
StateDkgDealsAwaitCanceledByError = fsm.State("state_dkg_deals_await_canceled_by_error")
|
||||
StateDkgDealsAwaitCanceledByTimeout = fsm.State("state_dkg_deals_await_canceled_by_timeout")
|
||||
// Confirmed
|
||||
//StateDkgDealsCollected = fsm.State("state_dkg_deals_collected")
|
||||
|
||||
StateDkgResponsesAwaitConfirmations = fsm.State("state_dkg_responses_await_confirmations")
|
||||
// Canceled
|
||||
StateDkgResponsesAwaitCanceled = fsm.State("state_dkg_responses_await_canceled")
|
||||
StateDkgResponsesAwaitCanceledByError = fsm.State("state_dkg_responses_await_canceled_by_error")
|
||||
StateDkgResponsesAwaitCanceledByTimeout = fsm.State("state_dkg_responses_sending_canceled_by_timeout")
|
||||
// Confirmed
|
||||
StateDkgResponsesCollected = fsm.State("state_dkg_responses_collected")
|
||||
|
||||
StateDkgMasterKeyAwaitConfirmations = fsm.State("state_dkg_master_key_await_confirmations")
|
||||
StateDkgMasterKeyAwaitCanceled = fsm.State("state_dkg_master_key_await_canceled")
|
||||
StateDkgMasterKeyAwaitCanceledByError = fsm.State("state_dkg_master_key_await_canceled_by_error")
|
||||
StateDkgMasterKeyAwaitCanceledByTimeout = fsm.State("state_dkg_master_key_await_canceled_by_timeout")
|
||||
|
||||
StateDkgMasterKeyCollected = fsm.State("state_dkg_master_key_collected")
|
||||
|
@ -104,7 +104,7 @@ func New() internal.DumpedMachineProvider {
|
|||
// Commits
|
||||
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations},
|
||||
// Canceled
|
||||
{Name: EventDKGCommitConfirmationError, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitCanceled},
|
||||
{Name: EventDKGCommitConfirmationError, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitCanceledByError},
|
||||
{Name: eventDKGCommitsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitCanceledByTimeout, IsInternal: true},
|
||||
|
||||
{Name: eventAutoDKGValidateConfirmationCommitsInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
@ -115,7 +115,7 @@ func New() internal.DumpedMachineProvider {
|
|||
// Deals
|
||||
{Name: EventDKGDealConfirmationReceived, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations},
|
||||
// Canceled
|
||||
{Name: EventDKGDealConfirmationError, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitCanceled},
|
||||
{Name: EventDKGDealConfirmationError, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitCanceledByError},
|
||||
{Name: eventDKGDealsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations, IsInternal: true},
|
||||
{Name: eventAutoDKGValidateConfirmationDealsInternal, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
||||
|
@ -124,7 +124,7 @@ func New() internal.DumpedMachineProvider {
|
|||
// Responses
|
||||
{Name: EventDKGResponseConfirmationReceived, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations},
|
||||
// Canceled
|
||||
{Name: EventDKGResponseConfirmationError, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitCanceled},
|
||||
{Name: EventDKGResponseConfirmationError, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitCanceledByError},
|
||||
{Name: eventDKGResponseConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitCanceledByTimeout, IsInternal: true},
|
||||
|
||||
{Name: eventAutoDKGValidateResponsesConfirmationInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
@ -134,15 +134,13 @@ func New() internal.DumpedMachineProvider {
|
|||
// Master key
|
||||
|
||||
{Name: EventDKGMasterKeyConfirmationReceived, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitConfirmations},
|
||||
{Name: EventDKGMasterKeyConfirmationError, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitCanceled},
|
||||
{Name: EventDKGMasterKeyConfirmationError, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitCanceledByError},
|
||||
{Name: eventDKGMasterKeyConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitCanceledByTimeout, IsInternal: true},
|
||||
|
||||
{Name: eventAutoDKGValidateMasterKeyConfirmationInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
||||
{Name: eventDKGMasterKeyConfirmedInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
||||
|
||||
// Done
|
||||
// {Name: EventDKGMasterKeyRequiredInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
||||
{Name: eventDKGMasterKeyConfirmedInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyCollected, IsInternal: true},
|
||||
},
|
||||
fsm.Callbacks{
|
||||
EventDKGInitProcess: machine.actionInitDKGProposal,
|
||||
|
|
|
@ -13,6 +13,7 @@ type DumpedMachineStatePayload struct {
|
|||
TransactionId string
|
||||
SignatureProposalPayload *SignatureConfirmation
|
||||
DKGProposalPayload *DKGConfirmation
|
||||
SigningProposalPayload *SigningConfirmation
|
||||
}
|
||||
|
||||
// Signature quorum
|
||||
|
@ -78,3 +79,35 @@ func (p *DumpedMachineStatePayload) DKGQuorumUpdate(id int, participant *DKGProp
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Signing quorum
|
||||
|
||||
func (p *DumpedMachineStatePayload) SigningQuorumCount() int {
|
||||
var count int
|
||||
if p.SigningProposalPayload.Quorum != nil {
|
||||
count = len(p.SigningProposalPayload.Quorum)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (p *DumpedMachineStatePayload) SigningQuorumExists(id int) bool {
|
||||
var exists bool
|
||||
if p.SigningProposalPayload.Quorum != nil {
|
||||
_, exists = p.SigningProposalPayload.Quorum[id]
|
||||
}
|
||||
return exists
|
||||
}
|
||||
|
||||
func (p *DumpedMachineStatePayload) SigningQuorumGet(id int) (participant *SigningProposalParticipant) {
|
||||
if p.SigningProposalPayload.Quorum != nil {
|
||||
participant, _ = p.SigningProposalPayload.Quorum[id]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *DumpedMachineStatePayload) SigningQuorumUpdate(id int, participant *SigningProposalParticipant) {
|
||||
if p.SigningProposalPayload.Quorum != nil {
|
||||
p.SigningProposalPayload.Quorum[id] = participant
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,6 +5,30 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type ConfirmationParticipantStatus uint8
|
||||
|
||||
const (
|
||||
SigConfirmationAwaitConfirmation ConfirmationParticipantStatus = iota
|
||||
SigConfirmationConfirmed
|
||||
SigConfirmationDeclined
|
||||
SigConfirmationError
|
||||
)
|
||||
|
||||
func (s ConfirmationParticipantStatus) String() string {
|
||||
var str = "undefined"
|
||||
switch s {
|
||||
case SigConfirmationAwaitConfirmation:
|
||||
str = "SigConfirmationAwaitConfirmation"
|
||||
case SigConfirmationConfirmed:
|
||||
str = "SigConfirmationConfirmed"
|
||||
case SigConfirmationDeclined:
|
||||
str = "SigConfirmationDeclined"
|
||||
case SigConfirmationError:
|
||||
str = "SigConfirmationError"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
type SignatureConfirmation struct {
|
||||
Quorum SignatureProposalQuorum
|
||||
CreatedAt time.Time
|
||||
|
@ -19,7 +43,7 @@ type SignatureProposalParticipant struct {
|
|||
DkgPubKey []byte
|
||||
// For validation user confirmation: sign(InvitationSecret, PubKey) => user
|
||||
InvitationSecret string
|
||||
Status ParticipantStatus
|
||||
Status ConfirmationParticipantStatus
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
|
@ -27,14 +51,12 @@ type SignatureProposalParticipant struct {
|
|||
// Excludes array merge and rotate operations
|
||||
type SignatureProposalQuorum map[string]*SignatureProposalParticipant
|
||||
|
||||
type ParticipantStatus uint8
|
||||
// DKG proposal
|
||||
|
||||
type DKGParticipantStatus uint8
|
||||
|
||||
const (
|
||||
SignatureConfirmationAwaitConfirmation ParticipantStatus = iota
|
||||
SignatureConfirmationConfirmed
|
||||
SignatureConfirmationDeclined
|
||||
SignatureConfirmationError
|
||||
CommitAwaitConfirmation
|
||||
CommitAwaitConfirmation DKGParticipantStatus = iota
|
||||
CommitConfirmed
|
||||
CommitConfirmationError
|
||||
DealAwaitConfirmation
|
||||
|
@ -55,7 +77,7 @@ type DKGProposalParticipant struct {
|
|||
Deal []byte
|
||||
Response []byte
|
||||
MasterKey []byte
|
||||
Status ParticipantStatus
|
||||
Status DKGParticipantStatus
|
||||
Error error
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
@ -70,17 +92,9 @@ type DKGConfirmation struct {
|
|||
|
||||
type DKGProposalParticipantStatus uint8
|
||||
|
||||
func (s ParticipantStatus) String() string {
|
||||
func (s DKGParticipantStatus) String() string {
|
||||
var str = "undefined"
|
||||
switch s {
|
||||
case SignatureConfirmationAwaitConfirmation:
|
||||
str = "SignatureConfirmationAwaitConfirmation"
|
||||
case SignatureConfirmationConfirmed:
|
||||
str = "SignatureConfirmationConfirmed"
|
||||
case SignatureConfirmationDeclined:
|
||||
str = "SignatureConfirmationDeclined"
|
||||
case SignatureConfirmationError:
|
||||
str = "SignatureConfirmationError"
|
||||
case CommitAwaitConfirmation:
|
||||
str = "CommitAwaitConfirmation"
|
||||
case CommitConfirmed:
|
||||
|
@ -99,6 +113,67 @@ func (s ParticipantStatus) String() string {
|
|||
str = "ResponseConfirmed"
|
||||
case ResponseConfirmationError:
|
||||
str = "ResponseConfirmationError"
|
||||
case MasterKeyAwaitConfirmation:
|
||||
str = "MasterKeyAwaitConfirmation"
|
||||
case MasterKeyConfirmed:
|
||||
str = "MasterKeyConfirmed"
|
||||
case MasterKeyConfirmationError:
|
||||
str = "MasterKeyConfirmationError"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// Signing proposal
|
||||
|
||||
type SigningConfirmation struct {
|
||||
Quorum SigningProposalQuorum
|
||||
RecoveredKey []byte
|
||||
SrcPayload []byte
|
||||
EncryptedPayload []byte
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
type SigningProposalQuorum map[int]*SigningProposalParticipant
|
||||
|
||||
type SigningParticipantStatus uint8
|
||||
|
||||
const (
|
||||
SigningIdle SigningParticipantStatus = iota
|
||||
SigningAwaitConfirmation
|
||||
SigningConfirmed
|
||||
SigningDeclined
|
||||
SigningAwaitPartialKeys
|
||||
SigningPartialKeysConfirmed
|
||||
SigningError
|
||||
SigningProcess
|
||||
)
|
||||
|
||||
func (s SigningParticipantStatus) String() string {
|
||||
var str = "undefined"
|
||||
switch s {
|
||||
case SigningIdle:
|
||||
str = "SigningIdle"
|
||||
case SigningAwaitConfirmation:
|
||||
str = "SigningAwaitConfirmation"
|
||||
case SigningConfirmed:
|
||||
str = "SigningConfirmed"
|
||||
case SigningAwaitPartialKeys:
|
||||
str = "SigningAwaitPartialKeys"
|
||||
case SigningPartialKeysConfirmed:
|
||||
str = "SigningPartialKeysConfirmed"
|
||||
case SigningError:
|
||||
str = "SigningError"
|
||||
case SigningProcess:
|
||||
str = "SigningProcess"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
type SigningProposalParticipant struct {
|
||||
Title string
|
||||
Status SigningParticipantStatus
|
||||
PartialKey []byte
|
||||
Error error
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ func init() {
|
|||
})
|
||||
}
|
||||
testParticipantsListRequest.Participants = participantsForRequest
|
||||
testParticipantsListRequest.SigningThreshold = len(participantsForRequest)
|
||||
}
|
||||
|
||||
func TestCreate_Positive(t *testing.T) {
|
||||
|
@ -399,7 +400,7 @@ func Test_SignatureProposal_Positive(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
compareState(t, fsm.StateGlobalDone, fsmResponse.State)
|
||||
compareState(t, dpf.StateDkgMasterKeyCollected, fsmResponse.State)
|
||||
}
|
||||
|
||||
func Test_DKGProposal_Positive(t *testing.T) {
|
||||
|
|
|
@ -57,7 +57,7 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
|
|||
PubKey: parsedPubKey,
|
||||
DkgPubKey: participant.DkgPubKey,
|
||||
InvitationSecret: secret,
|
||||
Status: internal.SignatureConfirmationAwaitConfirmation,
|
||||
Status: internal.SigConfirmationAwaitConfirmation,
|
||||
UpdatedAt: request.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
@ -128,16 +128,16 @@ func (m *SignatureProposalFSM) actionProposalResponseByParticipant(inEvent fsm.E
|
|||
return
|
||||
}
|
||||
|
||||
if signatureProposalParticipant.Status != internal.SignatureConfirmationAwaitConfirmation {
|
||||
if signatureProposalParticipant.Status != internal.SigConfirmationAwaitConfirmation {
|
||||
err = errors.New(fmt.Sprintf("cannot apply reply participant with {Status} = {\"%s\"}", signatureProposalParticipant.Status))
|
||||
return
|
||||
}
|
||||
|
||||
switch inEvent {
|
||||
case EventConfirmSignatureProposal:
|
||||
signatureProposalParticipant.Status = internal.SignatureConfirmationConfirmed
|
||||
signatureProposalParticipant.Status = internal.SigConfirmationConfirmed
|
||||
case EventDeclineProposal:
|
||||
signatureProposalParticipant.Status = internal.SignatureConfirmationDeclined
|
||||
signatureProposalParticipant.Status = internal.SigConfirmationDeclined
|
||||
default:
|
||||
err = errors.New("undefined {Event} for action")
|
||||
return
|
||||
|
@ -162,14 +162,14 @@ func (m *SignatureProposalFSM) actionValidateSignatureProposal(inEvent fsm.Event
|
|||
|
||||
unconfirmedParticipants := m.payload.SigQuorumCount()
|
||||
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
||||
if participant.Status == internal.SignatureConfirmationAwaitConfirmation {
|
||||
if participant.Status == internal.SigConfirmationAwaitConfirmation {
|
||||
if participant.UpdatedAt.Add(config.SignatureProposalConfirmationDeadline).Before(tm) {
|
||||
isContainsExpired = true
|
||||
}
|
||||
} else {
|
||||
if participant.Status == internal.SignatureConfirmationConfirmed {
|
||||
if participant.Status == internal.SigConfirmationConfirmed {
|
||||
unconfirmedParticipants--
|
||||
} else if participant.Status == internal.SignatureConfirmationDeclined {
|
||||
} else if participant.Status == internal.SigConfirmationDeclined {
|
||||
isContainsDeclined = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ const (
|
|||
eventDoneInternal = fsm.Event("event_sig_proposal_done")
|
||||
|
||||
eventSetValidationCanceledByTimeout = fsm.Event("event_sig_proposal_canceled_timeout")
|
||||
eventSetValidationCanceledByParticipant = fsm.Event("event_sig_proposal_declined_timeout")
|
||||
eventSetValidationCanceledByParticipant = fsm.Event("event_sig_proposal_canceled_participant")
|
||||
|
||||
StateSignatureProposalCollected = fsm.State("state_sig_proposal_collected")
|
||||
|
||||
|
@ -49,7 +49,7 @@ func New() internal.DumpedMachineProvider {
|
|||
FsmName,
|
||||
fsm.StateGlobalIdle,
|
||||
[]fsm.EventDesc{
|
||||
// {Name: "", SrcState: []string{""}, DstState: ""},
|
||||
// {Name: "", SrcState: []fsm.State{""}, DstState: ""},
|
||||
|
||||
// Init
|
||||
{Name: EventInitProposal, SrcState: []fsm.State{StateParticipantsConfirmationsInit}, DstState: StateAwaitParticipantsConfirmations},
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
package signing_proposal_fsm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/depools/dc4bc/fsm/config"
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||
"github.com/depools/dc4bc/fsm/types/requests"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (m *SigningProposalFSM) actionInitSigningProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
m.payloadMu.Lock()
|
||||
defer m.payloadMu.Unlock()
|
||||
|
||||
m.payload.SigningProposalPayload = &internal.SigningConfirmation{
|
||||
Quorum: make(internal.SigningProposalQuorum),
|
||||
}
|
||||
|
||||
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
||||
m.payload.SigningProposalPayload.Quorum[participant.ParticipantId] = &internal.SigningProposalParticipant{
|
||||
Title: participant.Title,
|
||||
Status: internal.SigningIdle,
|
||||
UpdatedAt: participant.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *SigningProposalFSM) actionStartSigningProposal(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
m.payloadMu.Lock()
|
||||
defer m.payloadMu.Unlock()
|
||||
|
||||
if len(args) != 1 {
|
||||
err = errors.New("{arg0} required {SigningProposalStartRequest}")
|
||||
return
|
||||
}
|
||||
|
||||
request, ok := args[0].(requests.SigningProposalStartRequest)
|
||||
|
||||
if !ok {
|
||||
err = errors.New("cannot cast {arg0} to type {SigningProposalStartRequest}")
|
||||
return
|
||||
}
|
||||
|
||||
if err = request.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *SigningProposalFSM) actionProposalResponseByParticipant(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
||||
m.payloadMu.Lock()
|
||||
defer m.payloadMu.Unlock()
|
||||
|
||||
if len(args) != 1 {
|
||||
err = errors.New("{arg0} required {SigningProposalParticipantRequest}")
|
||||
return
|
||||
}
|
||||
|
||||
request, ok := args[0].(requests.SigningProposalParticipantRequest)
|
||||
|
||||
if !ok {
|
||||
err = errors.New("cannot cast {arg0} to type {SigningProposalParticipantRequest}")
|
||||
return
|
||||
}
|
||||
|
||||
if err = request.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !m.payload.SigningQuorumExists(request.ParticipantId) {
|
||||
err = errors.New("{ParticipantId} not exist in quorum")
|
||||
return
|
||||
}
|
||||
|
||||
signingProposalParticipant := m.payload.SigningQuorumGet(request.ParticipantId)
|
||||
|
||||
if signingProposalParticipant.Status != internal.SigningAwaitConfirmation {
|
||||
err = errors.New(fmt.Sprintf("cannot confirm commit with {Status} = {\"%s\"}", signingProposalParticipant.Status))
|
||||
return
|
||||
}
|
||||
|
||||
// copy(signingProposalParticipant.Commit, request.Commit)
|
||||
signingProposalParticipant.UpdatedAt = request.CreatedAt
|
||||
signingProposalParticipant.Status = internal.SigningConfirmed
|
||||
|
||||
m.payload.SigningQuorumUpdate(request.ParticipantId, signingProposalParticipant)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *SigningProposalFSM) actionValidateSigningProposalConfirmations(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.SigningQuorumCount()
|
||||
for _, participant := range m.payload.SigningProposalPayload.Quorum {
|
||||
if participant.Status == internal.SigningAwaitConfirmation {
|
||||
if participant.UpdatedAt.Add(config.SigningConfirmationDeadline).Before(tm) {
|
||||
isContainsExpired = true
|
||||
}
|
||||
} else {
|
||||
if participant.Status == internal.SigningDeclined {
|
||||
isContainsError = true
|
||||
} else if participant.Status == internal.SigningConfirmed {
|
||||
unconfirmedParticipants--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isContainsError {
|
||||
outEvent = eventSetSigningConfirmCanceledByTimeoutInternal
|
||||
return
|
||||
}
|
||||
|
||||
if isContainsExpired {
|
||||
outEvent = eventSetSigningConfirmCanceledByParticipantInternal
|
||||
return
|
||||
}
|
||||
|
||||
// The are no declined and timed out participants, check for all confirmations
|
||||
if unconfirmedParticipants > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
outEvent = eventSetProposalValidatedInternal
|
||||
|
||||
for _, participant := range m.payload.SigningProposalPayload.Quorum {
|
||||
participant.Status = internal.SigningAwaitPartialKeys
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package signing_proposal_fsm
|
||||
|
||||
import (
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
dkp "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/internal"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
FsmName = "signing_proposal_fsm"
|
||||
|
||||
StateSigningInitial = dkp.StateDkgMasterKeyCollected
|
||||
|
||||
StateSigningIdle = fsm.State("stage_signing_idle")
|
||||
|
||||
// Starting
|
||||
|
||||
StateSigningAwaitConfirmations = fsm.State("state_signing_await_confirmations")
|
||||
// Cancelled
|
||||
StateSigningConfirmationsAwaitCancelledByTimeout = fsm.State("state_signing_confirmations_await_cancelled_by_timeout")
|
||||
StateSigningConfirmationsAwaitCancelledByParticipant = fsm.State("state_signing_confirmations_await_cancelled_by_participant")
|
||||
|
||||
StateSigningAwaitPartialKeys = fsm.State("state_signing_await_partial_keys")
|
||||
// Cancelled
|
||||
StateSigningPartialKeysAwaitCancelledByTimeout = fsm.State("state_signing_partial_keys_await_cancelled_by_timeout")
|
||||
StateSigningPartialKeysAwaitCancelledByParticipant = fsm.State("state_signing_partial_keys_await_cancelled_by_participant")
|
||||
|
||||
StateSigningPartialKeysCollected = fsm.State("state_signing_partial_keys_collected")
|
||||
|
||||
// Events
|
||||
|
||||
EventSigningInit = fsm.Event("event_signing_init")
|
||||
EventSigningStart = fsm.Event("event_signing_start")
|
||||
EventConfirmSigningConfirmation = fsm.Event("event_signing_proposal_confirm_by_participant")
|
||||
EventDeclineSigningConfirmation = fsm.Event("event_signing_proposal_decline_by_participant")
|
||||
eventSetSigningConfirmCanceledByParticipantInternal = fsm.Event("event_signing_proposal_canceled_by_participant")
|
||||
eventSetSigningConfirmCanceledByTimeoutInternal = fsm.Event("event_signing_proposal_canceled_by_timeout")
|
||||
|
||||
eventAutoValidateProposalInternal = fsm.Event("event_signing_proposal_validate")
|
||||
eventSetProposalValidatedInternal = fsm.Event("event_signing_proposal_set_validated")
|
||||
|
||||
EventSigningPartialKeyReceived = fsm.Event("event_signing_partial_key_received")
|
||||
EventSigningPartialKeyError = fsm.Event("event_signing_partial_key_error_received")
|
||||
eventSigningPartialKeyCancelByTimeoutInternal = fsm.Event("event_signing_partial_key_canceled_by_timeout_internal")
|
||||
eventSigningPartialKeyCancelByErrorInternal = fsm.Event("event_signing_partial_key_canceled_by_error_internal")
|
||||
eventSigningPartialKeysConfirmedInternal = fsm.Event("event_signing_partial_keys_confirmed_internal")
|
||||
EventSigningFinish = fsm.Event("event_signing_finish")
|
||||
)
|
||||
|
||||
type SigningProposalFSM struct {
|
||||
*fsm.FSM
|
||||
payload *internal.DumpedMachineStatePayload
|
||||
payloadMu sync.RWMutex
|
||||
}
|
||||
|
||||
func New() internal.DumpedMachineProvider {
|
||||
machine := &SigningProposalFSM{}
|
||||
|
||||
machine.FSM = fsm.MustNewFSM(
|
||||
FsmName,
|
||||
StateSigningInitial,
|
||||
[]fsm.EventDesc{
|
||||
// Init
|
||||
{Name: EventSigningInit, SrcState: []fsm.State{StateSigningInitial}, DstState: StateSigningIdle},
|
||||
|
||||
// Start
|
||||
{Name: EventSigningStart, SrcState: []fsm.State{StateSigningIdle}, DstState: StateSigningAwaitConfirmations},
|
||||
|
||||
// Validate by participants
|
||||
{Name: EventConfirmSigningConfirmation, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningAwaitConfirmations},
|
||||
{Name: EventDeclineSigningConfirmation, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningAwaitConfirmations},
|
||||
|
||||
// Canceled
|
||||
{Name: eventSetSigningConfirmCanceledByParticipantInternal, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningConfirmationsAwaitCancelledByParticipant, IsInternal: true},
|
||||
{Name: eventSetSigningConfirmCanceledByTimeoutInternal, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningConfirmationsAwaitCancelledByTimeout, IsInternal: true},
|
||||
|
||||
// Validate
|
||||
{Name: eventAutoValidateProposalInternal, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
||||
{Name: eventSetProposalValidatedInternal, SrcState: []fsm.State{StateSigningAwaitConfirmations}, DstState: StateSigningAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||
|
||||
// Canceled
|
||||
{Name: EventSigningPartialKeyReceived, SrcState: []fsm.State{StateSigningAwaitPartialKeys}, DstState: StateSigningAwaitPartialKeys},
|
||||
{Name: EventSigningPartialKeyError, SrcState: []fsm.State{StateSigningAwaitPartialKeys}, DstState: StateSigningPartialKeysAwaitCancelledByParticipant},
|
||||
{Name: eventSigningPartialKeyCancelByTimeoutInternal, SrcState: []fsm.State{StateSigningAwaitPartialKeys}, DstState: StateSigningPartialKeysAwaitCancelledByTimeout, IsInternal: true},
|
||||
{Name: eventSigningPartialKeyCancelByErrorInternal, SrcState: []fsm.State{StateSigningAwaitPartialKeys}, DstState: StateSigningPartialKeysAwaitCancelledByParticipant, IsInternal: true, IsAuto: true},
|
||||
|
||||
{Name: eventSigningPartialKeysConfirmedInternal, SrcState: []fsm.State{StateSigningAwaitPartialKeys}, DstState: StateSigningPartialKeysCollected, IsInternal: true},
|
||||
|
||||
{Name: EventSigningFinish, SrcState: []fsm.State{StateSigningPartialKeysCollected}, DstState: StateSigningIdle, IsInternal: true},
|
||||
},
|
||||
fsm.Callbacks{
|
||||
EventSigningInit: machine.actionInitSigningProposal,
|
||||
},
|
||||
)
|
||||
|
||||
return machine
|
||||
}
|
||||
|
||||
func (m *SigningProposalFSM) SetUpPayload(payload *internal.DumpedMachineStatePayload) {
|
||||
m.payloadMu.Lock()
|
||||
defer m.payloadMu.Unlock()
|
||||
|
||||
m.payload = payload
|
||||
}
|
|
@ -7,8 +7,9 @@ import "time"
|
|||
// States: "__idle"
|
||||
// Events: "event_sig_proposal_init"
|
||||
type SignatureProposalParticipantsListRequest struct {
|
||||
Participants []*SignatureProposalParticipantsEntry
|
||||
CreatedAt time.Time
|
||||
Participants []*SignatureProposalParticipantsEntry
|
||||
SigningThreshold int
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type SignatureProposalParticipantsEntry struct {
|
||||
|
|
|
@ -11,6 +11,14 @@ func (r *SignatureProposalParticipantsListRequest) Validate() error {
|
|||
return errors.New(fmt.Sprintf("too few participants, minimum is {%d}", config.ParticipantsMinCount))
|
||||
}
|
||||
|
||||
if r.SigningThreshold < 2 {
|
||||
return errors.New("{SigningThreshold} minimum count is {2}")
|
||||
}
|
||||
|
||||
if r.SigningThreshold > len(r.Participants) {
|
||||
return errors.New("{SigningThreshold} cannot be higher than {ParticipantsCount}")
|
||||
}
|
||||
|
||||
for _, participant := range r.Participants {
|
||||
if len(participant.Title) < 3 {
|
||||
return errors.New("{Title} minimum length is {3}")
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package requests
|
||||
|
||||
import "time"
|
||||
|
||||
// States: "stage_signing_idle"
|
||||
// Events: "event_signing_start"
|
||||
type SigningProposalStartRequest struct {
|
||||
ParticipantId int
|
||||
SrcPayload []byte
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// States: "state_signing_await_confirmations"
|
||||
// Events: "event_signing_proposal_confirm_by_participant"
|
||||
// "event_signing_proposal_decline_by_participant"
|
||||
type SigningProposalParticipantRequest struct {
|
||||
ParticipantId int
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// States: "state_signing_await_partial_keys"
|
||||
// Events: "event_signing_partial_key_received"
|
||||
type SigningProposalPartialKeyRequest struct {
|
||||
ParticipantId int
|
||||
PartialKey []byte
|
||||
CreatedAt time.Time
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package requests
|
||||
|
||||
import "errors"
|
||||
|
||||
func (r *SigningProposalStartRequest) Validate() error {
|
||||
if r.ParticipantId < 0 {
|
||||
return errors.New("{ParticipantId} cannot be a negative number")
|
||||
}
|
||||
|
||||
if len(r.SrcPayload) == 0 {
|
||||
return errors.New("{SrcPayload} cannot zero length")
|
||||
}
|
||||
|
||||
if r.CreatedAt.IsZero() {
|
||||
return errors.New("{CreatedAt} is not set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SigningProposalParticipantRequest) Validate() error {
|
||||
if r.ParticipantId < 0 {
|
||||
return errors.New("{ParticipantId} cannot be a negative number")
|
||||
}
|
||||
|
||||
if r.CreatedAt.IsZero() {
|
||||
return errors.New("{CreatedAt} is not set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SigningProposalPartialKeyRequest) Validate() error {
|
||||
if r.ParticipantId < 0 {
|
||||
return errors.New("{ParticipantId} cannot be a negative number")
|
||||
}
|
||||
|
||||
if len(r.PartialKey) == 0 {
|
||||
return errors.New("{PartialKey} cannot zero length")
|
||||
}
|
||||
|
||||
if r.CreatedAt.IsZero() {
|
||||
return errors.New("{CreatedAt} is not set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package responses
|
Loading…
Reference in New Issue