mirror of https://github.com/certusone/dc4bc.git
feat: fixes, tests, actions
This commit is contained in:
parent
7e3121d500
commit
897c15672a
|
@ -2,19 +2,23 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/depools/dc4bc/fsm/fsm"
|
"github.com/depools/dc4bc/fsm/fsm"
|
||||||
|
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
||||||
"github.com/depools/dc4bc/fsm/types/responses"
|
"github.com/depools/dc4bc/fsm/types/responses"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/depools/dc4bc/fsm/state_machines"
|
"github.com/depools/dc4bc/fsm/state_machines"
|
||||||
"github.com/depools/dc4bc/fsm/types/requests"
|
"github.com/depools/dc4bc/fsm/types/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
tm := time.Now()
|
||||||
fsmMachine, err := state_machines.Create("d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257")
|
fsmMachine, err := state_machines.Create("d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257")
|
||||||
log.Println(fsmMachine, err)
|
log.Println(fsmMachine, err)
|
||||||
resp, dump, err := fsmMachine.Do(
|
resp, dump, err := fsmMachine.Do(
|
||||||
"event_proposal_init",
|
signature_proposal_fsm.EventInitProposal,
|
||||||
requests.SignatureProposalParticipantsListRequest{
|
requests.SignatureProposalParticipantsListRequest{
|
||||||
|
Participants: []*requests.SignatureProposalParticipantsEntry{
|
||||||
{
|
{
|
||||||
"John Doe",
|
"John Doe",
|
||||||
[]byte("pubkey123123"),
|
[]byte("pubkey123123"),
|
||||||
|
@ -28,8 +32,14 @@ func main() {
|
||||||
[]byte("pubkey789789"),
|
[]byte("pubkey789789"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
CreatedAt: &tm,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
log.Println("Err", err)
|
log.Println("Err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Println("Dump", string(dump))
|
log.Println("Dump", string(dump))
|
||||||
|
|
||||||
processResponse(resp)
|
processResponse(resp)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fsmName = "dkg_proposal_fsm"
|
FsmName = "dkg_proposal_fsm"
|
||||||
|
|
||||||
StateDkgInitial = signature_proposal_fsm.StateValidationCompleted
|
StateDkgInitial = signature_proposal_fsm.StateValidationCompleted
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ func New() internal.DumpedMachineProvider {
|
||||||
machine := &DKGProposalFSM{}
|
machine := &DKGProposalFSM{}
|
||||||
|
|
||||||
machine.FSM = fsm.MustNewFSM(
|
machine.FSM = fsm.MustNewFSM(
|
||||||
fsmName,
|
FsmName,
|
||||||
StateDkgInitial,
|
StateDkgInitial,
|
||||||
[]fsm.EventDesc{
|
[]fsm.EventDesc{
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,11 @@ type SignatureProposalQuorum map[string]SignatureProposalParticipant
|
||||||
type SignatureProposalParticipantStatus uint8
|
type SignatureProposalParticipantStatus uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PubKeyConAwaitConfirmation DKGProposalParticipantStatus = iota
|
SignatureConfirmationAwaitConfirmation DKGProposalParticipantStatus = iota
|
||||||
|
SignatureConfirmationConfirmed
|
||||||
|
SignatureConfirmationDeclined
|
||||||
|
SignatureConfirmationError
|
||||||
|
PubKeyConAwaitConfirmation
|
||||||
PubKeyConfirmed
|
PubKeyConfirmed
|
||||||
PubKeyConfirmationError
|
PubKeyConfirmationError
|
||||||
CommitAwaitConfirmation
|
CommitAwaitConfirmation
|
||||||
|
@ -68,6 +72,14 @@ type DKGProposalParticipantStatus uint8
|
||||||
func (s DKGProposalParticipantStatus) String() string {
|
func (s DKGProposalParticipantStatus) 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 PubKeyConAwaitConfirmation:
|
case PubKeyConAwaitConfirmation:
|
||||||
str = "PubKeyConAwaitConfirmation"
|
str = "PubKeyConAwaitConfirmation"
|
||||||
case PubKeyConfirmed:
|
case PubKeyConfirmed:
|
||||||
|
|
|
@ -36,11 +36,11 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new fsm with unique id
|
// Create new fsm with unique id
|
||||||
// Transaction id required for unique identify dump
|
// transactionId required for unique identify dump
|
||||||
func Create(tid string) (*FSMInstance, error) {
|
func Create(transactionId string) (*FSMInstance, error) {
|
||||||
var err error
|
var err error
|
||||||
i := &FSMInstance{}
|
i := &FSMInstance{}
|
||||||
err = i.InitDump(tid)
|
err = i.InitDump(transactionId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -56,9 +56,16 @@ func Create(tid string) (*FSMInstance, error) {
|
||||||
func FromDump(data []byte) (*FSMInstance, error) {
|
func FromDump(data []byte) (*FSMInstance, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
i := &FSMInstance{}
|
if len(data) < 2 {
|
||||||
|
return nil, errors.New("machine dump is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := &FSMInstance{
|
||||||
|
dump: &FSMDump{},
|
||||||
|
}
|
||||||
err = i.dump.Unmarshal(data)
|
err = i.dump.Unmarshal(data)
|
||||||
|
|
||||||
|
// TODO: Add logger
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("cannot read machine dump")
|
return nil, errors.New("cannot read machine dump")
|
||||||
}
|
}
|
||||||
|
@ -87,21 +94,21 @@ func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Resp
|
||||||
return result, dump, err
|
return result, dump, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *FSMInstance) InitDump(tid string) error {
|
func (i *FSMInstance) InitDump(transactionId string) error {
|
||||||
if i.dump != nil {
|
if i.dump != nil {
|
||||||
return errors.New("dump already initialized")
|
return errors.New("dump already initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
tid = strings.TrimSpace(tid)
|
transactionId = strings.TrimSpace(transactionId)
|
||||||
|
|
||||||
if tid == "" {
|
if transactionId == "" {
|
||||||
return errors.New("empty transaction id")
|
return errors.New("empty transaction id")
|
||||||
}
|
}
|
||||||
|
|
||||||
i.dump = &FSMDump{
|
i.dump = &FSMDump{
|
||||||
State: fsm.StateGlobalIdle,
|
State: fsm.StateGlobalIdle,
|
||||||
Payload: &internal.DumpedMachineStatePayload{
|
Payload: &internal.DumpedMachineStatePayload{
|
||||||
TransactionId: tid,
|
TransactionId: transactionId,
|
||||||
ConfirmationProposalPayload: nil,
|
ConfirmationProposalPayload: nil,
|
||||||
DKGProposalPayload: nil,
|
DKGProposalPayload: nil,
|
||||||
},
|
},
|
||||||
|
@ -116,5 +123,9 @@ func (d *FSMDump) Marshal() ([]byte, error) {
|
||||||
|
|
||||||
// TODO: Add decryption
|
// TODO: Add decryption
|
||||||
func (d *FSMDump) Unmarshal(data []byte) error {
|
func (d *FSMDump) Unmarshal(data []byte) error {
|
||||||
|
if d == nil {
|
||||||
|
return errors.New("dump struct is not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
return json.Unmarshal(data, d)
|
return json.Unmarshal(data, d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
package state_machines
|
||||||
|
|
||||||
|
import (
|
||||||
|
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"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testTransactionId = "d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tm = time.Now()
|
||||||
|
testParticipantsListRequest = requests.SignatureProposalParticipantsListRequest{
|
||||||
|
Participants: []*requests.SignatureProposalParticipantsEntry{
|
||||||
|
{
|
||||||
|
"User 1",
|
||||||
|
[]byte("pubkey123123"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User 2",
|
||||||
|
[]byte("pubkey456456"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User 3",
|
||||||
|
[]byte("pubkey789789"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CreatedAt: &tm,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreate_Positive(t *testing.T) {
|
||||||
|
testFSMInstance, err := Create(testTransactionId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected nil error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if testFSMInstance == nil {
|
||||||
|
t.Fatalf("expected {*FSMInstance}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate_Negative(t *testing.T) {
|
||||||
|
_, err := Create("")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error for empty {transactionId}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Workflow(t *testing.T) {
|
||||||
|
testFSMInstance, err := Create(testTransactionId)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected nil error, got {%s}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testFSMInstance == nil {
|
||||||
|
t.Fatalf("expected {*FSMInstance}")
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fsmResponse, dump, err := testFSMInstance.Do(spf.EventInitProposal, testParticipantsListRequest)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected nil error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dump) == 0 {
|
||||||
|
t.Fatalf("expected non zero dump, when executed without error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if fsmResponse == nil {
|
||||||
|
t.Fatalf("expected {*fsm.FSMResponse}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if fsmResponse.State != spf.StateAwaitParticipantsConfirmations {
|
||||||
|
t.Fatalf("expected state {%s}", spf.StateAwaitParticipantsConfirmations)
|
||||||
|
}
|
||||||
|
|
||||||
|
testParticipantsListResponse, ok := fsmResponse.Data.(responses.SignatureProposalParticipantInvitationsResponse)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected response {SignatureProposalParticipantInvitationsResponse}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(testParticipantsListResponse) != len(testParticipantsListRequest.Participants) {
|
||||||
|
t.Fatalf("expected response len {%d}, got {%d}", len(testParticipantsListRequest.Participants), len(testParticipantsListResponse))
|
||||||
|
}
|
||||||
|
|
||||||
|
participantsMap := map[int]*responses.SignatureProposalParticipantInvitationEntry{}
|
||||||
|
|
||||||
|
for _, participant := range testParticipantsListResponse {
|
||||||
|
if _, ok := participantsMap[participant.ParticipantId]; ok {
|
||||||
|
t.Fatalf("expected unique {ParticipantId}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if participant.Title == "" {
|
||||||
|
t.Fatalf("expected not empty {Title}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if participant.EncryptedInvitation == "" {
|
||||||
|
t.Fatalf("expected not empty {EncryptedInvitation}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if participant.PubKeyFingerprint == "" {
|
||||||
|
t.Fatalf("expected not empty {PubKeyFingerprint}")
|
||||||
|
}
|
||||||
|
|
||||||
|
participantsMap[participant.ParticipantId] = participant
|
||||||
|
}
|
||||||
|
|
||||||
|
tm = tm.Add(10 * time.Second)
|
||||||
|
|
||||||
|
testFSMInstance, err = FromDump(dump)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected nil error, got {%s}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testFSMInstance == nil {
|
||||||
|
t.Fatalf("expected {*FSMInstance}")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, participant := range participantsMap {
|
||||||
|
response, _, err := testFSMInstance.Do(spf.EventConfirmProposal, requests.SignatureProposalParticipantRequest{
|
||||||
|
PubKeyFingerprint: participant.PubKeyFingerprint,
|
||||||
|
EncryptedInvitation: "lll",
|
||||||
|
CreatedAt: &tm,
|
||||||
|
})
|
||||||
|
log.Println(response, err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,21 +34,28 @@ func (m *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
|
||||||
|
|
||||||
m.payload.ConfirmationProposalPayload = make(internal.SignatureProposalQuorum)
|
m.payload.ConfirmationProposalPayload = make(internal.SignatureProposalQuorum)
|
||||||
|
|
||||||
for participantIntId, participant := range request {
|
for index, participant := range request.Participants {
|
||||||
participantId := createFingerprint(&participant.PublicKey)
|
participantId := createFingerprint(&participant.PublicKey)
|
||||||
secret, err := generateRandomString(32)
|
secret, err := generateRandomString(32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("cannot generateRandomString")
|
return nil, errors.New("cannot generateRandomString")
|
||||||
}
|
}
|
||||||
m.payload.ConfirmationProposalPayload[participantId] = internal.SignatureProposalParticipant{
|
m.payload.ConfirmationProposalPayload[participantId] = internal.SignatureProposalParticipant{
|
||||||
ParticipantId: participantIntId,
|
ParticipantId: index,
|
||||||
Title: participant.Title,
|
Title: participant.Title,
|
||||||
PublicKey: participant.PublicKey,
|
PublicKey: participant.PublicKey,
|
||||||
InvitationSecret: secret,
|
InvitationSecret: secret,
|
||||||
UpdatedAt: nil,
|
Status: internal.SignatureAwaitConfirmation,
|
||||||
|
UpdatedAt: request.CreatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checking fo quorum length
|
||||||
|
if len(m.payload.ConfirmationProposalPayload) != len(request.Participants) {
|
||||||
|
err = errors.New("error with creating {SignatureProposalQuorum}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Make response
|
// Make response
|
||||||
|
|
||||||
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
|
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
|
||||||
|
@ -59,6 +66,7 @@ func (m *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
|
||||||
return nil, errors.New("cannot encryptWithPubKey")
|
return nil, errors.New("cannot encryptWithPubKey")
|
||||||
}
|
}
|
||||||
responseEntry := &responses.SignatureProposalParticipantInvitationEntry{
|
responseEntry := &responses.SignatureProposalParticipantInvitationEntry{
|
||||||
|
ParticipantId: proposal.ParticipantId,
|
||||||
Title: proposal.Title,
|
Title: proposal.Title,
|
||||||
PubKeyFingerprint: pubKeyFingerprint,
|
PubKeyFingerprint: pubKeyFingerprint,
|
||||||
EncryptedInvitation: encryptedInvitationSecret,
|
EncryptedInvitation: encryptedInvitationSecret,
|
||||||
|
@ -72,13 +80,8 @@ func (m *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
func (m *SignatureProposalFSM) actionConfirmProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
func (m *SignatureProposalFSM) actionProposalResponseByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
||||||
log.Println("I'm actionConfirmProposalByParticipant")
|
// SignatureProposalParticipantRequest
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SignatureProposalFSM) actionDeclineProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
|
||||||
log.Println("I'm actionDeclineProposalByParticipant")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package signature_proposal_fsm
|
package signature_proposal_fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ func ProposalParticipantsQuorumToResponse(list *internal.SignatureProposalQuorum
|
||||||
// Common functions
|
// Common functions
|
||||||
|
|
||||||
func createFingerprint(data *[]byte) string {
|
func createFingerprint(data *[]byte) string {
|
||||||
hash := sha256.Sum256(*data)
|
hash := sha1.Sum(*data)
|
||||||
return base64.StdEncoding.EncodeToString(hash[:])
|
return base64.StdEncoding.EncodeToString(hash[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fsmName = "signature_proposal_fsm"
|
FsmName = "signature_proposal_fsm"
|
||||||
signingIdLen = 32
|
signingIdLen = 32
|
||||||
|
|
||||||
StateAwaitParticipantsConfirmations = fsm.State("state_validation_await_participants_confirmations") // waiting participants
|
StateParticipantsConfirmationsInit = fsm.StateGlobalIdle
|
||||||
|
|
||||||
StateValidationCanceledByParticipant = fsm.State("state_validation_canceled_by_participant")
|
StateAwaitParticipantsConfirmations = fsm.State("state_sig_proposal_await_participants_confirmations") // waiting participants
|
||||||
StateValidationCanceledByTimeout = fsm.State("state_validation_canceled_by_timeout")
|
|
||||||
|
|
||||||
StateValidationCompleted = fsm.State("state_validation_completed")
|
StateValidationCanceledByParticipant = fsm.State("state_sig_proposal_canceled_by_participant")
|
||||||
|
StateValidationCanceledByTimeout = fsm.State("state_sig_proposal_canceled_by_timeout")
|
||||||
|
|
||||||
EventInitProposal = fsm.Event("event_proposal_init")
|
StateValidationCompleted = fsm.State("state_sig_proposal_completed")
|
||||||
EventConfirmProposal = fsm.Event("event_proposal_confirm_by_participant")
|
|
||||||
EventDeclineProposal = fsm.Event("event_proposal_decline_by_participant")
|
|
||||||
EventValidateProposal = fsm.Event("event_proposal_validate")
|
|
||||||
EventSetProposalValidated = fsm.Event("event_proposal_set_validated")
|
|
||||||
|
|
||||||
eventSetValidationCanceledByTimeout = fsm.Event("proposal_canceled_timeout")
|
EventInitProposal = fsm.Event("event_sig_proposal_init")
|
||||||
|
EventConfirmProposal = fsm.Event("event_sig_proposal_confirm_by_participant")
|
||||||
|
EventDeclineProposal = fsm.Event("event_sig_proposal_decline_by_participant")
|
||||||
|
EventValidateProposal = fsm.Event("event_sig_proposal_validate")
|
||||||
|
EventSetProposalValidated = fsm.Event("event_sig_proposal_set_validated")
|
||||||
|
|
||||||
|
eventSetValidationCanceledByTimeout = fsm.Event("event_sig_proposal_canceled_timeout")
|
||||||
|
|
||||||
// Switch to next fsm
|
// Switch to next fsm
|
||||||
|
|
||||||
|
@ -39,13 +41,13 @@ func New() internal.DumpedMachineProvider {
|
||||||
machine := &SignatureProposalFSM{}
|
machine := &SignatureProposalFSM{}
|
||||||
|
|
||||||
machine.FSM = fsm.MustNewFSM(
|
machine.FSM = fsm.MustNewFSM(
|
||||||
fsmName,
|
FsmName,
|
||||||
fsm.StateGlobalIdle,
|
fsm.StateGlobalIdle,
|
||||||
[]fsm.EventDesc{
|
[]fsm.EventDesc{
|
||||||
// {Name: "", SrcState: []string{""}, DstState: ""},
|
// {Name: "", SrcState: []string{""}, DstState: ""},
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
{Name: EventInitProposal, SrcState: []fsm.State{fsm.StateGlobalIdle}, 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: EventConfirmProposal, SrcState: []fsm.State{StateAwaitParticipantsConfirmations}, DstState: StateAwaitParticipantsConfirmations},
|
||||||
|
@ -64,8 +66,8 @@ func New() internal.DumpedMachineProvider {
|
||||||
},
|
},
|
||||||
fsm.Callbacks{
|
fsm.Callbacks{
|
||||||
EventInitProposal: machine.actionInitProposal,
|
EventInitProposal: machine.actionInitProposal,
|
||||||
EventConfirmProposal: machine.actionConfirmProposalByParticipant,
|
EventConfirmProposal: machine.actionProposalResponseByParticipant,
|
||||||
EventDeclineProposal: machine.actionDeclineProposalByParticipant,
|
EventDeclineProposal: machine.actionProposalResponseByParticipant,
|
||||||
EventValidateProposal: machine.actionValidateProposal,
|
EventValidateProposal: machine.actionValidateProposal,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
package requests
|
package requests
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
// Requests
|
// Requests
|
||||||
|
|
||||||
type SignatureProposalParticipantsListRequest []SignatureProposalParticipantsEntry
|
// States: "__idle"
|
||||||
|
// Events: "event_sig_proposal_init"
|
||||||
|
type SignatureProposalParticipantsListRequest struct {
|
||||||
|
Participants []*SignatureProposalParticipantsEntry
|
||||||
|
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
|
||||||
|
@ -10,8 +17,12 @@ type SignatureProposalParticipantsEntry struct {
|
||||||
PublicKey []byte
|
PublicKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// States: "__idle"
|
||||||
|
// Events: "event_sig_proposal_confirm_by_participant"
|
||||||
|
// "event_sig_proposal_decline_by_participant"
|
||||||
type SignatureProposalParticipantRequest struct {
|
type SignatureProposalParticipantRequest struct {
|
||||||
// Key for link invitations to participants
|
// Key for link invitations to participants
|
||||||
PubKeyFingerprint string
|
PubKeyFingerprint string
|
||||||
EncryptedInvitation string
|
EncryptedInvitation string
|
||||||
|
CreatedAt *time.Time
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,42 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *SignatureProposalParticipantsListRequest) Validate() error {
|
func (r *SignatureProposalParticipantsListRequest) Validate() error {
|
||||||
if len(*r) < config.ParticipantsMinCount {
|
if len(r.Participants) < config.ParticipantsMinCount {
|
||||||
return errors.New("too few participants")
|
return errors.New("too few participants")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, participant := range *r {
|
for _, participant := range r.Participants {
|
||||||
if len(participant.Title) < 3 {
|
if len(participant.Title) < 3 {
|
||||||
return errors.New("title too short")
|
return errors.New("{Title} too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(participant.Title) > 150 {
|
if len(participant.Title) > 150 {
|
||||||
return errors.New("title too long")
|
return errors.New("{Title} too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(participant.PublicKey) < 10 {
|
if len(participant.PublicKey) < 10 {
|
||||||
return errors.New("pub key too short")
|
return errors.New("{PublicKey} too short")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.CreatedAt == nil {
|
||||||
|
return errors.New("{CreatedAt} cannot be a nil")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SignatureProposalParticipantRequest) Validate() error {
|
func (r *SignatureProposalParticipantRequest) Validate() error {
|
||||||
|
if len(r.PubKeyFingerprint) == 0 {
|
||||||
|
return errors.New("{PubKeyFingerprint} cannot zero length")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.EncryptedInvitation) == 0 {
|
||||||
|
return errors.New("{EncryptedInvitation} cannot zero length")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.CreatedAt == nil {
|
||||||
|
return errors.New("{CreatedAt} cannot be a nil")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue