Skip to content

Commit

Permalink
Merge pull request #43 from cloudstruct/feature/local-state-query-pro…
Browse files Browse the repository at this point in the history
…tocol

Implement local-state-query mini-protocol (part 1)
  • Loading branch information
agaffney authored Mar 17, 2022
2 parents 824ed3d + ae22772 commit 1670124
Show file tree
Hide file tree
Showing 4 changed files with 472 additions and 6 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ but the node-to-node protocols will also be implemented in time.
| Name | Status |
| --- | --- |
| Handshake | Implemented |
| Chain-Sync | Implemented |
| Block-Fetch | Implemented |
| TxSubmission | Not Implemented |
| Local TxSubmission | Implemented |
| Local State Query | Not Implemented |
| Keep-Alive | Implemented |
| ChainSync | Implemented |
| BlockFetch | Implemented |
| TxSubmission2 | Not Implemented |
| LocalTxSubmission | Implemented |
| LocalStateQuery | Partly Implemented |
| KeepAlive | Implemented |
| LocalTxMonitor | Not Implemented |

## Testing

Expand Down
6 changes: 6 additions & 0 deletions ouroboros.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/cloudstruct/go-ouroboros-network/protocol/chainsync"
"github.com/cloudstruct/go-ouroboros-network/protocol/handshake"
"github.com/cloudstruct/go-ouroboros-network/protocol/keepalive"
"github.com/cloudstruct/go-ouroboros-network/protocol/localstatequery"
"github.com/cloudstruct/go-ouroboros-network/protocol/localtxsubmission"
"net"
)
Expand All @@ -31,6 +32,8 @@ type Ouroboros struct {
keepAliveCallbackConfig *keepalive.KeepAliveCallbackConfig
LocalTxSubmission *localtxsubmission.LocalTxSubmission
localTxSubmissionCallbackConfig *localtxsubmission.CallbackConfig
LocalStateQuery *localstatequery.LocalStateQuery
localStateQueryCallbackConfig *localstatequery.CallbackConfig
}

type OuroborosOptions struct {
Expand All @@ -45,6 +48,7 @@ type OuroborosOptions struct {
BlockFetchCallbackConfig *blockfetch.BlockFetchCallbackConfig
KeepAliveCallbackConfig *keepalive.KeepAliveCallbackConfig
LocalTxSubmissionCallbackConfig *localtxsubmission.CallbackConfig
LocalStateQueryCallbackConfig *localstatequery.CallbackConfig
}

func New(options *OuroborosOptions) (*Ouroboros, error) {
Expand All @@ -57,6 +61,7 @@ func New(options *OuroborosOptions) (*Ouroboros, error) {
blockFetchCallbackConfig: options.BlockFetchCallbackConfig,
keepAliveCallbackConfig: options.KeepAliveCallbackConfig,
localTxSubmissionCallbackConfig: options.LocalTxSubmissionCallbackConfig,
localStateQueryCallbackConfig: options.LocalStateQueryCallbackConfig,
ErrorChan: options.ErrorChan,
sendKeepAlives: options.SendKeepAlives,
delayMuxerStart: options.DelayMuxerStart,
Expand Down Expand Up @@ -140,6 +145,7 @@ func (o *Ouroboros) setupConnection() error {
protoOptions.Mode = protocol.ProtocolModeNodeToClient
o.ChainSync = chainsync.New(protoOptions, o.chainSyncCallbackConfig)
o.LocalTxSubmission = localtxsubmission.New(protoOptions, o.localTxSubmissionCallbackConfig)
o.LocalStateQuery = localstatequery.New(protoOptions, o.localStateQueryCallbackConfig)
}
if !o.delayMuxerStart {
o.muxer.Start()
Expand Down
242 changes: 242 additions & 0 deletions protocol/localstatequery/localstatequery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package localstatequery

import (
"fmt"
"github.com/cloudstruct/go-ouroboros-network/protocol"
)

const (
PROTOCOL_NAME = "local-state-query"
PROTOCOL_ID uint16 = 7
)

var (
STATE_IDLE = protocol.NewState(1, "Idle")
STATE_ACQUIRING = protocol.NewState(2, "Acquiring")
STATE_ACQUIRED = protocol.NewState(3, "Acquired")
STATE_QUERYING = protocol.NewState(4, "Querying")
STATE_DONE = protocol.NewState(5, "Done")
)

var StateMap = protocol.StateMap{
STATE_IDLE: protocol.StateMapEntry{
Agency: protocol.AGENCY_SERVER,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_ACQUIRE,
NewState: STATE_ACQUIRING,
},
{
MsgType: MESSAGE_TYPE_ACQUIRE_NO_POINT,
NewState: STATE_ACQUIRING,
},
{
MsgType: MESSAGE_TYPE_DONE,
NewState: STATE_DONE,
},
},
},
STATE_ACQUIRING: protocol.StateMapEntry{
Agency: protocol.AGENCY_CLIENT,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_FAILURE,
NewState: STATE_IDLE,
},
{
MsgType: MESSAGE_TYPE_ACQUIRED,
NewState: STATE_ACQUIRED,
},
},
},
STATE_ACQUIRED: protocol.StateMapEntry{
Agency: protocol.AGENCY_SERVER,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_QUERY,
NewState: STATE_QUERYING,
},
{
MsgType: MESSAGE_TYPE_REACQUIRE,
NewState: STATE_ACQUIRING,
},
{
MsgType: MESSAGE_TYPE_REACQUIRE_NO_POINT,
NewState: STATE_ACQUIRING,
},
{
MsgType: MESSAGE_TYPE_RELEASE,
NewState: STATE_IDLE,
},
},
},
STATE_QUERYING: protocol.StateMapEntry{
Agency: protocol.AGENCY_CLIENT,
Transitions: []protocol.StateTransition{
{
MsgType: MESSAGE_TYPE_RESULT,
NewState: STATE_ACQUIRED,
},
},
},
STATE_DONE: protocol.StateMapEntry{
Agency: protocol.AGENCY_NONE,
},
}

type LocalStateQuery struct {
proto *protocol.Protocol
callbackConfig *CallbackConfig
}

type CallbackConfig struct {
AcquireFunc AcquireFunc
AcquiredFunc AcquiredFunc
FailureFunc FailureFunc
QueryFunc QueryFunc
ResultFunc ResultFunc
ReleaseFunc ReleaseFunc
ReAcquireFunc ReAcquireFunc
DoneFunc DoneFunc
}

// Callback function types
// TODO: update callbacks
type AcquireFunc func(interface{}) error
type AcquiredFunc func() error
type FailureFunc func(interface{}) error
type QueryFunc func(interface{}) error
type ResultFunc func(interface{}) error
type ReleaseFunc func() error
type ReAcquireFunc func(interface{}) error
type DoneFunc func() error

func New(options protocol.ProtocolOptions, callbackConfig *CallbackConfig) *LocalStateQuery {
l := &LocalStateQuery{
callbackConfig: callbackConfig,
}
protoConfig := protocol.ProtocolConfig{
Name: PROTOCOL_NAME,
ProtocolId: PROTOCOL_ID,
Muxer: options.Muxer,
ErrorChan: options.ErrorChan,
Mode: options.Mode,
Role: options.Role,
MessageHandlerFunc: l.messageHandler,
MessageFromCborFunc: NewMsgFromCbor,
StateMap: StateMap,
InitialState: STATE_IDLE,
}
l.proto = protocol.New(protoConfig)
return l
}

func (l *LocalStateQuery) messageHandler(msg protocol.Message, isResponse bool) error {
var err error
switch msg.Type() {
case MESSAGE_TYPE_ACQUIRE:
err = l.handleAcquire(msg)
case MESSAGE_TYPE_ACQUIRED:
err = l.handleAcquired()
case MESSAGE_TYPE_FAILURE:
err = l.handleFailure(msg)
case MESSAGE_TYPE_QUERY:
err = l.handleQuery(msg)
case MESSAGE_TYPE_RESULT:
err = l.handleResult(msg)
case MESSAGE_TYPE_RELEASE:
err = l.handleRelease()
case MESSAGE_TYPE_REACQUIRE:
err = l.handleReAcquire(msg)
case MESSAGE_TYPE_ACQUIRE_NO_POINT:
err = l.handleAcquire(msg)
case MESSAGE_TYPE_REACQUIRE_NO_POINT:
err = l.handleReAcquire(msg)
case MESSAGE_TYPE_DONE:
err = l.handleDone()
default:
err = fmt.Errorf("%s: received unexpected message type %d", PROTOCOL_NAME, msg.Type())
}
return err
}

func (l *LocalStateQuery) handleAcquire(msg protocol.Message) error {
if l.callbackConfig.AcquireFunc == nil {
return fmt.Errorf("received local-state-query Acquire message but no callback function is defined")
}
switch msgAcquire := msg.(type) {
case *MsgAcquire:
// Call the user callback function
return l.callbackConfig.AcquireFunc(msgAcquire.Point)
case *MsgAcquireNoPoint:
// Call the user callback function
return l.callbackConfig.AcquireFunc(nil)
}
return nil
}

func (l *LocalStateQuery) handleAcquired() error {
if l.callbackConfig.AcquiredFunc == nil {
return fmt.Errorf("received local-state-query Acquired message but no callback function is defined")
}
// Call the user callback function
return l.callbackConfig.AcquiredFunc()
}

func (l *LocalStateQuery) handleFailure(msg protocol.Message) error {
if l.callbackConfig.FailureFunc == nil {
return fmt.Errorf("received local-state-query Failure message but no callback function is defined")
}
msgFailure := msg.(*MsgFailure)
// Call the user callback function
return l.callbackConfig.FailureFunc(msgFailure.Failure)
}

func (l *LocalStateQuery) handleQuery(msg protocol.Message) error {
if l.callbackConfig.QueryFunc == nil {
return fmt.Errorf("received local-state-query Query message but no callback function is defined")
}
msgQuery := msg.(*MsgQuery)
// Call the user callback function
return l.callbackConfig.QueryFunc(msgQuery.Query)
}

func (l *LocalStateQuery) handleResult(msg protocol.Message) error {
if l.callbackConfig.ResultFunc == nil {
return fmt.Errorf("received local-state-query Result message but no callback function is defined")
}
msgResult := msg.(*MsgResult)
// Call the user callback function
return l.callbackConfig.ResultFunc(msgResult.Result)
}

func (l *LocalStateQuery) handleRelease() error {
if l.callbackConfig.ReleaseFunc == nil {
return fmt.Errorf("received local-state-query Release message but no callback function is defined")
}
// Call the user callback function
return l.callbackConfig.ReleaseFunc()
}

func (l *LocalStateQuery) handleReAcquire(msg protocol.Message) error {
if l.callbackConfig.ReAcquireFunc == nil {
return fmt.Errorf("received local-state-query ReAcquire message but no callback function is defined")
}
switch msgReAcquire := msg.(type) {
case *MsgReAcquire:
// Call the user callback function
return l.callbackConfig.ReAcquireFunc(msgReAcquire.Point)
case *MsgReAcquireNoPoint:
// Call the user callback function
return l.callbackConfig.ReAcquireFunc(nil)
}
return nil
}

func (l *LocalStateQuery) handleDone() error {
if l.callbackConfig.DoneFunc == nil {
return fmt.Errorf("received local-state-query Done message but no callback function is defined")
}
// Call the user callback function
return l.callbackConfig.DoneFunc()
}
Loading

0 comments on commit 1670124

Please sign in to comment.