Skip to content

Commit

Permalink
Merge pull request #1381 from input-output-hk/lc/ouroboros-versioned
Browse files Browse the repository at this point in the history
Ouroboros: Switch to versioned protocol
  • Loading branch information
locallycompact committed May 8, 2024
2 parents 45292ad + 79daa18 commit 7d66414
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 74 deletions.
17 changes: 10 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,23 @@ changes.

## [0.17.0] - UNRELEASED

- **BREAKING** `hydra-node` `/commit` enpoint now also accepts a _blueprint/draft_
transaction together with the `UTxO` which is spent in this transaction. `hydra-node` can
still be used like before if the provided `UTxO` is at public key address. In order to spend
from a script `UTxO`, and also unlock more involved use-cases, users need to provide additional
unsigned transaction that correctly specifies required data (like redeemers, validity ranges etc.)

- Add `GET /snapshot/utxo` API endpoint to query confirmed UTxO set on demand.
- Always responds with the last confirmed UTxO

- _DEPRECATED_ the `GetUTxO` client input and `GetUTxOResponse` server output. Use `GET /snapshot/utxo` instead.

- `hydra-node` logs will now report `NetworkEvents` to distinguish between `ConnectivityEvent`s and `ReceivedMessage`s on the network.

## [0.17.0] - UNRELEASED

- **BREAKING** `hydra-node` `/commit` enpoint now also accepts a _blueprint/draft_
transaction together with the `UTxO` which is spent in this transaction. `hydra-node` can
still be used like before if the provided `UTxO` is at public key address. In order to spend
from a script `UTxO`, and also unlock more involved use-cases, users need to provide additional
unsigned transaction that correctly specifies required data (like redeemers, validity ranges etc.)
- Hydra now uses a versioned protocol for handshaking. In the event of a node
attempting to connect using a different version of the networking protocol, a
`HandshakeFailure` event will be recorded in the logs and sent as a server
output on the API.

## [0.16.0] - 2024-04-03

Expand Down
1 change: 1 addition & 0 deletions hydra-node/hydra-node.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ library
Hydra.Network.Ouroboros.Client
Hydra.Network.Ouroboros.Server
Hydra.Network.Ouroboros.Type
Hydra.Network.Ouroboros.VersionedProtocol
Hydra.Network.Reliability
Hydra.Node
Hydra.Node.InputQueue
Expand Down
89 changes: 89 additions & 0 deletions hydra-node/json-schemas/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ channels:
- $ref: "api.yaml#/components/messages/Greetings"
- $ref: "api.yaml#/components/messages/PeerConnected"
- $ref: "api.yaml#/components/messages/PeerDisconnected"
- $ref: "api.yaml#/components/messages/PeerHandshakeFailure"
- $ref: "api.yaml#/components/messages/HeadIsInitializing"
- $ref: "api.yaml#/components/messages/Committed"
- $ref: "api.yaml#/components/messages/HeadIsOpen"
Expand Down Expand Up @@ -333,6 +334,13 @@ components:
payload:
$ref: "api.yaml#/components/schemas/PeerDisconnected"

PeerHandshakeFailure:
title: PeerHandshakeFailure
description: |
A peer has failed to negotiate a protocol.
payload:
$ref: "api.yaml#/components/schemas/PeerHandshakeFailure"

HeadIsInitializing:
title: HeadIsInitializing
description: |
Expand Down Expand Up @@ -494,6 +502,7 @@ components:
- $ref: "api.yaml#/components/schemas/Greetings"
- $ref: "api.yaml#/components/schemas/PeerConnected"
- $ref: "api.yaml#/components/schemas/PeerDisconnected"
- $ref: "api.yaml#/components/schemas/PeerHandshakeFailure"
- $ref: "api.yaml#/components/schemas/HeadIsInitializing"
- $ref: "api.yaml#/components/schemas/Committed"
- $ref: "api.yaml#/components/schemas/HeadIsOpen"
Expand Down Expand Up @@ -571,6 +580,34 @@ components:
timestamp:
$ref: "api.yaml#/components/schemas/UTCTime"

PeerHandshakeFailure:
type: object
required:
- tag
- remoteHost
- ourVersion
- theirVersions
- seq
- timestamp
properties:
tag:
type: string
enum: ["PeerHandshakeFailure"]
remoteHost:
type: object
$ref: "api.yaml#/components/schemas/IP"
ourVersion:
type: integer
minimum: 0
theirVersions:
type: array
items:
type: integer
seq:
$ref: "api.yaml#/components/schemas/SequenceNumber"
timestamp:
$ref: "api.yaml#/components/schemas/UTCTime"

HeadIsInitializing:
type: object
required:
Expand Down Expand Up @@ -1976,3 +2013,55 @@ components:

# NOTE: We don't want anyone to depend on this!
ChainState: {}

IP:
type: object
oneOf:
- title: IPv4
type: object
properties:
tag:
type: string
enum: ["IPv4"]
ipv4:
type: string
- title: IPv6
type: string
properties:
tag:
type: string
enum: ["IPv6"]
ipv6:
type: string

MkHydraVersionedProtocolNumber:
type: object
required:
- hydraVersionedProtocolNumber
properties:
hydraVersionedProtocolNumber:
type: integer
minimum: 0

KnownHydraVersions:
oneOf:
- title: NoKnownHydraVersions
required:
- tag
properties:
tag:
type: string
enum: ["NoKnownHydraVersions"]
- title: KnownHydraVersions
type: object
required:
- tag
- fromKnownHydraVersions
properties:
tag:
type: string
enum: ["KnownHydraVersions"]
fromKnownHydraVersions:
type: array
items:
$ref: "api.yaml#/components/schemas/MkHydraVersionedProtocolNumber"
44 changes: 22 additions & 22 deletions hydra-node/json-schemas/logs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,26 @@ definitions:
nodeId:
type: string

- title: HandshakeFailure
type: object
additionalProperties: false
required:
- tag
- remoteHost
- ourVersion
- theirVersions
properties:
tag:
type: string
enum: ["HandshakeFailure"]
remoteHost:
type: object
$ref: "api.yaml#/components/schemas/IP"
ourVersion:
$ref: "api.yaml#/components/schemas/MkHydraVersionedProtocolNumber"
theirVersions:
$ref: "api.yaml#/components/schemas/KnownHydraVersions"

- title: ReceivedMessage
type: object
additionalProperties: false
Expand Down Expand Up @@ -2110,26 +2130,6 @@ definitions:
items:
$ref: "api.yaml#/components/schemas/TxId"

IP:
type: object
oneOf:
- title: IPv4
type: object
properties:
tag:
type: string
enum: ["IPv4"]
ipv4:
type: string
- title: IPv6
type: string
properties:
tag:
type: string
enum: ["IPv6"]
ipv6:
type: string

RunOptions:
type: object
required:
Expand Down Expand Up @@ -2164,15 +2164,15 @@ definitions:
type: string
host:
type: object
$ref: "logs.yaml#/definitions/IP"
$ref: "api.yaml#/components/schemas/IP"
port:
type: integer
peers:
type: array
items:
$ref: "api.yaml#/components/schemas/Peer"
apiHost:
$ref: "logs.yaml#/definitions/IP"
$ref: "api.yaml#/components/schemas/IP"
apiPort:
type: integer
monitoringPort:
Expand Down
9 changes: 8 additions & 1 deletion hydra-node/src/Hydra/API/ServerOutput.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Hydra.Crypto (MultiSignature)
import Hydra.HeadId (HeadId)
import Hydra.HeadLogic.State (HeadState)
import Hydra.Ledger (IsTx, UTxOType, ValidationError)
import Hydra.Network (NodeId)
import Hydra.Network (Host, NodeId)
import Hydra.OnChainId (OnChainId)
import Hydra.Party (Party)
import Hydra.Prelude hiding (seq)
Expand Down Expand Up @@ -53,6 +53,11 @@ instance IsChainState tx => FromJSON (TimedServerOutput tx) where
data ServerOutput tx
= PeerConnected {peer :: NodeId}
| PeerDisconnected {peer :: NodeId}
| PeerHandshakeFailure
{ remoteHost :: Host
, ourVersion :: Int
, theirVersions :: [Int]
}
| HeadIsInitializing {headId :: HeadId, parties :: [Party]}
| Committed {headId :: HeadId, party :: Party, utxo :: UTxOType tx}
| HeadIsOpen {headId :: HeadId, utxo :: UTxOType tx}
Expand Down Expand Up @@ -129,6 +134,7 @@ instance
shrink = \case
PeerConnected p -> PeerConnected <$> shrink p
PeerDisconnected p -> PeerDisconnected <$> shrink p
PeerHandshakeFailure rh ov tv -> PeerHandshakeFailure <$> shrink rh <*> shrink ov <*> shrink tv
HeadIsInitializing headId xs -> HeadIsInitializing <$> shrink headId <*> shrink xs
Committed headId p u -> Committed <$> shrink headId <*> shrink p <*> shrink u
HeadIsOpen headId u -> HeadIsOpen <$> shrink headId <*> shrink u
Expand Down Expand Up @@ -178,6 +184,7 @@ prepareServerOutput ServerOutputConfig{utxoInSnapshot} response =
case output response of
PeerConnected{} -> encodedResponse
PeerDisconnected{} -> encodedResponse
PeerHandshakeFailure{} -> encodedResponse
HeadIsInitializing{} -> encodedResponse
Committed{} -> encodedResponse
HeadIsOpen{} -> encodedResponse
Expand Down
18 changes: 17 additions & 1 deletion hydra-node/src/Hydra/HeadLogic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import Hydra.Ledger (
applyTransactions,
txId,
)
import Hydra.Network.Message (Connectivity (..), Message (..), NetworkEvent (..))
import Hydra.Network.Message (Connectivity (..), HydraVersionedProtocolNumber (..), KnownHydraVersions (..), Message (..), NetworkEvent (..))
import Hydra.OnChainId (OnChainId)
import Hydra.Party (Party (vkey))
import Hydra.Snapshot (ConfirmedSnapshot (..), Snapshot (..), SnapshotNumber, getSnapshot)
Expand All @@ -102,6 +102,22 @@ onConnectionEvent = \case
causes [ClientEffect (ServerOutput.PeerConnected nodeId)]
Disconnected{nodeId} ->
causes [ClientEffect (ServerOutput.PeerDisconnected nodeId)]
HandshakeFailure{remoteHost, ourVersion, theirVersions} ->
causes
[ ClientEffect
( ServerOutput.PeerHandshakeFailure
{ remoteHost
, ourVersion = getVersion ourVersion
, theirVersions = getKnownVersions theirVersions
}
)
]
where
getVersion MkHydraVersionedProtocolNumber{hydraVersionedProtocolNumber} = hydraVersionedProtocolNumber

getKnownVersions = \case
NoKnownHydraVersions -> []
KnownHydraVersions{fromKnownHydraVersions} -> getVersion <$> fromKnownHydraVersions

-- * The Coordinated Head protocol

Expand Down
37 changes: 36 additions & 1 deletion hydra-node/src/Hydra/Network/Message.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Cardano.Binary (serialize')
import Cardano.Crypto.Util (SignableRepresentation, getSignableRepresentation)
import Hydra.Crypto (Signature)
import Hydra.Ledger (IsTx (TxIdType), UTxOType)
import Hydra.Network (NodeId)
import Hydra.Network (Host, NodeId)
import Hydra.Party (Party)
import Hydra.Snapshot (Snapshot, SnapshotNumber)

Expand All @@ -21,9 +21,44 @@ data NetworkEvent msg
instance Arbitrary msg => Arbitrary (NetworkEvent msg) where
arbitrary = genericArbitrary

type HydraVersionedProtocolNumber :: Type
newtype HydraVersionedProtocolNumber = MkHydraVersionedProtocolNumber {hydraVersionedProtocolNumber :: Int}
deriving stock (Eq, Show, Generic, Ord)
deriving anyclass (ToJSON, FromJSON)

instance Arbitrary HydraVersionedProtocolNumber where
arbitrary = genericArbitrary

type KnownHydraVersions :: Type
data KnownHydraVersions
= KnownHydraVersions {fromKnownHydraVersions :: [HydraVersionedProtocolNumber]}
| NoKnownHydraVersions
deriving stock (Eq, Show, Generic)
deriving anyclass (ToJSON, FromJSON)

instance Arbitrary KnownHydraVersions where
arbitrary = genericArbitrary

type HydraHandshakeRefused :: Type
data HydraHandshakeRefused = HydraHandshakeRefused
{ remoteHost :: Host
, ourVersion :: HydraVersionedProtocolNumber
, theirVersions :: KnownHydraVersions
}
deriving stock (Eq, Show, Generic)
deriving anyclass (ToJSON, FromJSON)

instance Arbitrary HydraHandshakeRefused where
arbitrary = genericArbitrary

data Connectivity
= Connected {nodeId :: NodeId}
| Disconnected {nodeId :: NodeId}
| HandshakeFailure
{ remoteHost :: Host
, ourVersion :: HydraVersionedProtocolNumber
, theirVersions :: KnownHydraVersions
}
deriving stock (Generic, Eq, Show)
deriving anyclass (ToJSON, FromJSON)

Expand Down

0 comments on commit 7d66414

Please sign in to comment.