dc4bc/fsm/state_machines/provider.go

182 lines
3.7 KiB
Go
Raw Normal View History

2020-07-28 07:52:05 -07:00
package state_machines
import (
2020-08-18 09:41:43 -07:00
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
2020-07-28 07:52:05 -07:00
"encoding/json"
"errors"
2020-08-07 06:08:37 -07:00
"strings"
2020-08-03 23:34:10 -07:00
2020-08-18 09:41:43 -07:00
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
2020-08-03 23:34:10 -07:00
"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"
2020-07-28 07:52:05 -07:00
)
const (
dkgTransactionIdLength = 128
)
2020-07-28 07:52:05 -07:00
// Is machine state scope dump will be locked?
type FSMDump struct {
2020-08-07 06:08:37 -07:00
TransactionId string
State fsm.State
Payload *internal.DumpedMachineStatePayload
2020-07-28 07:52:05 -07:00
}
type FSMInstance struct {
2020-08-07 06:08:37 -07:00
machine internal.DumpedMachineProvider
2020-07-28 07:52:05 -07:00
dump *FSMDump
}
var (
fsmPoolProvider *fsm_pool.FSMPool
2020-07-28 07:52:05 -07:00
)
func init() {
fsmPoolProvider = fsm_pool.Init(
signature_proposal_fsm.New(),
2020-08-06 17:20:13 -07:00
dkg_proposal_fsm.New(),
2020-07-28 07:52:05 -07:00
)
}
// Create new fsm with unique id
2020-08-08 05:33:34 -07:00
// transactionId required for unique identify dump
2020-08-18 09:41:43 -07:00
func Create(dkgID string) (*FSMInstance, error) {
var (
err error
i = &FSMInstance{}
)
2020-08-07 06:08:37 -07:00
2020-08-18 09:41:43 -07:00
err = i.InitDump(dkgID)
2020-08-07 06:08:37 -07:00
if err != nil {
return nil, err
2020-07-28 07:52:05 -07:00
}
2020-08-07 06:08:37 -07:00
machine, err := fsmPoolProvider.EntryPointMachine()
i.machine = machine.(internal.DumpedMachineProvider)
i.machine.SetUpPayload(i.dump.Payload)
return i, err
}
2020-08-12 06:40:03 -07:00
// DKGQuorumGet fsm from dump
2020-08-07 06:08:37 -07:00
func FromDump(data []byte) (*FSMInstance, error) {
var err error
2020-08-08 05:33:34 -07:00
if len(data) < 2 {
return nil, errors.New("machine dump is empty")
}
i := &FSMInstance{
dump: &FSMDump{},
}
2020-07-28 07:52:05 -07:00
err = i.dump.Unmarshal(data)
2020-08-08 05:33:34 -07:00
// TODO: Add logger
2020-07-28 07:52:05 -07:00
if err != nil {
return nil, errors.New("cannot read machine dump")
}
2020-08-07 06:08:37 -07:00
machine, err := fsmPoolProvider.MachineByState(i.dump.State)
i.machine = machine.(internal.DumpedMachineProvider)
i.machine.SetUpPayload(i.dump.Payload)
2020-07-28 07:52:05 -07:00
return i, err
}
2020-08-18 09:41:43 -07:00
func (i *FSMInstance) GetPubKeyByAddr(addr string) (ed25519.PublicKey, error) {
return ed25519.PublicKey{}, nil
}
2020-08-07 06:08:37 -07:00
func (i *FSMInstance) Do(event fsm.Event, args ...interface{}) (result *fsm.Response, dump []byte, err error) {
var dumpErr error
2020-08-11 01:56:11 -07:00
if i.machine == nil {
return nil, []byte{}, errors.New("machine is not initialized")
}
2020-08-07 06:08:37 -07:00
result, err = i.machine.Do(event, args...)
2020-07-28 07:52:05 -07:00
// On route errors result will be nil
if result != nil {
2020-08-07 06:08:37 -07:00
i.dump.State = result.State
2020-07-28 07:52:05 -07:00
2020-08-07 06:08:37 -07:00
dump, dumpErr = i.dump.Marshal()
if dumpErr != nil {
return result, []byte{}, err
2020-07-28 07:52:05 -07:00
}
}
return result, dump, err
}
2020-08-08 05:33:34 -07:00
func (i *FSMInstance) InitDump(transactionId string) error {
2020-08-07 06:08:37 -07:00
if i.dump != nil {
return errors.New("dump already initialized")
}
2020-08-08 05:33:34 -07:00
transactionId = strings.TrimSpace(transactionId)
2020-08-07 06:08:37 -07:00
2020-08-08 05:33:34 -07:00
if transactionId == "" {
2020-08-07 06:08:37 -07:00
return errors.New("empty transaction id")
}
i.dump = &FSMDump{
2020-08-11 01:56:11 -07:00
TransactionId: transactionId,
State: fsm.StateGlobalIdle,
2020-08-07 06:08:37 -07:00
Payload: &internal.DumpedMachineStatePayload{
2020-08-12 06:40:03 -07:00
TransactionId: transactionId,
SignatureProposalPayload: nil,
DKGProposalPayload: nil,
2020-08-07 06:08:37 -07:00
},
2020-07-28 07:52:05 -07:00
}
2020-08-07 06:08:37 -07:00
return nil
2020-07-28 07:52:05 -07:00
}
2020-08-11 01:56:11 -07:00
func (i *FSMInstance) State() (fsm.State, error) {
if i.machine == nil {
return "", errors.New("machine is not initialized")
}
return i.machine.State(), nil
}
func (i *FSMInstance) Id() string {
if i.dump != nil {
return i.dump.TransactionId
}
return ""
}
2020-08-11 09:46:18 -07:00
func (i *FSMInstance) Dump() ([]byte, error) {
if i.dump == nil {
return []byte{}, errors.New("dump is not initialized")
}
return i.dump.Marshal()
}
2020-07-28 07:52:05 -07:00
// TODO: Add encryption
func (d *FSMDump) Marshal() ([]byte, error) {
return json.Marshal(d)
}
// TODO: Add decryption
func (d *FSMDump) Unmarshal(data []byte) error {
2020-08-08 05:33:34 -07:00
if d == nil {
2020-08-11 09:46:18 -07:00
return errors.New("dump is not initialized")
2020-08-08 05:33:34 -07:00
}
2020-07-28 07:52:05 -07:00
return json.Unmarshal(data, d)
}
func generateDkgTransactionId() (string, error) {
b := make([]byte, dkgTransactionIdLength)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), err
}