Skip to content

Commit

Permalink
Merge pull request #190 from cloudstruct/docs/protocol-localtxsubmiss…
Browse files Browse the repository at this point in the history
…ion-package

docs: code docs for protocol/localtxsubmission
  • Loading branch information
agaffney authored Feb 9, 2023
2 parents 0c7536c + d6f58ae commit cb421c9
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 45 deletions.
20 changes: 12 additions & 8 deletions protocol/localtxsubmission/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"sync"
)

// Client implements the LocalTxSubmission client
type Client struct {
*protocol.Protocol
config *Config
busyMutex sync.Mutex
submitResultChan chan error
}

// NewClient returns a new LocalTxSubmission client object
func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
if cfg == nil {
tmpCfg := NewConfig()
Expand All @@ -25,22 +27,22 @@ func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
}
// Update state map with timeout
stateMap := StateMap.Copy()
if entry, ok := stateMap[STATE_BUSY]; ok {
if entry, ok := stateMap[stateBusy]; ok {
entry.Timeout = c.config.Timeout
stateMap[STATE_BUSY] = entry
stateMap[stateBusy] = entry
}
// Configure underlying Protocol
protoConfig := protocol.ProtocolConfig{
Name: PROTOCOL_NAME,
ProtocolId: PROTOCOL_ID,
Name: protocolName,
ProtocolId: protocolId,
Muxer: protoOptions.Muxer,
ErrorChan: protoOptions.ErrorChan,
Mode: protoOptions.Mode,
Role: protocol.ProtocolRoleClient,
MessageHandlerFunc: c.messageHandler,
MessageFromCborFunc: NewMsgFromCbor,
StateMap: stateMap,
InitialState: STATE_IDLE,
InitialState: stateIdle,
}
c.Protocol = protocol.New(protoConfig)
// Start goroutine to cleanup resources on protocol shutdown
Expand All @@ -54,16 +56,17 @@ func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
func (c *Client) messageHandler(msg protocol.Message, isResponse bool) error {
var err error
switch msg.Type() {
case MESSAGE_TYPE_ACCEPT_TX:
case MessageTypeAcceptTx:
err = c.handleAcceptTx()
case MESSAGE_TYPE_REJECT_TX:
case MessageTypeRejectTx:
err = c.handleRejectTx(msg)
default:
err = fmt.Errorf("%s: received unexpected message type %d", PROTOCOL_NAME, msg.Type())
err = fmt.Errorf("%s: received unexpected message type %d", protocolName, msg.Type())
}
return err
}

// SubmitTx submits a transaction using the specified transaction era ID and TX payload
func (c *Client) SubmitTx(eraId uint16, tx []byte) error {
c.busyMutex.Lock()
defer c.busyMutex.Unlock()
Expand All @@ -75,6 +78,7 @@ func (c *Client) SubmitTx(eraId uint16, tx []byte) error {
return err
}

// Stop transations the protocol to the Done state. No more operations will be possible
func (c *Client) Stop() error {
c.busyMutex.Lock()
defer c.busyMutex.Unlock()
Expand Down
1 change: 1 addition & 0 deletions protocol/localtxsubmission/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
)

// TransactionRejectedError represents an explicit transaction rejection
type TransactionRejectedError struct {
ReasonCbor []byte
Reason error
Expand Down
38 changes: 24 additions & 14 deletions protocol/localtxsubmission/localtxsubmission.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package localtxsubmission implements the Ouroboros local-tx-submission protocol
package localtxsubmission

import (
Expand All @@ -6,50 +7,54 @@ import (
"github.com/cloudstruct/go-ouroboros-network/protocol"
)

// Protocol identifiers
const (
PROTOCOL_NAME = "local-tx-submission"
PROTOCOL_ID uint16 = 6
protocolName = "local-tx-submission"
protocolId uint16 = 6
)

var (
STATE_IDLE = protocol.NewState(1, "Idle")
STATE_BUSY = protocol.NewState(2, "Busy")
STATE_DONE = protocol.NewState(3, "Done")
stateIdle = protocol.NewState(1, "Idle")
stateBusy = protocol.NewState(2, "Busy")
stateDone = protocol.NewState(3, "Done")
)

// LocalTxSubmission protocol state machine
var StateMap = protocol.StateMap{
STATE_IDLE: protocol.StateMapEntry{
stateIdle: protocol.StateMapEntry{
Agency: protocol.AgencyClient,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_SUBMIT_TX,
NewState: STATE_BUSY,
MsgType: MessageTypeSubmitTx,
NewState: stateBusy,
},
},
},
STATE_BUSY: protocol.StateMapEntry{
stateBusy: protocol.StateMapEntry{
Agency: protocol.AgencyServer,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_ACCEPT_TX,
NewState: STATE_IDLE,
MsgType: MessageTypeAcceptTx,
NewState: stateIdle,
},
{
MsgType: MESSAGE_TYPE_REJECT_TX,
NewState: STATE_IDLE,
MsgType: MessageTypeRejectTx,
NewState: stateIdle,
},
},
},
STATE_DONE: protocol.StateMapEntry{
stateDone: protocol.StateMapEntry{
Agency: protocol.AgencyNone,
},
}

// LocalTxSubmission is a wrapper object that holds the client and server instances
type LocalTxSubmission struct {
Client *Client
Server *Server
}

// Config is used to configure the LocalTxSubmission protocol instance
type Config struct {
SubmitTxFunc SubmitTxFunc
Timeout time.Duration
Expand All @@ -58,6 +63,7 @@ type Config struct {
// Callback function types
type SubmitTxFunc func(interface{}) error

// New returns a new LocalTxSubmission object
func New(protoOptions protocol.ProtocolOptions, cfg *Config) *LocalTxSubmission {
l := &LocalTxSubmission{
Client: NewClient(protoOptions, cfg),
Expand All @@ -66,8 +72,10 @@ func New(protoOptions protocol.ProtocolOptions, cfg *Config) *LocalTxSubmission
return l
}

// LocalTxSubmissionOptionFunc represents a function used to modify the LocalTxSubmission protocol config
type LocalTxSubmissionOptionFunc func(*Config)

// NewConfig returns a new LocalTxSubmission config object with the provided options
func NewConfig(options ...LocalTxSubmissionOptionFunc) Config {
c := Config{
Timeout: 30 * time.Second,
Expand All @@ -79,12 +87,14 @@ func NewConfig(options ...LocalTxSubmissionOptionFunc) Config {
return c
}

// WithSubmitTxFunc specifies the callback function when a TX is submitted when acting as a server
func WithSubmitTxFunc(submitTxFunc SubmitTxFunc) LocalTxSubmissionOptionFunc {
return func(c *Config) {
c.SubmitTxFunc = submitTxFunc
}
}

// WithTimeout specifies the timeout for a TX submit operation when acting as a client
func WithTimeout(timeout time.Duration) LocalTxSubmissionOptionFunc {
return func(c *Config) {
c.Timeout = timeout
Expand Down
29 changes: 16 additions & 13 deletions protocol/localtxsubmission/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,35 @@ package localtxsubmission

import (
"fmt"

"github.com/cloudstruct/go-ouroboros-network/protocol"
"github.com/cloudstruct/go-ouroboros-network/utils"
"github.com/fxamacker/cbor/v2"
)

// Message types
const (
MESSAGE_TYPE_SUBMIT_TX = 0
MESSAGE_TYPE_ACCEPT_TX = 1
MESSAGE_TYPE_REJECT_TX = 2
MESSAGE_TYPE_DONE = 3
MessageTypeSubmitTx = 0
MessageTypeAcceptTx = 1
MessageTypeRejectTx = 2
MessageTypeDone = 3
)

// NewMsgFromCbor parses a LocalTxSubmission message from CBOR
func NewMsgFromCbor(msgType uint, data []byte) (protocol.Message, error) {
var ret protocol.Message
switch msgType {
case MESSAGE_TYPE_SUBMIT_TX:
case MessageTypeSubmitTx:
ret = &MsgSubmitTx{}
case MESSAGE_TYPE_ACCEPT_TX:
case MessageTypeAcceptTx:
ret = &MsgAcceptTx{}
case MESSAGE_TYPE_REJECT_TX:
case MessageTypeRejectTx:
ret = &MsgRejectTx{}
case MESSAGE_TYPE_DONE:
case MessageTypeDone:
ret = &MsgDone{}
}
if _, err := utils.CborDecode(data, ret); err != nil {
return nil, fmt.Errorf("%s: decode error: %s", PROTOCOL_NAME, err)
return nil, fmt.Errorf("%s: decode error: %s", protocolName, err)
}
if ret != nil {
// Store the raw message CBOR
Expand All @@ -51,7 +54,7 @@ type MsgSubmitTxTransaction struct {
func NewMsgSubmitTx(eraId uint16, tx []byte) *MsgSubmitTx {
m := &MsgSubmitTx{
MessageBase: protocol.MessageBase{
MessageType: MESSAGE_TYPE_SUBMIT_TX,
MessageType: MessageTypeSubmitTx,
},
Transaction: MsgSubmitTxTransaction{
EraId: eraId,
Expand All @@ -72,7 +75,7 @@ type MsgAcceptTx struct {
func NewMsgAcceptTx() *MsgAcceptTx {
m := &MsgAcceptTx{
MessageBase: protocol.MessageBase{
MessageType: MESSAGE_TYPE_ACCEPT_TX,
MessageType: MessageTypeAcceptTx,
},
}
return m
Expand All @@ -88,7 +91,7 @@ type MsgRejectTx struct {
func NewMsgRejectTx(reasonCbor []byte) *MsgRejectTx {
m := &MsgRejectTx{
MessageBase: protocol.MessageBase{
MessageType: MESSAGE_TYPE_REJECT_TX,
MessageType: MessageTypeRejectTx,
},
Reason: cbor.RawMessage(reasonCbor),
}
Expand All @@ -102,7 +105,7 @@ type MsgDone struct {
func NewMsgDone() *MsgDone {
m := &MsgDone{
MessageBase: protocol.MessageBase{
MessageType: MESSAGE_TYPE_DONE,
MessageType: MessageTypeDone,
},
}
return m
Expand Down
8 changes: 4 additions & 4 deletions protocol/localtxsubmission/messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,23 @@ var placeholderRejectError = hexDecode("820204")
var tests = []testDefinition{
{
CborHex: fmt.Sprintf("82008204d81846%x", placeholderTx),
MessageType: MESSAGE_TYPE_SUBMIT_TX,
MessageType: MessageTypeSubmitTx,
Message: NewMsgSubmitTx(ledger.TX_TYPE_ALONZO, placeholderTx),
},
{
CborHex: "8101",
Message: NewMsgAcceptTx(),
MessageType: MESSAGE_TYPE_ACCEPT_TX,
MessageType: MessageTypeAcceptTx,
},
{
CborHex: fmt.Sprintf("8202%x", placeholderRejectError),
MessageType: MESSAGE_TYPE_REJECT_TX,
MessageType: MessageTypeRejectTx,
Message: NewMsgRejectTx(placeholderRejectError),
},
{
CborHex: "8103",
Message: NewMsgDone(),
MessageType: MESSAGE_TYPE_DONE,
MessageType: MessageTypeDone,
},
}

Expand Down
14 changes: 8 additions & 6 deletions protocol/localtxsubmission/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,28 @@ import (
"github.com/cloudstruct/go-ouroboros-network/protocol"
)

// Server implements the LocalTxSubmission server
type Server struct {
*protocol.Protocol
config *Config
}

// NewServer returns a new Server object
func NewServer(protoOptions protocol.ProtocolOptions, cfg *Config) *Server {
s := &Server{
config: cfg,
}
protoConfig := protocol.ProtocolConfig{
Name: PROTOCOL_NAME,
ProtocolId: PROTOCOL_ID,
Name: protocolName,
ProtocolId: protocolId,
Muxer: protoOptions.Muxer,
ErrorChan: protoOptions.ErrorChan,
Mode: protoOptions.Mode,
Role: protocol.ProtocolRoleServer,
MessageHandlerFunc: s.messageHandler,
MessageFromCborFunc: NewMsgFromCbor,
StateMap: StateMap,
InitialState: STATE_IDLE,
InitialState: stateIdle,
}
s.Protocol = protocol.New(protoConfig)
return s
Expand All @@ -33,12 +35,12 @@ func NewServer(protoOptions protocol.ProtocolOptions, cfg *Config) *Server {
func (s *Server) messageHandler(msg protocol.Message, isResponse bool) error {
var err error
switch msg.Type() {
case MESSAGE_TYPE_SUBMIT_TX:
case MessageTypeSubmitTx:
err = s.handleSubmitTx(msg)
case MESSAGE_TYPE_DONE:
case MessageTypeDone:
err = s.handleDone()
default:
err = fmt.Errorf("%s: received unexpected message type %d", PROTOCOL_NAME, msg.Type())
err = fmt.Errorf("%s: received unexpected message type %d", protocolName, msg.Type())
}
return err
}
Expand Down

0 comments on commit cb421c9

Please sign in to comment.