Skip to content

Commit

Permalink
[ADP-3306] Improve witness count validation in submitTransaction. (#…
Browse files Browse the repository at this point in the history
…4594)

This PR follows on from #4590, and:
- Extracts out witness count validation into a common function
`validateWitnessCounts`.
- Replaces `fromIntegral` with `intCastMaybe` and `fromJustNote` with a
unique and identifiable error message.
- Changes the types of fields `{expected,detected}NumberOfKeyWits` to
`Natural`.
- Changes the name of `ErrSubmitTransactionPartiallySignedOrNoSignedTx`
to `ErrSubmitTransactionMissingWitnesses`.

## Issue

ADP-3306
  • Loading branch information
paweljakubas authored May 16, 2024
2 parents bfbb5b8 + 0bf79f7 commit 47f4ccc
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 16 deletions.
14 changes: 7 additions & 7 deletions lib/api/src/Cardano/Wallet/Api/Http/Server/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import Cardano.Wallet
, ErrStakePoolDelegation (..)
, ErrStartTimeLaterThanEndTime (..)
, ErrSubmitTransaction (..)
, ErrSubmitTransactionMissingWitnessCounts (..)
, ErrSubmitTx (..)
, ErrUpdatePassphrase (..)
, ErrWalletAlreadyExists (..)
Expand Down Expand Up @@ -646,20 +647,19 @@ instance IsServerError ErrSubmitTransaction where
, "wallet and cannot be sent. Submit a transaction that has "
, "either an input or a withdrawal belonging to the wallet."
]
ErrSubmitTransactionPartiallySignedOrNoSignedTx
expectedWitsNo foundWitsNo ->
ErrSubmitTransactionMissingWitnesses
ErrSubmitTransactionMissingWitnessCounts
{expectedNumberOfKeyWits, detectedNumberOfKeyWits} ->
flip (apiError err403) message $
MissingWitnessesInTransaction
ApiErrorMissingWitnessesInTransaction
{ expectedNumberOfKeyWits = fromIntegral expectedWitsNo
, detectedNumberOfKeyWits = fromIntegral foundWitsNo
}
{expectedNumberOfKeyWits, detectedNumberOfKeyWits}
where
message = mconcat
[ "The transaction expects "
, toText expectedWitsNo
, toText expectedNumberOfKeyWits
, " witness(es) to be fully-signed but "
, toText foundWitsNo
, toText detectedNumberOfKeyWits
, " was provided."
, " Please submit a fully-signed transaction."
]
Expand Down
35 changes: 27 additions & 8 deletions lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ import Cardano.Wallet
, ErrReadRewardAccount (..)
, ErrSignPayment (..)
, ErrSubmitTransaction (..)
, ErrSubmitTransactionMissingWitnessCounts (..)
, ErrUpdatePassphrase (..)
, ErrWalletAlreadyExists (..)
, ErrWalletNotResponding (..)
Expand Down Expand Up @@ -763,6 +764,9 @@ import Data.Generics.Labels
import Data.Generics.Product
( typed
)
import Data.IntCast
( intCastMaybe
)
import Data.List
( isInfixOf
, sortOn
Expand Down Expand Up @@ -855,6 +859,9 @@ import Network.Wai.Middleware.ServerError
import Numeric.Natural
( Natural
)
import Safe
( fromJustNote
)
import Servant
( Application
, NoContent (..)
Expand Down Expand Up @@ -3701,6 +3708,24 @@ toOut ((TxOut addr (TokenBundle c tmap)), (Just path)) =
, derivationPath = NE.map ApiT path
}

validateWitnessCounts
:: Monad m
=> Int
-- ^ expected number of key witnesses
-> Int
-- ^ detected number of key witnesses
-> ExceptT ErrSubmitTransaction m ()
validateWitnessCounts expected detected =
when (expected > detected) $ throwE $
ErrSubmitTransactionMissingWitnesses $
ErrSubmitTransactionMissingWitnessCounts
{ expectedNumberOfKeyWits = toNatural expected
, detectedNumberOfKeyWits = toNatural detected
}
where
toNatural :: Int -> Natural
toNatural = fromJustNote "validateWitnessCounts.toNatural" . intCastMaybe

submitTransaction
:: forall ctx s k n
. ( ctx ~ ApiLayer s
Expand Down Expand Up @@ -3747,10 +3772,7 @@ submitTransaction ctx apiw@(ApiT wid) apitx = do
when (countJoinsQuits (apiDecoded ^. #certificates) > 1) $
liftHandler $ throwE ErrSubmitTransactionMultidelegationNotSupported

when (witsRequiredForInputs > totalNumberOfWits)
$ liftHandler . throwE
$ ErrSubmitTransactionPartiallySignedOrNoSignedTx
witsRequiredForInputs totalNumberOfWits
liftHandler $ validateWitnessCounts witsRequiredForInputs totalNumberOfWits

void $ withWorkerCtx ctx wid liftE liftE $ \wrk -> do
let tx = walletTx $ decodeTx tl era sealedTx
Expand Down Expand Up @@ -3897,10 +3919,7 @@ submitSharedTransaction ctx apiw@(ApiT wid) apitx = do
fromIntegral pWitsPerInput * witsRequiredForInputs
let allWitsRequired =
paymentWitsRequired + fromIntegral delegationWitsRequired
when (allWitsRequired > totalNumberOfWits) $
liftHandler $ throwE $
ErrSubmitTransactionPartiallySignedOrNoSignedTx
allWitsRequired totalNumberOfWits
liftHandler $ validateWitnessCounts allWitsRequired totalNumberOfWits

let txCtx = defaultTransactionCtx
{ txValidityInterval = (Nothing, ttl)
Expand Down
11 changes: 10 additions & 1 deletion lib/wallet/src/Cardano/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ module Cardano.Wallet
, ErrCannotQuit (..)
, ErrCannotVote (..)
, ErrSubmitTransaction (..)
, ErrSubmitTransactionMissingWitnessCounts (..)

-- ** Migration
, createMigrationPlan
Expand Down Expand Up @@ -3651,10 +3652,18 @@ data ErrSignPayment
-- | Errors that can occur when submitting a transaction.
data ErrSubmitTransaction
= ErrSubmitTransactionForeignWallet
| ErrSubmitTransactionPartiallySignedOrNoSignedTx Int Int
| ErrSubmitTransactionMissingWitnesses
!ErrSubmitTransactionMissingWitnessCounts
| ErrSubmitTransactionMultidelegationNotSupported
deriving (Show, Eq)

data ErrSubmitTransactionMissingWitnessCounts =
ErrSubmitTransactionMissingWitnessCounts
{ expectedNumberOfKeyWits :: !Natural
, detectedNumberOfKeyWits :: !Natural
}
deriving (Show, Eq)

-- | Errors that can occur when constructing an unsigned transaction.
data ErrConstructTx
= ErrConstructTxWrongPayload
Expand Down

0 comments on commit 47f4ccc

Please sign in to comment.