Merge branch 'master' into feat/client-fsm

This commit is contained in:
programmer10110 2020-08-07 16:55:23 +03:00
commit 80b03b2572
9 changed files with 147 additions and 104 deletions

View File

@ -10,11 +10,10 @@ import (
) )
func main() { func main() {
fsmMachine, err := state_machines.New([]byte{}) 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", "event_proposal_init",
"d8a928b2043db77e340b523547bf16cb4aa483f0645fe0a290ed1f20aab76257",
requests.SignatureProposalParticipantsListRequest{ requests.SignatureProposalParticipantsListRequest{
{ {
"John Doe", "John Doe",
@ -40,7 +39,7 @@ func main() {
func processResponse(resp *fsm.Response) { func processResponse(resp *fsm.Response) {
switch resp.State { switch resp.State {
// Await proposals // Await proposals
case fsm.State("validate_proposal"): case fsm.State("state_validation_await_participants_confirmations"):
data, ok := resp.Data.(responses.SignatureProposalParticipantInvitationsResponse) data, ok := resp.Data.(responses.SignatureProposalParticipantInvitationsResponse)
if !ok { if !ok {
log.Printf("undefined response type for state \"%s\"\n", resp.State) log.Printf("undefined response type for state \"%s\"\n", resp.State)

View File

@ -6,49 +6,49 @@ import (
) )
// Pub keys // Pub keys
func (s *DKGProposalFSM) actionDKGPubKeysSent(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGPubKeysSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeysSent") log.Println("I'm actionDKGPubKeysSent")
return return
} }
func (s *DKGProposalFSM) actionDKGPubKeyConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGPubKeyConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeyConfirmationReceived") log.Println("I'm actionDKGPubKeyConfirmationReceived")
return return
} }
func (s *DKGProposalFSM) actionDKGPubKeyConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGPubKeyConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGPubKeyConfirmationError") log.Println("I'm actionDKGPubKeyConfirmationError")
return return
} }
// Commits // Commits
func (s *DKGProposalFSM) actionDKGCommitsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGCommitsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitsSent") log.Println("I'm actionDKGCommitsSent")
return return
} }
func (s *DKGProposalFSM) actionDKGCommitConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGCommitConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitConfirmationReceived") log.Println("I'm actionDKGCommitConfirmationReceived")
return return
} }
func (s *DKGProposalFSM) actionDKGCommitConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGCommitConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGCommitConfirmationError") log.Println("I'm actionDKGCommitConfirmationError")
return return
} }
// Deals // Deals
func (s *DKGProposalFSM) actionDKGDealsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGDealsSent(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealsSent") log.Println("I'm actionDKGDealsSent")
return return
} }
func (s *DKGProposalFSM) actionDKGDealConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGDealConfirmationReceived(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealConfirmationReceived") log.Println("I'm actionDKGDealConfirmationReceived")
return return
} }
func (s *DKGProposalFSM) actionDKGDealConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *DKGProposalFSM) actionDKGDealConfirmationError(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDKGDealConfirmationError") log.Println("I'm actionDKGDealConfirmationError")
return return
} }

View File

@ -2,8 +2,9 @@ package dkg_proposal_fsm
import ( import (
"github.com/depools/dc4bc/fsm/fsm" "github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool" "github.com/depools/dc4bc/fsm/state_machines/internal"
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm" "github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
"sync"
) )
const ( const (
@ -67,9 +68,11 @@ const (
type DKGProposalFSM struct { type DKGProposalFSM struct {
*fsm.FSM *fsm.FSM
payload *internal.DumpedMachineStatePayload
payloadMu sync.RWMutex
} }
func New() fsm_pool.MachineProvider { func New() internal.DumpedMachineProvider {
machine := &DKGProposalFSM{} machine := &DKGProposalFSM{}
machine.FSM = fsm.MustNewFSM( machine.FSM = fsm.MustNewFSM(
@ -131,3 +134,10 @@ func New() fsm_pool.MachineProvider {
) )
return machine return machine
} }
func (m *DKGProposalFSM) SetUpPayload(payload *internal.DumpedMachineStatePayload) {
m.payloadMu.Lock()
defer m.payloadMu.Unlock()
m.payload = payload
}

View File

@ -1,13 +1,14 @@
package internal package internal
type MachineStatePayload struct { import "github.com/depools/dc4bc/fsm/fsm_pool"
ConfirmationProposalPayload ConfirmationProposalPrivateQuorum
DKGProposalPayload DKGProposalPrivateQuorum type DumpedMachineStatePayload struct {
TransactionId string
ConfirmationProposalPayload SignatureProposalQuorum
DKGProposalPayload DKGProposalQuorum
} }
// Using combine response for modify data with chain type DumpedMachineProvider interface {
// User value or pointer? How about memory state? fsm_pool.MachineProvider
type MachineCombinedResponse struct { SetUpPayload(payload *DumpedMachineStatePayload)
Response interface{}
Payload *MachineStatePayload
} }

View File

@ -2,27 +2,58 @@ package internal
import "time" import "time"
type ProposalParticipantPrivate struct { const (
SignatureAwaitConfirmation SignatureProposalParticipantStatus = iota
SignatureConfirmed
)
type ConfirmationProposal struct {
Quorum SignatureProposalQuorum
CreatedAt *time.Time
ExpiresAt *time.Time
}
type SignatureProposalParticipant struct {
// Public title for address, such as name, nickname, organization // Public title for address, such as name, nickname, organization
ParticipantId int ParticipantId int
Title string Title string
PublicKey []byte PublicKey []byte
// For validation user confirmation: sign(InvitationSecret, PublicKey) => user // For validation user confirmation: sign(InvitationSecret, PublicKey) => user
InvitationSecret string InvitationSecret string
ConfirmedAt *time.Time Status SignatureProposalParticipantStatus
UpdatedAt *time.Time
} }
// Unique alias for map iteration - Public Key Fingerprint // Unique alias for map iteration - Public Key Fingerprint
// Excludes array merge and rotate operations // Excludes array merge and rotate operations
type SignatureProposalQuorum map[string]SignatureProposalParticipant
type ConfirmationProposalPrivateQuorum map[string]ProposalParticipantPrivate type SignatureProposalParticipantStatus uint8
type ProposalDKGParticipantPrivate struct { const (
PubKeyConAwaitConfirmation DKGProposalParticipantStatus = iota
PubKeyConfirmed
CommitAwaitConfirmation
CommitConfirmed
DealAwaitConfirmation
DealConfirmed
)
type DKGProposal struct {
Quorum map[int]DKGProposalParticipant
CreatedAt *time.Time
ExpiresAt *time.Time
}
type DKGProposalParticipant struct {
Title string Title string
PublicKey []byte PublicKey []byte
Commit []byte Commit []byte
Deal []byte Deal []byte
Status DKGProposalParticipantStatus
UpdatedAt *time.Time UpdatedAt *time.Time
} }
type DKGProposalPrivateQuorum map[int]ProposalParticipantPrivate type DKGProposalQuorum map[int]DKGProposalParticipant
type DKGProposalParticipantStatus uint8

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm" "github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
"strings"
"github.com/depools/dc4bc/fsm/fsm" "github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool" "github.com/depools/dc4bc/fsm/fsm_pool"
@ -13,13 +14,13 @@ import (
// Is machine state scope dump will be locked? // Is machine state scope dump will be locked?
type FSMDump struct { type FSMDump struct {
Id string TransactionId string
State fsm.State State fsm.State
Payload internal.MachineStatePayload Payload *internal.DumpedMachineStatePayload
} }
type FSMInstance struct { type FSMInstance struct {
machine fsm_pool.MachineProvider machine internal.DumpedMachineProvider
dump *FSMDump dump *FSMDump
} }
@ -34,58 +35,76 @@ func init() {
) )
} }
func New(data []byte) (*FSMInstance, error) { // Transaction id required for unique identify dump
func Create(tid string) (*FSMInstance, error) {
var err error var err error
i := &FSMInstance{} i := &FSMInstance{}
if len(data) == 0 { err = i.InitDump(tid)
i.InitDump()
i.machine, err = fsmPoolProvider.EntryPointMachine() if err != nil {
return i, err // Create machine return nil, err
} }
machine, err := fsmPoolProvider.EntryPointMachine()
i.machine = machine.(internal.DumpedMachineProvider)
i.machine.SetUpPayload(i.dump.Payload)
return i, err
}
func FromDump(data []byte) (*FSMInstance, error) {
var err error
i := &FSMInstance{}
err = i.dump.Unmarshal(data) err = i.dump.Unmarshal(data)
if err != nil { if err != nil {
return nil, errors.New("cannot read machine dump") return nil, errors.New("cannot read machine dump")
} }
i.machine, err = fsmPoolProvider.MachineByState(i.dump.State) machine, err := fsmPoolProvider.MachineByState(i.dump.State)
i.machine = machine.(internal.DumpedMachineProvider)
i.machine.SetUpPayload(i.dump.Payload)
return i, err return i, err
} }
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (*fsm.Response, []byte, error) { func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Response, dump []byte, err error) {
// Provide payload as first argument ever var dumpErr error
result, err := i.machine.Do(event, append([]interface{}{i.dump.Payload}, args...)...)
result, err = i.machine.Do(event, args...)
// On route errors result will be nil // On route errors result will be nil
if result != nil { if result != nil {
// Proxying combined response, separate payload and data
if result.Data != nil {
if r, ok := result.Data.(internal.MachineCombinedResponse); ok {
i.dump.Payload = *r.Payload
result.Data = r.Response
} else {
return nil, []byte{}, errors.New("cannot cast callback response")
}
}
i.dump.State = result.State i.dump.State = result.State
}
dump, dumpErr := i.dump.Marshal() dump, dumpErr = i.dump.Marshal()
if dumpErr != nil { if dumpErr != nil {
return result, []byte{}, err return result, []byte{}, err
}
} }
return result, dump, err return result, dump, err
} }
func (i *FSMInstance) InitDump() { func (i *FSMInstance) InitDump(tid string) error {
if i.dump == nil { if i.dump != nil {
i.dump = &FSMDump{ return errors.New("dump already initialized")
State: fsm.StateGlobalIdle,
}
} }
tid = strings.TrimSpace(tid)
if tid == "" {
return errors.New("empty transaction id")
}
i.dump = &FSMDump{
State: fsm.StateGlobalIdle,
Payload: &internal.DumpedMachineStatePayload{
TransactionId: tid,
ConfirmationProposalPayload: nil,
DKGProposalPayload: nil,
},
}
return nil
} }
// TODO: Add encryption // TODO: Add encryption

View File

@ -12,40 +12,16 @@ import (
// init -> awaitingConfirmations // init -> awaitingConfirmations
// args: payload, signing id, participants list // args: payload, signing id, participants list
func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...interface{}) (response interface{}, err error) {
var payload internal.MachineStatePayload m.payloadMu.Lock()
// Init proposal defer m.payloadMu.Unlock()
log.Println("I'm actionInitProposal")
if len(args) < 3 { if len(args) != 1 {
err = errors.New("payload and signing id required and participants list required") err = errors.New("participants list required")
return return
} }
if len(args) > 3 { request, ok := args[0].(requests.SignatureProposalParticipantsListRequest)
err = errors.New("too many arguments")
return
}
payload, ok := args[0].(internal.MachineStatePayload)
if !ok {
err = errors.New("cannot cast payload")
return
}
signingId, ok := args[1].(string)
if !ok {
err = errors.New("cannot cast signing id, awaiting string value")
return
}
if len(signingId) < signingIdLen {
err = errors.New("signing id to short ")
return
}
request, ok := args[2].(requests.SignatureProposalParticipantsListRequest)
if !ok { if !ok {
err = errors.New("cannot cast participants list") err = errors.New("cannot cast participants list")
@ -56,7 +32,7 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
return return
} }
payload.ConfirmationProposalPayload = make(internal.ConfirmationProposalPrivateQuorum) m.payload.ConfirmationProposalPayload = make(internal.SignatureProposalQuorum)
for participantIntId, participant := range request { for participantIntId, participant := range request {
participantId := createFingerprint(&participant.PublicKey) participantId := createFingerprint(&participant.PublicKey)
@ -64,12 +40,12 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
if err != nil { if err != nil {
return nil, errors.New("cannot generateRandomString") return nil, errors.New("cannot generateRandomString")
} }
payload.ConfirmationProposalPayload[participantId] = internal.ProposalParticipantPrivate{ m.payload.ConfirmationProposalPayload[participantId] = internal.SignatureProposalParticipant{
ParticipantId: participantIntId, ParticipantId: participantIntId,
Title: participant.Title, Title: participant.Title,
PublicKey: participant.PublicKey, PublicKey: participant.PublicKey,
InvitationSecret: secret, InvitationSecret: secret,
ConfirmedAt: nil, UpdatedAt: nil,
} }
} }
@ -77,7 +53,7 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0) responseData := make(responses.SignatureProposalParticipantInvitationsResponse, 0)
for pubKeyFingerprint, proposal := range payload.ConfirmationProposalPayload { for pubKeyFingerprint, proposal := range m.payload.ConfirmationProposalPayload {
encryptedInvitationSecret, err := encryptWithPubKey(proposal.PublicKey, proposal.InvitationSecret) encryptedInvitationSecret, err := encryptWithPubKey(proposal.PublicKey, proposal.InvitationSecret)
if err != nil { if err != nil {
return nil, errors.New("cannot encryptWithPubKey") return nil, errors.New("cannot encryptWithPubKey")
@ -92,24 +68,21 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
// Change state // Change state
return internal.MachineCombinedResponse{ return responseData, nil
Response: responseData,
Payload: &payload,
}, nil
} }
// //
func (s *SignatureProposalFSM) actionConfirmProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *SignatureProposalFSM) actionConfirmProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionConfirmProposalByParticipant") log.Println("I'm actionConfirmProposalByParticipant")
return return
} }
func (s *SignatureProposalFSM) actionDeclineProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *SignatureProposalFSM) actionDeclineProposalByParticipant(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionDeclineProposalByParticipant") log.Println("I'm actionDeclineProposalByParticipant")
return return
} }
func (s *SignatureProposalFSM) actionValidateProposal(event fsm.Event, args ...interface{}) (response interface{}, err error) { func (m *SignatureProposalFSM) actionValidateProposal(event fsm.Event, args ...interface{}) (response interface{}, err error) {
log.Println("I'm actionValidateProposal") log.Println("I'm actionValidateProposal")
return return
} }

View File

@ -11,7 +11,7 @@ import (
// Request and response mutators // Request and response mutators
func ProposalParticipantsQuorumToResponse(list *internal.ConfirmationProposalPrivateQuorum) responses.SignatureProposalParticipantInvitationsResponse { func ProposalParticipantsQuorumToResponse(list *internal.SignatureProposalQuorum) responses.SignatureProposalParticipantInvitationsResponse {
var response responses.SignatureProposalParticipantInvitationsResponse var response responses.SignatureProposalParticipantInvitationsResponse
for quorumId, parcipant := range *list { for quorumId, parcipant := range *list {
response = append(response, &responses.SignatureProposalParticipantInvitationEntry{ response = append(response, &responses.SignatureProposalParticipantInvitationEntry{

View File

@ -2,7 +2,8 @@ package signature_proposal_fsm
import ( import (
"github.com/depools/dc4bc/fsm/fsm" "github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool" "github.com/depools/dc4bc/fsm/state_machines/internal"
"sync"
) )
const ( const (
@ -30,9 +31,11 @@ const (
type SignatureProposalFSM struct { type SignatureProposalFSM struct {
*fsm.FSM *fsm.FSM
payload *internal.DumpedMachineStatePayload
payloadMu sync.RWMutex
} }
func New() fsm_pool.MachineProvider { func New() internal.DumpedMachineProvider {
machine := &SignatureProposalFSM{} machine := &SignatureProposalFSM{}
machine.FSM = fsm.MustNewFSM( machine.FSM = fsm.MustNewFSM(
@ -68,3 +71,10 @@ func New() fsm_pool.MachineProvider {
) )
return machine return machine
} }
func (m *SignatureProposalFSM) SetUpPayload(payload *internal.DumpedMachineStatePayload) {
m.payloadMu.Lock()
defer m.payloadMu.Unlock()
m.payload = payload
}