Skip to content

Commit

Permalink
Try to spend committed input and add an error
Browse files Browse the repository at this point in the history
If the wallet does not know about the provided input, it's not possible
to spend it -> throw a synchronous exception.
  • Loading branch information
ch1bo committed Nov 22, 2021
1 parent 24ec3e0 commit 10d58bd
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 9 deletions.
10 changes: 7 additions & 3 deletions hydra-node/src/Hydra/Chain.hs
Expand Up @@ -8,7 +8,7 @@ import Cardano.Prelude
import Control.Monad.Class.MonadThrow (MonadThrow)
import Data.Aeson (FromJSON, ToJSON)
import Data.Time (DiffTime, UTCTime)
import Hydra.Ledger (Tx, Utxo)
import Hydra.Ledger (Tx, TxIn, Utxo)
import Hydra.Party (Party)
import Hydra.Prelude (Arbitrary (arbitrary), genericArbitrary)
import Hydra.Snapshot (Snapshot, SnapshotNumber)
Expand Down Expand Up @@ -74,9 +74,13 @@ instance (Arbitrary tx, Arbitrary (Utxo tx)) => Arbitrary (OnChainTx tx) where
-- component. The transaction may be deemed invalid because it does not
-- satisfies pre-conditions fixed by our application (e.g. more than one UTXO is
-- committed).
data InvalidTxError
data InvalidTxError tx
= MoreThanOneUtxoCommitted
deriving (Eq, Exception, Show)
| CannotSpendInput {input :: TxIn tx}
deriving (Exception)

deriving instance Tx tx => Eq (InvalidTxError tx)
deriving instance Tx tx => Show (InvalidTxError tx)

-- | Handle to interface with the main chain network
newtype Chain tx m = Chain
Expand Down
9 changes: 6 additions & 3 deletions hydra-node/src/Hydra/Chain/Direct.hs
Expand Up @@ -17,10 +17,11 @@ import Hydra.Prelude

import Cardano.Ledger.Alonzo.Tx (ValidatedTx)
import Cardano.Ledger.Alonzo.TxSeq (txSeqTxns)
import Cardano.Ledger.Shelley.API (TxIn (TxIn))
import qualified Cardano.Ledger.Shelley.API as Ledger
import Control.Exception (IOException)
import Control.Monad (foldM)
import Control.Monad.Class.MonadSTM (MonadSTMTx (writeTVar), newTQueueIO, newTVarIO, readTQueue, writeTQueue)
import Control.Monad.Class.MonadSTM (MonadSTMTx (writeTVar), newTQueueIO, newTVarIO, readTQueue, throwSTM, writeTQueue)
import Control.Tracer (nullTracer)
import Data.Aeson (Value (String), object, (.=))
import qualified Data.Map as Map
Expand Down Expand Up @@ -59,7 +60,7 @@ import Hydra.Chain.Direct.Util (
versions,
)
import qualified Hydra.Chain.Direct.Util as Cardano
import Hydra.Chain.Direct.Wallet (TinyWallet (..), TinyWalletLog, withTinyWallet)
import Hydra.Chain.Direct.Wallet (ErrCoverFee (ErrUnknownInput, input), TinyWallet (..), TinyWalletLog, withTinyWallet)
import Hydra.Ledger.Cardano (CardanoTx)
import Hydra.Logging (Tracer, traceWith)
import Hydra.Party (Party)
Expand Down Expand Up @@ -332,14 +333,16 @@ txSubmissionClient tracer queue =
)

finalizeTx ::
MonadSTM m =>
(MonadSTM m, MonadThrow (STM m)) =>
TinyWallet m ->
TVar m OnChainHeadState ->
ValidatedTx Era ->
STM m (ValidatedTx Era)
finalizeTx TinyWallet{sign, coverFee} headState partialTx = do
utxo <- knownUtxo <$> readTVar headState
coverFee utxo partialTx >>= \case
Left ErrUnknownInput{input = TxIn txId txIx} ->
throwSTM $ CannotSpendInput @CardanoTx (txId, txIx)
Left e ->
error ("failed to cover fee for transaction: " <> show e <> ", " <> show partialTx)
Right validatedTx -> do
Expand Down
4 changes: 3 additions & 1 deletion hydra-node/src/Hydra/Chain/Direct/Tx.hs
Expand Up @@ -189,7 +189,9 @@ commitTx party utxo (initialIn, pkh) =
where
body =
TxBody
{ inputs = Set.singleton initialIn
{ inputs =
Set.singleton initialIn
<> maybe mempty (Set.singleton . fst) utxo
, collateral = mempty
, outputs =
StrictSeq.fromList
Expand Down
2 changes: 2 additions & 0 deletions hydra-node/src/Hydra/Ledger.hs
Expand Up @@ -35,6 +35,8 @@ class

balance :: Utxo tx -> Balance tx

type TxIn tx = (TxId tx, Natural)

data Balance tx = Balance
{ lovelace :: Natural
, assets :: Map (AssetId tx) Integer
Expand Down
5 changes: 3 additions & 2 deletions local-cluster/test/Test/DirectChainSpec.hs
Expand Up @@ -95,8 +95,9 @@ spec = around showLogsOnFailure $ do
postTx (CommitTx alice (someUtxoA <> someUtxoB))
`shouldThrow` (== MoreThanOneUtxoCommitted)

postTx $ CommitTx alice someUtxoA
alicesCallback `observesInTime` PostTxFailed
postTx (CommitTx alice someUtxoA)
`shouldThrow` (== CannotSpendUtxo someUtxoA)

-- TODO: we need to do some magic to observe the correct Utxo being
-- committed. This is not trivial because we need to generate a tx
-- in the chain that can then be committed, by Alice. And it needs
Expand Down

0 comments on commit 10d58bd

Please sign in to comment.