From bf9e71b95c0e1f764dc57964dc5893963559171b Mon Sep 17 00:00:00 2001 From: Aurora Gaffney Date: Fri, 27 Dec 2024 13:39:38 -0600 Subject: [PATCH] feat: support for acquire immutable tip in local-state-query * rename (Re)AcquireNoPoint to (Re)AcquireVolatileTip * add new messages for ImmutableTip * add client functions for acquiring volatile/immutable tip * change Acquire callback signature for immutable trip Fixes #766 --- protocol/localstatequery/client.go | 80 +++++++++++++++------ protocol/localstatequery/client_test.go | 2 +- protocol/localstatequery/localstatequery.go | 35 +++++++-- protocol/localstatequery/messages.go | 76 ++++++++++++++------ protocol/localstatequery/messages_test.go | 8 +-- protocol/localstatequery/server.go | 36 ++++++---- 6 files changed, 172 insertions(+), 65 deletions(-) diff --git a/protocol/localstatequery/client.go b/protocol/localstatequery/client.go index 85be0a68..d657c477 100644 --- a/protocol/localstatequery/client.go +++ b/protocol/localstatequery/client.go @@ -114,20 +114,49 @@ func (c *Client) Start() { // Acquire starts the acquire process for the specified chain point func (c *Client) Acquire(point *common.Point) error { - var msg string - if point != nil { - msg = fmt.Sprintf( - "calling Acquire(point: {Slot: %d, Hash: %x})", - point.Slot, - point.Hash, + // Use volatile tip if no point provided + if point == nil { + return c.AcquireVolatileTip() + } + c.Protocol.Logger(). + Debug( + fmt.Sprintf( + "calling Acquire(point: {Slot: %d, Hash: %x})", + point.Slot, + point.Hash, + ), + "component", "network", + "protocol", ProtocolName, + "role", "client", + "connection_id", c.callbackContext.ConnectionId.String(), ) - } else { - msg = "calling Acquire(point: latest)" + c.busyMutex.Lock() + defer c.busyMutex.Unlock() + acquireTarget := AcquireSpecificPoint{ + Point: *point, } + return c.acquire(acquireTarget) +} + +func (c *Client) AcquireVolatileTip() error { + c.Protocol.Logger(). + Debug( + "calling AcquireVolatileTip", + "component", "network", + "protocol", ProtocolName, + "role", "client", + "connection_id", c.callbackContext.ConnectionId.String(), + ) + c.busyMutex.Lock() + defer c.busyMutex.Unlock() + acquireTarget := AcquireVolatileTip{} + return c.acquire(acquireTarget) +} +func (c *Client) AcquireImmutableTip() error { c.Protocol.Logger(). Debug( - msg, + "calling AcquireImmutableTip", "component", "network", "protocol", ProtocolName, "role", "client", @@ -135,7 +164,8 @@ func (c *Client) Acquire(point *common.Point) error { ) c.busyMutex.Lock() defer c.busyMutex.Unlock() - return c.acquire(point) + acquireTarget := AcquireImmutableTip{} + return c.acquire(acquireTarget) } // Release releases the previously acquired chain point @@ -906,19 +936,29 @@ func (c *Client) handleResult(msg protocol.Message) error { return nil } -func (c *Client) acquire(point *common.Point) error { +func (c *Client) acquire(acquireTarget AcquireTarget) error { var msg protocol.Message if c.acquired { - if point != nil { - msg = NewMsgReAcquire(*point) - } else { - msg = NewMsgReAcquireNoPoint() + switch t := acquireTarget.(type) { + case AcquireSpecificPoint: + msg = NewMsgReAcquire(t.Point) + case AcquireVolatileTip: + msg = NewMsgReAcquireVolatileTip() + case AcquireImmutableTip: + msg = NewMsgReAcquireImmutableTip() + default: + return fmt.Errorf("invalid acquire point provided") } } else { - if point != nil { - msg = NewMsgAcquire(*point) - } else { - msg = NewMsgAcquireNoPoint() + switch t := acquireTarget.(type) { + case AcquireSpecificPoint: + msg = NewMsgAcquire(t.Point) + case AcquireVolatileTip: + msg = NewMsgAcquireVolatileTip() + case AcquireImmutableTip: + msg = NewMsgAcquireImmutableTip() + default: + return fmt.Errorf("invalid acquire point provided") } } if err := c.SendMessage(msg); err != nil { @@ -944,7 +984,7 @@ func (c *Client) release() error { func (c *Client) runQuery(query interface{}, result interface{}) error { msg := NewMsgQuery(query) if !c.acquired { - if err := c.acquire(nil); err != nil { + if err := c.acquire(AcquireVolatileTip{}); err != nil { return err } } diff --git a/protocol/localstatequery/client_test.go b/protocol/localstatequery/client_test.go index 39e0249d..d4575eef 100644 --- a/protocol/localstatequery/client_test.go +++ b/protocol/localstatequery/client_test.go @@ -37,7 +37,7 @@ var conversationHandshakeAcquire = []ouroboros_mock.ConversationEntry{ ouroboros_mock.ConversationEntryHandshakeNtCResponse, ouroboros_mock.ConversationEntryInput{ ProtocolId: localstatequery.ProtocolId, - MessageType: localstatequery.MessageTypeAcquireNoPoint, + MessageType: localstatequery.MessageTypeAcquireVolatileTip, }, ouroboros_mock.ConversationEntryOutput{ ProtocolId: localstatequery.ProtocolId, diff --git a/protocol/localstatequery/localstatequery.go b/protocol/localstatequery/localstatequery.go index 3544c3d3..ad313deb 100644 --- a/protocol/localstatequery/localstatequery.go +++ b/protocol/localstatequery/localstatequery.go @@ -47,7 +47,11 @@ var StateMap = protocol.StateMap{ NewState: stateAcquiring, }, { - MsgType: MessageTypeAcquireNoPoint, + MsgType: MessageTypeAcquireVolatileTip, + NewState: stateAcquiring, + }, + { + MsgType: MessageTypeAcquireImmutableTip, NewState: stateAcquiring, }, { @@ -81,7 +85,11 @@ var StateMap = protocol.StateMap{ NewState: stateAcquiring, }, { - MsgType: MessageTypeReacquireNoPoint, + MsgType: MessageTypeReacquireVolatileTip, + NewState: stateAcquiring, + }, + { + MsgType: MessageTypeReacquireImmutableTip, NewState: stateAcquiring, }, { @@ -121,6 +129,25 @@ type Config struct { QueryTimeout time.Duration } +// Acquire target types +type AcquireTarget interface { + isAcquireTarget() +} + +type AcquireSpecificPoint struct { + Point common.Point +} + +func (AcquireSpecificPoint) isAcquireTarget() {} + +type AcquireVolatileTip struct{} + +func (AcquireVolatileTip) isAcquireTarget() {} + +type AcquireImmutableTip struct{} + +func (AcquireImmutableTip) isAcquireTarget() {} + // Callback context type CallbackContext struct { ConnectionId connection.ConnectionId @@ -129,10 +156,10 @@ type CallbackContext struct { } // Callback function types -type AcquireFunc func(CallbackContext, *common.Point) error +type AcquireFunc func(CallbackContext, AcquireTarget) error type QueryFunc func(CallbackContext, any) error type ReleaseFunc func(CallbackContext) error -type ReAcquireFunc func(CallbackContext, *common.Point) error +type ReAcquireFunc func(CallbackContext, AcquireTarget) error type DoneFunc func(CallbackContext) error // New returns a new LocalStateQuery object diff --git a/protocol/localstatequery/messages.go b/protocol/localstatequery/messages.go index 4d713159..ab0c1729 100644 --- a/protocol/localstatequery/messages.go +++ b/protocol/localstatequery/messages.go @@ -24,16 +24,18 @@ import ( // Message types const ( - MessageTypeAcquire = 0 - MessageTypeAcquired = 1 - MessageTypeFailure = 2 - MessageTypeQuery = 3 - MessageTypeResult = 4 - MessageTypeRelease = 5 - MessageTypeReacquire = 6 - MessageTypeDone = 7 - MessageTypeAcquireNoPoint = 8 - MessageTypeReacquireNoPoint = 9 + MessageTypeAcquire = 0 + MessageTypeAcquired = 1 + MessageTypeFailure = 2 + MessageTypeQuery = 3 + MessageTypeResult = 4 + MessageTypeRelease = 5 + MessageTypeReacquire = 6 + MessageTypeDone = 7 + MessageTypeAcquireVolatileTip = 8 + MessageTypeReacquireVolatileTip = 9 + MessageTypeAcquireImmutableTip = 10 + MessageTypeReacquireImmutableTip = 11 ) // Acquire failure reasons @@ -60,10 +62,14 @@ func NewMsgFromCbor(msgType uint, data []byte) (protocol.Message, error) { ret = &MsgRelease{} case MessageTypeReacquire: ret = &MsgReAcquire{} - case MessageTypeAcquireNoPoint: - ret = &MsgAcquireNoPoint{} - case MessageTypeReacquireNoPoint: - ret = &MsgReAcquireNoPoint{} + case MessageTypeAcquireVolatileTip: + ret = &MsgAcquireVolatileTip{} + case MessageTypeReacquireVolatileTip: + ret = &MsgReAcquireVolatileTip{} + case MessageTypeAcquireImmutableTip: + ret = &MsgAcquireImmutableTip{} + case MessageTypeReacquireImmutableTip: + ret = &MsgReAcquireImmutableTip{} case MessageTypeDone: ret = &MsgDone{} } @@ -92,14 +98,27 @@ func NewMsgAcquire(point common.Point) *MsgAcquire { return m } -type MsgAcquireNoPoint struct { +type MsgAcquireVolatileTip struct { protocol.MessageBase } -func NewMsgAcquireNoPoint() *MsgAcquireNoPoint { - m := &MsgAcquireNoPoint{ +func NewMsgAcquireVolatileTip() *MsgAcquireVolatileTip { + m := &MsgAcquireVolatileTip{ MessageBase: protocol.MessageBase{ - MessageType: MessageTypeAcquireNoPoint, + MessageType: MessageTypeAcquireVolatileTip, + }, + } + return m +} + +type MsgAcquireImmutableTip struct { + protocol.MessageBase +} + +func NewMsgAcquireImmutableTip() *MsgAcquireImmutableTip { + m := &MsgAcquireImmutableTip{ + MessageBase: protocol.MessageBase{ + MessageType: MessageTypeAcquireImmutableTip, }, } return m @@ -191,14 +210,27 @@ func NewMsgReAcquire(point common.Point) *MsgReAcquire { return m } -type MsgReAcquireNoPoint struct { +type MsgReAcquireVolatileTip struct { + protocol.MessageBase +} + +func NewMsgReAcquireVolatileTip() *MsgReAcquireVolatileTip { + m := &MsgReAcquireVolatileTip{ + MessageBase: protocol.MessageBase{ + MessageType: MessageTypeReacquireVolatileTip, + }, + } + return m +} + +type MsgReAcquireImmutableTip struct { protocol.MessageBase } -func NewMsgReAcquireNoPoint() *MsgReAcquireNoPoint { - m := &MsgReAcquireNoPoint{ +func NewMsgReAcquireImmutableTip() *MsgReAcquireImmutableTip { + m := &MsgReAcquireImmutableTip{ MessageBase: protocol.MessageBase{ - MessageType: MessageTypeReacquireNoPoint, + MessageType: MessageTypeReacquireImmutableTip, }, } return m diff --git a/protocol/localstatequery/messages_test.go b/protocol/localstatequery/messages_test.go index 6366b81e..16e797d0 100644 --- a/protocol/localstatequery/messages_test.go +++ b/protocol/localstatequery/messages_test.go @@ -83,13 +83,13 @@ var tests = []testDefinition{ }, { CborHex: "8108", - Message: NewMsgAcquireNoPoint(), - MessageType: MessageTypeAcquireNoPoint, + Message: NewMsgAcquireVolatileTip(), + MessageType: MessageTypeAcquireVolatileTip, }, { CborHex: "8109", - Message: NewMsgReAcquireNoPoint(), - MessageType: MessageTypeReacquireNoPoint, + Message: NewMsgReAcquireVolatileTip(), + MessageType: MessageTypeReacquireVolatileTip, }, } diff --git a/protocol/localstatequery/server.go b/protocol/localstatequery/server.go index 21a67c4f..7450baf0 100644 --- a/protocol/localstatequery/server.go +++ b/protocol/localstatequery/server.go @@ -75,9 +75,9 @@ func (s *Server) messageHandler(msg protocol.Message) error { err = s.handleRelease() case MessageTypeReacquire: err = s.handleReAcquire(msg) - case MessageTypeAcquireNoPoint: + case MessageTypeAcquireVolatileTip: err = s.handleAcquire(msg) - case MessageTypeReacquireNoPoint: + case MessageTypeReacquireVolatileTip: err = s.handleReAcquire(msg) case MessageTypeDone: err = s.handleDone() @@ -104,15 +104,19 @@ func (s *Server) handleAcquire(msg protocol.Message) error { "received local-state-query Acquire message but no callback function is defined", ) } + var acquireTarget AcquireTarget switch msgAcquire := msg.(type) { case *MsgAcquire: - // Call the user callback function - return s.config.AcquireFunc(s.callbackContext, &msgAcquire.Point) - case *MsgAcquireNoPoint: - // Call the user callback function - return s.config.AcquireFunc(s.callbackContext, nil) + acquireTarget = AcquireSpecificPoint{ + Point: msgAcquire.Point, + } + case *MsgAcquireVolatileTip: + acquireTarget = AcquireVolatileTip{} + case *MsgAcquireImmutableTip: + acquireTarget = AcquireImmutableTip{} } - return nil + // Call the user callback function + return s.config.AcquireFunc(s.callbackContext, acquireTarget) } func (s *Server) handleQuery(msg protocol.Message) error { @@ -163,15 +167,19 @@ func (s *Server) handleReAcquire(msg protocol.Message) error { "received local-state-query ReAcquire message but no callback function is defined", ) } + var acquireTarget AcquireTarget switch msgReAcquire := msg.(type) { case *MsgReAcquire: - // Call the user callback function - return s.config.ReAcquireFunc(s.callbackContext, &msgReAcquire.Point) - case *MsgReAcquireNoPoint: - // Call the user callback function - return s.config.ReAcquireFunc(s.callbackContext, nil) + acquireTarget = AcquireSpecificPoint{ + Point: msgReAcquire.Point, + } + case *MsgReAcquireVolatileTip: + acquireTarget = AcquireVolatileTip{} + case *MsgReAcquireImmutableTip: + acquireTarget = AcquireImmutableTip{} } - return nil + // Call the user callback function + return s.config.ReAcquireFunc(s.callbackContext, acquireTarget) } func (s *Server) handleDone() error {