Skip to content

Commit

Permalink
Implement waiting for all parties to ack snapshot before confirming it
Browse files Browse the repository at this point in the history
  • Loading branch information
KtorZ committed Jun 16, 2021
1 parent bf33662 commit abe3316
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 19 deletions.
59 changes: 45 additions & 14 deletions hydra-node/src/Hydra/HeadLogic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ data HydraMessage tx
| AckTx Party tx
| ConfTx
| ReqSn SnapshotNumber [tx]
| AckSn Party (Snapshot tx) -- TODO: should actually be stored locally and not transmitted
| AckSn Party SnapshotNumber
| ConfSn
| Ping Party
deriving (Eq, Show)
Expand Down Expand Up @@ -127,6 +127,7 @@ data SimpleHeadState tx = SimpleHeadState
unconfirmedTxs :: Map tx (Set Party)
, confirmedTxs :: [tx]
, confirmedSnapshot :: Snapshot tx
, unconfirmedSnapshot :: Maybe (Snapshot tx, Set Party)
}

deriving instance Tx tx => Eq (SimpleHeadState tx)
Expand Down Expand Up @@ -217,7 +218,7 @@ update Environment{party, snapshotStrategy} ledger (HeadState p st) ev = case (s
let u0 = utxo
in newState
p
(OpenState $ SimpleHeadState u0 mempty mempty (Snapshot 0 u0 mempty))
(OpenState $ SimpleHeadState u0 mempty mempty (Snapshot 0 u0 mempty) Nothing)
[ClientEffect $ HeadIsOpen u0]
--
(OpenState SimpleHeadState{confirmedSnapshot, confirmedTxs}, ClientEvent Close) ->
Expand Down Expand Up @@ -271,21 +272,51 @@ update Environment{party, snapshotStrategy} ledger (HeadState p st) ev = case (s
)
[]
(OpenState s@SimpleHeadState{confirmedSnapshot}, NetworkEvent (ReqSn sn txs)) ->
-- TODO: Verify the request is signed by (?) / comes from the leader
-- (Can we prove a message comes from a given peer, without signature?)
case applyTransactions ledger (utxo confirmedSnapshot) txs of
Left e ->
--TODO: Wait for transaction to be applicable.
panic $ "Received not applicable snapshot (" <> show sn <> ") " <> show txs <> ": " <> show e
Right u ->
let nextSnapshot = Snapshot sn u txs
in newState p (OpenState s) [NetworkEffect $ AckSn party nextSnapshot]
(OpenState headState@SimpleHeadState{confirmedTxs, confirmedSnapshot}, NetworkEvent (AckSn _otherParty sn))
| number confirmedSnapshot + 1 == number sn ->
-- TODO: wait for all AckSn before confirming!
newState
p
(OpenState $ headState{confirmedTxs = confirmedTxs \\ confirmed sn, confirmedSnapshot = sn})
[ClientEffect $ SnapshotConfirmed $ number sn]
| otherwise ->
newState p st []
Right u
| number confirmedSnapshot + 1 == sn ->
let nextSnapshot = Snapshot sn u txs
in newState
p
(OpenState $ s{unconfirmedSnapshot = Just (nextSnapshot, mempty)})
[NetworkEffect $ AckSn party sn]
Right _ ->
panic $ "Received invalid snapshot request from leader. Confirmed snapshot: " <> show (number confirmedSnapshot) <> ", Requested snapshot: " <> show sn
(OpenState headState@SimpleHeadState{confirmedTxs, unconfirmedSnapshot}, NetworkEvent (AckSn otherParty sn)) ->
-- TODO: Verify snapshot signatures.
case unconfirmedSnapshot of
Nothing -> panic "TODO: wait until reqSn is seen (and unconfirmedSnapshot created)"
Just (snapshot, sigs)
| number snapshot == sn ->
let sigs' = otherParty `Set.insert` sigs
in if sigs' == parties p
then
newState
p
( OpenState $
headState
{ confirmedTxs = confirmedTxs \\ confirmed snapshot
, confirmedSnapshot = snapshot
, unconfirmedSnapshot = Nothing
}
)
[ClientEffect $ SnapshotConfirmed sn]
else
newState
p
( OpenState $
headState
{ unconfirmedSnapshot = Just (snapshot, sigs')
}
)
[]
Just (snapshot, _) ->
panic $ "Received ack for unknown unconfirmed snapshot. Unconfirmed snapshot: " <> show (number snapshot) <> ", Requested snapshot: " <> show sn
(_, OnChainEvent (CloseTx snapshot txs)) ->
-- TODO(1): Should check whether we want / can contest the close snapshot by
-- comparing with our local state / utxo.
Expand Down
8 changes: 4 additions & 4 deletions hydra-node/test/Hydra/HeadLogicSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ spec = describe "Hydra Head Logic" $ do

it "confirms tx given it receives AckTx from all parties" $ do
let reqTx = NetworkEvent $ ReqTx (ValidTx 1)
ackFrom n = NetworkEvent $ AckTx n (ValidTx 1)
ackFrom p = NetworkEvent $ AckTx p (ValidTx 1)
s0 = initialState threeParties ledger

s1 <- assertNewState $ update env ledger s0 reqTx
Expand All @@ -68,7 +68,7 @@ spec = describe "Hydra Head Logic" $ do
it "confirms snapshot given it receives AckSn from all parties" $ do
let s0 = initialState threeParties ledger
reqSn = NetworkEvent $ ReqSn 1 []
ackFrom n = NetworkEvent $ AckSn n (Snapshot 1 [] [])
ackFrom p = NetworkEvent $ AckSn p 1
s1 <- assertNewState $ update env ledger s0 reqSn
s2 <- assertNewState $ update env ledger s1 (ackFrom 3)
s3 <- assertNewState $ update env ledger s2 (ackFrom 1)
Expand Down Expand Up @@ -100,7 +100,7 @@ genHeadStatus =
[ InitState
, FinalState
, CollectingState mempty mempty
, OpenState (SimpleHeadState [] mempty mempty (Snapshot 0 mempty mempty))
, OpenState (SimpleHeadState [] mempty mempty (Snapshot 0 mempty mempty) Nothing)
]

defaultHeadParameters :: HeadParameters
Expand Down Expand Up @@ -135,7 +135,7 @@ initialState parties Ledger{initUTxO} =
let u0 = initUTxO
snapshot0 = Snapshot 0 u0 mempty
in HeadState
{ headStatus = OpenState $ SimpleHeadState u0 mempty mempty snapshot0
{ headStatus = OpenState $ SimpleHeadState u0 mempty mempty snapshot0 Nothing
, headParameters =
HeadParameters
{ contestationPeriod = 42
Expand Down
2 changes: 1 addition & 1 deletion hydra-node/test/Hydra/NetworkSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ instance Arbitrary (HydraMessage MockTx) where
, AckTx <$> arbitraryNatural <*> arbitrary
, pure ConfTx
, ReqSn <$> arbitraryNatural <*> arbitrary
, AckSn <$> arbitraryNatural <*> arbitrary
, AckSn <$> arbitraryNatural <*> arbitraryNatural
, pure ConfSn
, Ping <$> arbitraryNatural
]
Expand Down

0 comments on commit abe3316

Please sign in to comment.