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

View File

@ -6,49 +6,49 @@ import (
)
// 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")
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")
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")
return
}
// 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")
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")
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")
return
}
// 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")
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")
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")
return
}

View File

@ -2,8 +2,9 @@ package dkg_proposal_fsm
import (
"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"
"sync"
)
const (
@ -67,9 +68,11 @@ const (
type DKGProposalFSM struct {
*fsm.FSM
payload *internal.DumpedMachineStatePayload
payloadMu sync.RWMutex
}
func New() fsm_pool.MachineProvider {
func New() internal.DumpedMachineProvider {
machine := &DKGProposalFSM{}
machine.FSM = fsm.MustNewFSM(
@ -131,3 +134,10 @@ func New() fsm_pool.MachineProvider {
)
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
type MachineStatePayload struct {
ConfirmationProposalPayload ConfirmationProposalPrivateQuorum
DKGProposalPayload DKGProposalPrivateQuorum
import "github.com/depools/dc4bc/fsm/fsm_pool"
type DumpedMachineStatePayload struct {
TransactionId string
ConfirmationProposalPayload SignatureProposalQuorum
DKGProposalPayload DKGProposalQuorum
}
// Using combine response for modify data with chain
// User value or pointer? How about memory state?
type MachineCombinedResponse struct {
Response interface{}
Payload *MachineStatePayload
type DumpedMachineProvider interface {
fsm_pool.MachineProvider
SetUpPayload(payload *DumpedMachineStatePayload)
}

View File

@ -2,27 +2,58 @@ package internal
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
ParticipantId int
Title string
PublicKey []byte
// For validation user confirmation: sign(InvitationSecret, PublicKey) => user
InvitationSecret string
ConfirmedAt *time.Time
Status SignatureProposalParticipantStatus
UpdatedAt *time.Time
}
// Unique alias for map iteration - Public Key Fingerprint
// 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
PublicKey []byte
Commit []byte
Deal []byte
Status DKGProposalParticipantStatus
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"
"errors"
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
"strings"
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/fsm_pool"
@ -13,13 +14,13 @@ import (
// Is machine state scope dump will be locked?
type FSMDump struct {
Id string
State fsm.State
Payload internal.MachineStatePayload
TransactionId string
State fsm.State
Payload *internal.DumpedMachineStatePayload
}
type FSMInstance struct {
machine fsm_pool.MachineProvider
machine internal.DumpedMachineProvider
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
i := &FSMInstance{}
if len(data) == 0 {
i.InitDump()
i.machine, err = fsmPoolProvider.EntryPointMachine()
return i, err // Create machine
err = i.InitDump(tid)
if err != nil {
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)
if err != nil {
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
}
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (*fsm.Response, []byte, error) {
// Provide payload as first argument ever
result, err := i.machine.Do(event, append([]interface{}{i.dump.Payload}, args...)...)
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Response, dump []byte, err error) {
var dumpErr error
result, err = i.machine.Do(event, args...)
// On route errors result will be 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
}
dump, dumpErr := i.dump.Marshal()
if dumpErr != nil {
return result, []byte{}, err
dump, dumpErr = i.dump.Marshal()
if dumpErr != nil {
return result, []byte{}, err
}
}
return result, dump, err
}
func (i *FSMInstance) InitDump() {
if i.dump == nil {
i.dump = &FSMDump{
State: fsm.StateGlobalIdle,
}
func (i *FSMInstance) InitDump(tid string) error {
if i.dump != nil {
return errors.New("dump already initialized")
}
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

View File

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

View File

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

View File

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