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
|
ParticipantsMinCount = 3
|
||||||
SignatureProposalConfirmationDeadline = time.Hour * 24
|
SignatureProposalConfirmationDeadline = time.Hour * 24
|
||||||
DkgConfirmationDeadline = time.Hour * 24
|
DkgConfirmationDeadline = time.Hour * 24
|
||||||
|
SigningConfirmationDeadline = time.Hour * 24
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Events
|
|
@ -15,7 +15,7 @@ const (
|
||||||
// Sending dkg commits
|
// Sending dkg commits
|
||||||
StateDkgCommitsAwaitConfirmations = fsm.State("state_dkg_commits_await_confirmations")
|
StateDkgCommitsAwaitConfirmations = fsm.State("state_dkg_commits_await_confirmations")
|
||||||
// Canceled
|
// 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")
|
StateDkgCommitsAwaitCanceledByTimeout = fsm.State("state_dkg_commits_await_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
StateDkgCommitsCollected = fsm.State("state_dkg_commits_collected")
|
StateDkgCommitsCollected = fsm.State("state_dkg_commits_collected")
|
||||||
|
@ -23,20 +23,20 @@ const (
|
||||||
// Sending dkg deals
|
// Sending dkg deals
|
||||||
StateDkgDealsAwaitConfirmations = fsm.State("state_dkg_deals_await_confirmations")
|
StateDkgDealsAwaitConfirmations = fsm.State("state_dkg_deals_await_confirmations")
|
||||||
// Canceled
|
// 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")
|
StateDkgDealsAwaitCanceledByTimeout = fsm.State("state_dkg_deals_await_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
//StateDkgDealsCollected = fsm.State("state_dkg_deals_collected")
|
//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")
|
StateDkgResponsesAwaitCanceledByError = fsm.State("state_dkg_responses_await_canceled_by_error")
|
||||||
StateDkgResponsesAwaitCanceledByTimeout = fsm.State("state_dkg_responses_sending_canceled_by_timeout")
|
StateDkgResponsesAwaitCanceledByTimeout = fsm.State("state_dkg_responses_sending_canceled_by_timeout")
|
||||||
// Confirmed
|
// Confirmed
|
||||||
StateDkgResponsesCollected = fsm.State("state_dkg_responses_collected")
|
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")
|
StateDkgMasterKeyAwaitCanceledByError = fsm.State("state_dkg_master_key_await_canceled_by_error")
|
||||||
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")
|
StateDkgMasterKeyCollected = fsm.State("state_dkg_master_key_collected")
|
||||||
|
@ -104,7 +104,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
// Commits
|
// Commits
|
||||||
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations},
|
{Name: EventDKGCommitConfirmationReceived, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations},
|
||||||
// Canceled
|
// 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: eventDKGCommitsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitCanceledByTimeout, IsInternal: true},
|
||||||
|
|
||||||
{Name: eventAutoDKGValidateConfirmationCommitsInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
{Name: eventAutoDKGValidateConfirmationCommitsInternal, SrcState: []fsm.State{StateDkgCommitsAwaitConfirmations}, DstState: StateDkgCommitsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||||
|
@ -115,7 +115,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
// Deals
|
// Deals
|
||||||
{Name: EventDKGDealConfirmationReceived, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations},
|
{Name: EventDKGDealConfirmationReceived, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations},
|
||||||
// Canceled
|
// 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: eventDKGDealsConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations, IsInternal: true},
|
||||||
{Name: eventAutoDKGValidateConfirmationDealsInternal, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
{Name: eventAutoDKGValidateConfirmationDealsInternal, SrcState: []fsm.State{StateDkgDealsAwaitConfirmations}, DstState: StateDkgDealsAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
// Responses
|
// Responses
|
||||||
{Name: EventDKGResponseConfirmationReceived, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations},
|
{Name: EventDKGResponseConfirmationReceived, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations},
|
||||||
// Canceled
|
// 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: eventDKGResponseConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitCanceledByTimeout, IsInternal: true},
|
||||||
|
|
||||||
{Name: eventAutoDKGValidateResponsesConfirmationInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations, IsInternal: true, IsAuto: true},
|
{Name: eventAutoDKGValidateResponsesConfirmationInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: StateDkgResponsesAwaitConfirmations, IsInternal: true, IsAuto: true},
|
||||||
|
@ -134,15 +134,13 @@ func New() internal.DumpedMachineProvider {
|
||||||
// Master key
|
// Master key
|
||||||
|
|
||||||
{Name: EventDKGMasterKeyConfirmationReceived, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitConfirmations},
|
{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: eventDKGMasterKeyConfirmationCancelByTimeoutInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitCanceledByTimeout, IsInternal: true},
|
||||||
|
|
||||||
{Name: eventAutoDKGValidateMasterKeyConfirmationInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyAwaitConfirmations, IsInternal: true, IsAuto: 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
|
// Done
|
||||||
// {Name: EventDKGMasterKeyRequiredInternal, SrcState: []fsm.State{StateDkgResponsesAwaitConfirmations}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
{Name: eventDKGMasterKeyConfirmedInternal, SrcState: []fsm.State{StateDkgMasterKeyAwaitConfirmations}, DstState: StateDkgMasterKeyCollected, IsInternal: true},
|
||||||
},
|
},
|
||||||
fsm.Callbacks{
|
fsm.Callbacks{
|
||||||
EventDKGInitProcess: machine.actionInitDKGProposal,
|
EventDKGInitProcess: machine.actionInitDKGProposal,
|
||||||
|
|
|
@ -13,6 +13,7 @@ type DumpedMachineStatePayload struct {
|
||||||
TransactionId string
|
TransactionId string
|
||||||
SignatureProposalPayload *SignatureConfirmation
|
SignatureProposalPayload *SignatureConfirmation
|
||||||
DKGProposalPayload *DKGConfirmation
|
DKGProposalPayload *DKGConfirmation
|
||||||
|
SigningProposalPayload *SigningConfirmation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature quorum
|
// Signature quorum
|
||||||
|
@ -78,3 +79,35 @@ func (p *DumpedMachineStatePayload) DKGQuorumUpdate(id int, participant *DKGProp
|
||||||
}
|
}
|
||||||
return
|
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"
|
"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 {
|
type SignatureConfirmation struct {
|
||||||
Quorum SignatureProposalQuorum
|
Quorum SignatureProposalQuorum
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
|
@ -19,7 +43,7 @@ type SignatureProposalParticipant struct {
|
||||||
DkgPubKey []byte
|
DkgPubKey []byte
|
||||||
// For validation user confirmation: sign(InvitationSecret, PubKey) => user
|
// For validation user confirmation: sign(InvitationSecret, PubKey) => user
|
||||||
InvitationSecret string
|
InvitationSecret string
|
||||||
Status ParticipantStatus
|
Status ConfirmationParticipantStatus
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,14 +51,12 @@ type SignatureProposalParticipant struct {
|
||||||
// Excludes array merge and rotate operations
|
// Excludes array merge and rotate operations
|
||||||
type SignatureProposalQuorum map[string]*SignatureProposalParticipant
|
type SignatureProposalQuorum map[string]*SignatureProposalParticipant
|
||||||
|
|
||||||
type ParticipantStatus uint8
|
// DKG proposal
|
||||||
|
|
||||||
|
type DKGParticipantStatus uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SignatureConfirmationAwaitConfirmation ParticipantStatus = iota
|
CommitAwaitConfirmation DKGParticipantStatus = iota
|
||||||
SignatureConfirmationConfirmed
|
|
||||||
SignatureConfirmationDeclined
|
|
||||||
SignatureConfirmationError
|
|
||||||
CommitAwaitConfirmation
|
|
||||||
CommitConfirmed
|
CommitConfirmed
|
||||||
CommitConfirmationError
|
CommitConfirmationError
|
||||||
DealAwaitConfirmation
|
DealAwaitConfirmation
|
||||||
|
@ -55,7 +77,7 @@ type DKGProposalParticipant struct {
|
||||||
Deal []byte
|
Deal []byte
|
||||||
Response []byte
|
Response []byte
|
||||||
MasterKey []byte
|
MasterKey []byte
|
||||||
Status ParticipantStatus
|
Status DKGParticipantStatus
|
||||||
Error error
|
Error error
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
@ -70,17 +92,9 @@ type DKGConfirmation struct {
|
||||||
|
|
||||||
type DKGProposalParticipantStatus uint8
|
type DKGProposalParticipantStatus uint8
|
||||||
|
|
||||||
func (s ParticipantStatus) String() string {
|
func (s DKGParticipantStatus) String() string {
|
||||||
var str = "undefined"
|
var str = "undefined"
|
||||||
switch s {
|
switch s {
|
||||||
case SignatureConfirmationAwaitConfirmation:
|
|
||||||
str = "SignatureConfirmationAwaitConfirmation"
|
|
||||||
case SignatureConfirmationConfirmed:
|
|
||||||
str = "SignatureConfirmationConfirmed"
|
|
||||||
case SignatureConfirmationDeclined:
|
|
||||||
str = "SignatureConfirmationDeclined"
|
|
||||||
case SignatureConfirmationError:
|
|
||||||
str = "SignatureConfirmationError"
|
|
||||||
case CommitAwaitConfirmation:
|
case CommitAwaitConfirmation:
|
||||||
str = "CommitAwaitConfirmation"
|
str = "CommitAwaitConfirmation"
|
||||||
case CommitConfirmed:
|
case CommitConfirmed:
|
||||||
|
@ -99,6 +113,67 @@ func (s ParticipantStatus) String() string {
|
||||||
str = "ResponseConfirmed"
|
str = "ResponseConfirmed"
|
||||||
case ResponseConfirmationError:
|
case ResponseConfirmationError:
|
||||||
str = "ResponseConfirmationError"
|
str = "ResponseConfirmationError"
|
||||||
|
case MasterKeyAwaitConfirmation:
|
||||||
|
str = "MasterKeyAwaitConfirmation"
|
||||||
|
case MasterKeyConfirmed:
|
||||||
|
str = "MasterKeyConfirmed"
|
||||||
|
case MasterKeyConfirmationError:
|
||||||
|
str = "MasterKeyConfirmationError"
|
||||||
}
|
}
|
||||||
return str
|
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.Participants = participantsForRequest
|
||||||
|
testParticipantsListRequest.SigningThreshold = len(participantsForRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreate_Positive(t *testing.T) {
|
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) {
|
func Test_DKGProposal_Positive(t *testing.T) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (m *SignatureProposalFSM) actionInitSignatureProposal(inEvent fsm.Event, ar
|
||||||
PubKey: parsedPubKey,
|
PubKey: parsedPubKey,
|
||||||
DkgPubKey: participant.DkgPubKey,
|
DkgPubKey: participant.DkgPubKey,
|
||||||
InvitationSecret: secret,
|
InvitationSecret: secret,
|
||||||
Status: internal.SignatureConfirmationAwaitConfirmation,
|
Status: internal.SigConfirmationAwaitConfirmation,
|
||||||
UpdatedAt: request.CreatedAt,
|
UpdatedAt: request.CreatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,16 +128,16 @@ func (m *SignatureProposalFSM) actionProposalResponseByParticipant(inEvent fsm.E
|
||||||
return
|
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))
|
err = errors.New(fmt.Sprintf("cannot apply reply participant with {Status} = {\"%s\"}", signatureProposalParticipant.Status))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch inEvent {
|
switch inEvent {
|
||||||
case EventConfirmSignatureProposal:
|
case EventConfirmSignatureProposal:
|
||||||
signatureProposalParticipant.Status = internal.SignatureConfirmationConfirmed
|
signatureProposalParticipant.Status = internal.SigConfirmationConfirmed
|
||||||
case EventDeclineProposal:
|
case EventDeclineProposal:
|
||||||
signatureProposalParticipant.Status = internal.SignatureConfirmationDeclined
|
signatureProposalParticipant.Status = internal.SigConfirmationDeclined
|
||||||
default:
|
default:
|
||||||
err = errors.New("undefined {Event} for action")
|
err = errors.New("undefined {Event} for action")
|
||||||
return
|
return
|
||||||
|
@ -162,14 +162,14 @@ func (m *SignatureProposalFSM) actionValidateSignatureProposal(inEvent fsm.Event
|
||||||
|
|
||||||
unconfirmedParticipants := m.payload.SigQuorumCount()
|
unconfirmedParticipants := m.payload.SigQuorumCount()
|
||||||
for _, participant := range m.payload.SignatureProposalPayload.Quorum {
|
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) {
|
if participant.UpdatedAt.Add(config.SignatureProposalConfirmationDeadline).Before(tm) {
|
||||||
isContainsExpired = true
|
isContainsExpired = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if participant.Status == internal.SignatureConfirmationConfirmed {
|
if participant.Status == internal.SigConfirmationConfirmed {
|
||||||
unconfirmedParticipants--
|
unconfirmedParticipants--
|
||||||
} else if participant.Status == internal.SignatureConfirmationDeclined {
|
} else if participant.Status == internal.SigConfirmationDeclined {
|
||||||
isContainsDeclined = true
|
isContainsDeclined = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const (
|
||||||
eventDoneInternal = fsm.Event("event_sig_proposal_done")
|
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_canceled_participant")
|
||||||
|
|
||||||
StateSignatureProposalCollected = fsm.State("state_sig_proposal_collected")
|
StateSignatureProposalCollected = fsm.State("state_sig_proposal_collected")
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
FsmName,
|
FsmName,
|
||||||
fsm.StateGlobalIdle,
|
fsm.StateGlobalIdle,
|
||||||
[]fsm.EventDesc{
|
[]fsm.EventDesc{
|
||||||
// {Name: "", SrcState: []string{""}, DstState: ""},
|
// {Name: "", SrcState: []fsm.State{""}, DstState: ""},
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
{Name: EventInitProposal, SrcState: []fsm.State{StateParticipantsConfirmationsInit}, DstState: StateAwaitParticipantsConfirmations},
|
{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
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import "time"
|
||||||
// Events: "event_sig_proposal_init"
|
// Events: "event_sig_proposal_init"
|
||||||
type SignatureProposalParticipantsListRequest struct {
|
type SignatureProposalParticipantsListRequest struct {
|
||||||
Participants []*SignatureProposalParticipantsEntry
|
Participants []*SignatureProposalParticipantsEntry
|
||||||
|
SigningThreshold int
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,14 @@ func (r *SignatureProposalParticipantsListRequest) Validate() error {
|
||||||
return errors.New(fmt.Sprintf("too few participants, minimum is {%d}", config.ParticipantsMinCount))
|
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 {
|
for _, participant := range r.Participants {
|
||||||
if len(participant.Title) < 3 {
|
if len(participant.Title) < 3 {
|
||||||
return errors.New("{Title} minimum length is {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