diff --git a/.changes/20261023_sub_transaction_witness_assemble.yml b/.changes/20261023_sub_transaction_witness_assemble.yml new file mode 100644 index 0000000000..ca136bc091 --- /dev/null +++ b/.changes/20261023_sub_transaction_witness_assemble.yml @@ -0,0 +1,5 @@ +project: cardano-cli +pr: 1485 +kind: + - feature +description: Add Dijkstra sub-transaction witness and assemble commands to create key witnesses separately and combine them with an unsigned sub-transaction. diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Command.hs b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Command.hs index c8cc7721d4..fe6f5c037f 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Command.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Command.hs @@ -6,6 +6,8 @@ module Cardano.CLI.EraBased.Transaction.SubTransaction.Command ( SubTransactionCmds (..) , SubTransactionBuildRawCmdArgs (..) , SubTransactionSignCmdArgs (..) + , SubTransactionWitnessCmdArgs (..) + , SubTransactionAssembleCmdArgs (..) , SubTransactionTxIdCmdArgs (..) , Guard (..) , GuardScript (..) @@ -30,6 +32,8 @@ import Vary (Vary) data SubTransactionCmds = SubTransactionBuildRawCmd !SubTransactionBuildRawCmdArgs | SubTransactionSignCmd !SubTransactionSignCmdArgs + | SubTransactionWitnessCmd !SubTransactionWitnessCmdArgs + | SubTransactionAssembleCmd !SubTransactionAssembleCmdArgs | SubTransactionTxIdCmd !SubTransactionTxIdCmdArgs -- | Like 'TransactionBuildRawCmdArgs' for a sub-transaction body. A @@ -95,6 +99,20 @@ data SubTransactionSignCmdArgs = SubTransactionSignCmdArgs } deriving Show +data SubTransactionWitnessCmdArgs = SubTransactionWitnessCmdArgs + { subTxFile :: !(UnsignedSubTxFile In) + , witnessSigningData :: !WitnessSigningData + , outFile :: !(File () Out) + } + deriving Show + +data SubTransactionAssembleCmdArgs = SubTransactionAssembleCmdArgs + { subTxFile :: !(UnsignedSubTxFile In) + , witnessFiles :: ![WitnessFile] + , outFile :: !(SignedSubTxFile Out) + } + deriving Show + data SubTransactionTxIdCmdArgs = SubTransactionTxIdCmdArgs { inputSubTxFile :: !InputSubTxFile , outputFormat :: !(Vary [FormatJson, FormatText, FormatYaml]) @@ -105,4 +123,6 @@ renderSubTransactionCmds :: SubTransactionCmds -> Text renderSubTransactionCmds = \case SubTransactionBuildRawCmd{} -> "sub-transaction build-raw" SubTransactionSignCmd{} -> "sub-transaction sign" + SubTransactionWitnessCmd{} -> "sub-transaction witness" + SubTransactionAssembleCmd{} -> "sub-transaction assemble" SubTransactionTxIdCmd{} -> "sub-transaction txid" diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Option.hs b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Option.hs index 349aecff64..35b9f6ff10 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Option.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Option.hs @@ -73,6 +73,16 @@ pSubTransactionCmds = commandWithMetavar "sign" $ Opt.info pSubTransactionSign $ Opt.progDesc "Sign a sub-transaction" + , Just $ + Opt.hsubparser $ + commandWithMetavar "witness" $ + Opt.info pSubTransactionWitness $ + Opt.progDesc "Create a sub-transaction key witness" + , Just $ + Opt.hsubparser $ + commandWithMetavar "assemble" $ + Opt.info pSubTransactionAssemble $ + Opt.progDesc "Assemble an unsigned sub-transaction and key witnesses into a signed sub-transaction" , Just $ Opt.hsubparser $ commandWithMetavar "txid" $ @@ -144,6 +154,22 @@ pSubTransactionSign = <*> many pSubTransactionSigningData <*> pSignedSubTxFileOut +pSubTransactionWitness :: Parser SubTransactionCmds +pSubTransactionWitness = + fmap SubTransactionWitnessCmd $ + SubTransactionWitnessCmdArgs + <$> pUnsignedSubTxFileIn + <*> pSubTransactionSigningData + <*> pOutputFile + +pSubTransactionAssemble :: Parser SubTransactionCmds +pSubTransactionAssemble = + fmap SubTransactionAssembleCmd $ + SubTransactionAssembleCmdArgs + <$> pUnsignedSubTxFileIn + <*> many pWitnessFile + <*> pSignedSubTxFileOut + pSubTransactionTxId :: Parser SubTransactionCmds pSubTransactionTxId = fmap SubTransactionTxIdCmd $ diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Run.hs b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Run.hs index b28af3cf30..e665942bfa 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Run.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Transaction/SubTransaction/Run.hs @@ -15,6 +15,8 @@ module Cardano.CLI.EraBased.Transaction.SubTransaction.Run ( runSubTransactionCmds , runSubTransactionBuildRawCmd , runSubTransactionSignCmd + , runSubTransactionWitnessCmd + , runSubTransactionAssembleCmd , runSubTransactionTxIdCmd , readSignedSubTransactions , validateCanonicalSubTransactions @@ -69,6 +71,8 @@ runSubTransactionCmds :: Cmd.SubTransactionCmds -> CIO e () runSubTransactionCmds = \case Cmd.SubTransactionBuildRawCmd args -> runSubTransactionBuildRawCmd args Cmd.SubTransactionSignCmd args -> runSubTransactionSignCmd args + Cmd.SubTransactionWitnessCmd args -> runSubTransactionWitnessCmd args + Cmd.SubTransactionAssembleCmd args -> runSubTransactionAssembleCmd args Cmd.SubTransactionTxIdCmd args -> runSubTransactionTxIdCmd args -- | Read the signed sub-transactions named on the command line, checking that @@ -479,6 +483,56 @@ runSubTransactionSignCmd fromEitherIOCli $ writeFileTextEnvelope outFile Nothing signed +runSubTransactionWitnessCmd + :: Cmd.SubTransactionWitnessCmdArgs + -> CIO e () +runSubTransactionWitnessCmd + Cmd.SubTransactionWitnessCmdArgs + { subTxFile = File subTxFilePath + , witnessSigningData + , outFile + } = do + subTxFile <- liftIO $ fileOrPipe subTxFilePath + unsigned <- + fromEitherIOCli $ first TxCmdTextEnvError <$> readFileUnsignedSubTx subTxFile + signingWitness <- + fromEitherIOCli $ + first TxCmdReadWitnessSigningDataError <$> readWitnessSigningData witnessSigningData + key <- case categoriseSomeSigningWitness signingWitness of + AByronWitness _ -> throwCliError TxCmdSubTxByronWitnessUnsupported + AShelleyKeyWitness key -> pure key + let witness = ShelleyKeyWitness ShelleyBasedEraDijkstra $ Exp.makeSubTxKeyWitness unsigned key + fromEitherIOCli $ + first TxCmdWriteFileError <$> writeTxWitnessFileTextEnvelope ShelleyBasedEraDijkstra outFile witness + +runSubTransactionAssembleCmd + :: Cmd.SubTransactionAssembleCmdArgs + -> CIO e () +runSubTransactionAssembleCmd + Cmd.SubTransactionAssembleCmdArgs + { subTxFile = File subTxFilePath + , witnessFiles + , outFile + } = do + subTxFile <- liftIO $ fileOrPipe subTxFilePath + unsigned <- + fromEitherIOCli $ first TxCmdTextEnvError <$> readFileUnsignedSubTx subTxFile + keyWits <- forM witnessFiles $ \witnessFile@(WitnessFile path) -> do + InAnyShelleyBasedEra era witness <- + fromEitherIOCli $ first TxCmdTextEnvError <$> readFileTxKeyWitness path + case era of + ShelleyBasedEraDijkstra -> case witness of + ShelleyKeyWitness _ keyWit -> pure keyWit + ShelleyBootstrapWitness{} -> throwCliError TxCmdSubTxByronWitnessUnsupported + _ -> + throwCliError $ + TxCmdWitnessEraMismatch + (AnyCardanoEra DijkstraEra) + (AnyCardanoEra $ toCardanoEra era) + witnessFile + -- Preserve the body bytes covered by the signatures, as in 'sign'. + fromEitherIOCli $ writeFileTextEnvelope outFile Nothing $ Exp.signSubTx [] keyWits unsigned + runSubTransactionTxIdCmd :: Cmd.SubTransactionTxIdCmdArgs -> CIO e () diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/SubTransaction.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/SubTransaction.hs index 4481913fc2..70fb37725d 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/SubTransaction.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Dijkstra/Transaction/SubTransaction.hs @@ -60,6 +60,35 @@ hprop_golden_dijkstra_transaction_sub_transaction_pipeline = ] H.diffFileVsGoldenFile signedSubTxFile (goldenDir <> "/signed_out") + -- Creating a detached witness and assembling must reproduce direct signing. + witnessFile <- noteTempFile tempDir "sub-tx.witness" + void $ + execCardanoCLI + [ "dijkstra" + , "sub-transaction" + , "witness" + , "--sub-tx-file" + , unsignedSubTxFile + , "--signing-key-file" + , signingKeyFile + , "--out-file" + , witnessFile + ] + H.diffFileVsGoldenFile witnessFile (goldenDir <> "/witness_out") + void $ + execCardanoCLI + [ "dijkstra" + , "sub-transaction" + , "assemble" + , "--sub-tx-file" + , unsignedSubTxFile + , "--witness-file" + , witnessFile + , "--out-file" + , signedSubTxFile + ] + H.diffFileVsGoldenFile signedSubTxFile (goldenDir <> "/signed_out") + -- The id is the body hash, so signing must not change it unsignedId <- execCardanoCLI diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/sub-transaction/witness_out b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/sub-transaction/witness_out new file mode 100644 index 0000000000..b3729ad395 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/dijkstra/transaction/sub-transaction/witness_out @@ -0,0 +1,5 @@ +{ + "type": "TxWitness DijkstraEra", + "description": "Key Witness ShelleyEra", + "cborHex": "82582048d968a47923d491cbba6548e61cc3e347e658d1818d7bea90cf7d04ca13dbd15840449d80212dc4f45426f668daefe5dc22f60ff15c74b7262ccaebd8fad59504e05e19b03616a3305dcb4d0e384385b8bf7da7d059bfa112ad899223c7d1c6d400" +} diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli index 429eafe95d..b1f68c7e9c 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli @@ -5261,7 +5261,14 @@ Usage: cardano-cli dijkstra stake-pool metadata-hash Calculate the hash of a stake pool metadata file, optionally checking the obtained hash against an expected value. -Usage: cardano-cli dijkstra sub-transaction (build-raw | sign | txid) +Usage: cardano-cli dijkstra sub-transaction + ( build-raw + | sign + | witness + | assemble + | txid + ) + Sub-transaction commands. A sub-transaction is built and signed on its own, then embedded in a top-level transaction. @@ -5444,6 +5451,21 @@ Usage: cardano-cli dijkstra sub-transaction sign --sub-tx-file FILEPATH Sign a sub-transaction +Usage: cardano-cli dijkstra sub-transaction witness --sub-tx-file FILEPATH + --signing-key-file FILEPATH + --out-file FILEPATH + + + Create a sub-transaction key witness + +Usage: cardano-cli dijkstra sub-transaction assemble --sub-tx-file FILEPATH + [--witness-file FILEPATH] + --out-file FILEPATH + + + Assemble an unsigned sub-transaction and key witnesses into a signed + sub-transaction + Usage: cardano-cli dijkstra sub-transaction txid ( --sub-tx-file FILEPATH | --signed-sub-tx-file FILEPATH diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction.cli index 2576cebec8..44fce59213 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction.cli @@ -1,4 +1,11 @@ -Usage: cardano-cli dijkstra sub-transaction (build-raw | sign | txid) +Usage: cardano-cli dijkstra sub-transaction + ( build-raw + | sign + | witness + | assemble + | txid + ) + Sub-transaction commands. A sub-transaction is built and signed on its own, then embedded in a top-level transaction. @@ -12,4 +19,7 @@ Available commands: Please note the order[93;22;23;24m of some cmd options is crucial. If used incorrectly may produce undesired sub-transaction body. See nested [] notation above for details.[0;22;23;24m sign Sign a sub-transaction + witness Create a sub-transaction key witness + assemble Assemble an unsigned sub-transaction and key + witnesses into a signed sub-transaction txid Print a sub-transaction identifier. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_assemble.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_assemble.cli new file mode 100644 index 0000000000..154492abc1 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_assemble.cli @@ -0,0 +1,13 @@ +Usage: cardano-cli dijkstra sub-transaction assemble --sub-tx-file FILEPATH + [--witness-file FILEPATH] + --out-file FILEPATH + + + Assemble an unsigned sub-transaction and key witnesses into a signed + sub-transaction + +Available options: + --sub-tx-file FILEPATH Input filepath of the JSON unsigned sub-transaction. + --witness-file FILEPATH Filepath of the witness + --out-file FILEPATH Output filepath of the JSON signed sub-transaction. + -h,--help Show this help text diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_witness.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_witness.cli new file mode 100644 index 0000000000..a33de9c575 --- /dev/null +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/dijkstra_sub-transaction_witness.cli @@ -0,0 +1,13 @@ +Usage: cardano-cli dijkstra sub-transaction witness --sub-tx-file FILEPATH + --signing-key-file FILEPATH + --out-file FILEPATH + + + Create a sub-transaction key witness + +Available options: + --sub-tx-file FILEPATH Input filepath of the JSON unsigned sub-transaction. + --signing-key-file FILEPATH + Input filepath of the signing key. + --out-file FILEPATH The output file. + -h,--help Show this help text diff --git a/cardano-cli/test/cardano-cli-test/Test/Cli/Transaction/SubTransaction.hs b/cardano-cli/test/cardano-cli-test/Test/Cli/Transaction/SubTransaction.hs index 7f9ee8ac0c..2cf9f58dc0 100644 --- a/cardano-cli/test/cardano-cli-test/Test/Cli/Transaction/SubTransaction.hs +++ b/cardano-cli/test/cardano-cli-test/Test/Cli/Transaction/SubTransaction.hs @@ -43,15 +43,168 @@ txIn = "63e6a9a8e58e48cc025cae04daaed9d36fc7b70bc292721d9f5057ae37b24981#0" txOut :: String txOut = "addr_test1vp0t4dfa9ktc2uvv7sg9leafuhtwyu0xcj4q4kf5pqkpjwqhklklg+5000000" +-- | Detached signing preserves every payload and agrees with direct signing, +-- including empty witness sets, multiple key roles and duplicate witnesses. +hprop_dijkstra_sub_transaction_witness_assemble :: Property +hprop_dijkstra_sub_transaction_witness_assemble = + watchdogProp . propertyOnce $ H.moduleWorkspace "tmp" $ \tempDir -> do + unsignedFile <- H.noteTempFile tempDir "sub.unsigned" + signedFile <- H.noteTempFile tempDir "sub.signed" + assembledFile <- H.noteTempFile tempDir "sub.assembled" + paramsFile <- H.noteTempFile tempDir "params.json" + metadataFile <- H.noteTempFile tempDir "metadata.json" + stakeKeyFile <- H.noteTempFile tempDir "stake.skey" + stakeVKeyFile <- H.noteTempFile tempDir "stake.vkey" + H.evalIO $ writeDijkstraProtocolParams paramsFile + H.evalIO $ writeFile metadataFile "{\"0\":42}" + void $ + execCardanoCLI + [ "dijkstra" + , "stake-address" + , "key-gen" + , "--signing-key-file" + , stakeKeyFile + , "--verification-key-file" + , stakeVKeyFile + ] + forM_ [False, True] $ \canonical -> do + void $ + execCardanoCLI $ + subTransactionArgs + ++ [ "--tx-in-script-file" + , plutusScriptFile 4 + , "--tx-in-datum-value" + , "0" + , "--tx-in-redeemer-value" + , "0" + , "--tx-in-execution-units" + , "(0,0)" + , "--guard-script-file" + , nativeScriptFile + , "--metadata-json-file" + , metadataFile + , "--protocol-params-file" + , paramsFile + , "--out-file" + , unsignedFile + ] + ++ concat (replicate 24 ["--tx-out", txOut]) + ++ ["--out-canonical-cbor" | canonical] + unsigned@(Exp.UnsignedSubTx unsignedTx) <- + H.evalEither =<< H.evalIO (readFileTextEnvelope (File unsignedFile)) + let bodyBytes = L.originalBytes (unsignedTx ^. L.bodyTxL) + canonicalBytes <- H.evalEither $ canonicaliseCborBs bodyBytes + (bodyBytes == canonicalBytes) H.=== canonical + witnesses <- forM (zip ["payment", "stake"] [signingKey, stakeKeyFile]) $ \(name, key) -> do + witnessFile <- H.noteTempFile tempDir (name ++ ".witness") + void $ + execCardanoCLI + [ "dijkstra" + , "sub-transaction" + , "witness" + , "--sub-tx-file" + , unsignedFile + , "--signing-key-file" + , key + , "--out-file" + , witnessFile + ] + pure witnessFile + forM_ [0, 1, 2, 3] $ \count -> do + let keys = take count [signingKey, stakeKeyFile, signingKey] + files = take count (witnesses ++ witnesses) + void $ + execCardanoCLI $ + ["dijkstra", "sub-transaction", "sign", "--sub-tx-file", unsignedFile, "--out-file", signedFile] + ++ concatMap (\key -> ["--signing-key-file", key]) keys + void $ + execCardanoCLI $ + [ "dijkstra" + , "sub-transaction" + , "assemble" + , "--sub-tx-file" + , unsignedFile + , "--out-file" + , assembledFile + ] + ++ concatMap (\file -> ["--witness-file", file]) files + signedBytes <- H.evalIO $ BS.readFile signedFile + assembledBytes <- H.evalIO $ BS.readFile assembledFile + assembledBytes H.=== signedBytes + assembled@(Exp.SignedSubTx assembledTx) <- + H.evalEither =<< H.evalIO (readFileTextEnvelope (File assembledFile)) + Exp.getSignedSubTxId assembled H.=== Exp.getUnsignedSubTxId unsigned + L.originalBytes (assembledTx ^. L.bodyTxL) H.=== bodyBytes + assembledTx ^. L.auxDataTxL H.=== unsignedTx ^. L.auxDataTxL + assembledTx ^. L.witsTxL . L.scriptTxWitsL H.=== unsignedTx ^. L.witsTxL . L.scriptTxWitsL + assembledTx ^. L.witsTxL . L.datsTxWitsL H.=== unsignedTx ^. L.witsTxL . L.datsTxWitsL + assembledTx ^. L.witsTxL . L.rdmrsTxWitsL H.=== unsignedTx ^. L.witsTxL . L.rdmrsTxWitsL + Set.size (assembledTx ^. L.witsTxL . L.addrTxWitsL) H.=== min count 2 + +-- | Bad inputs fail before creating output; assembly accepts only Dijkstra witnesses. +hprop_dijkstra_sub_transaction_witness_assemble_rejects_invalid_inputs :: Property +hprop_dijkstra_sub_transaction_witness_assemble_rejects_invalid_inputs = + watchdogProp . propertyOnce $ H.moduleWorkspace "tmp" $ \tempDir -> do + unsignedFile <- H.noteTempFile tempDir "sub.unsigned" + signedFile <- H.noteTempFile tempDir "sub.signed" + malformedFile <- H.noteTempFile tempDir "malformed.json" + missingFile <- H.noteTempFile tempDir "missing.json" + bodyFile <- H.noteTempFile tempDir "conway.body" + witnessFile <- H.noteTempFile tempDir "conway.witness" + outFile <- H.noteTempFile tempDir "output" + H.evalIO $ writeFile malformedFile "{}" + void $ execCardanoCLI $ subTransactionArgs ++ ["--out-file", unsignedFile] + void $ + execCardanoCLI + ["dijkstra", "sub-transaction", "sign", "--sub-tx-file", unsignedFile, "--out-file", signedFile] + void $ + execCardanoCLI + ["conway", "transaction", "build-raw", "--tx-in", txIn, "--fee", "0", "--out-file", bodyFile] + void $ + execCardanoCLI + [ "conway" + , "transaction" + , "witness" + , "--tx-body-file" + , bodyFile + , "--signing-key-file" + , signingKey + , "--out-file" + , witnessFile + ] + let reject command args = do + (exitCode, _, stderr) <- + execDetailCardanoCLI $ ["dijkstra", "sub-transaction", command] ++ args ++ ["--out-file", outFile] + exitCode H.=== ExitFailure 1 + H.evalIO (doesFileExist outFile) >>= (H.=== False) + pure stderr + stderr <- reject "assemble" ["--sub-tx-file", unsignedFile, "--witness-file", witnessFile] + H.assertWith stderr ("The era of a witness does not match" `isInfixOf`) + forM_ [signedFile, malformedFile, missingFile] $ \input -> do + void $ reject "witness" ["--sub-tx-file", input, "--signing-key-file", signingKey] + void $ reject "assemble" ["--sub-tx-file", input] + forM_ [malformedFile, missingFile] $ \input -> do + void $ reject "witness" ["--sub-tx-file", unsignedFile, "--signing-key-file", input] + void $ reject "assemble" ["--sub-tx-file", unsignedFile, "--witness-file", input] + void $ reject "witness" ["--sub-tx-file", unsignedFile] + void $ + reject + "witness" + ["--sub-tx-file", unsignedFile, "--signing-key-file", signingKey, "--signing-key-file", signingKey] + forM_ ["witness", "assemble"] $ \command -> do + (exitCode, _, conwayError) <- execDetailCardanoCLI ["conway", "sub-transaction", command] + exitCode H.=== ExitFailure 1 + H.assertWith conwayError ("Invalid argument `sub-transaction'" `isInfixOf`) + -- | Sub-transaction signing rejects the Byron-only address option at parse time. hprop_dijkstra_sub_transaction_sign_rejects_address :: Property hprop_dijkstra_sub_transaction_sign_rejects_address = - watchdogProp . propertyOnce $ do + watchdogProp . propertyOnce $ forM_ ["sign", "witness"] $ \command -> do (exitCode, _, stderr) <- execDetailCardanoCLI [ "dijkstra" , "sub-transaction" - , "sign" + , command , "--sub-tx-file" , "unused" , "--signing-key-file" @@ -260,12 +413,12 @@ hprop_dijkstra_sub_transaction_sign_rejects_byron_key = , "--out-file" , byronKeyFile ] - (exitCode, _stdout, stderr) <- - H.noteShowM $ + forM_ ["sign", "witness"] $ \command -> do + (exitCode, _, stderr) <- execDetailCardanoCLI [ "dijkstra" , "sub-transaction" - , "sign" + , command , "--sub-tx-file" , unsignedFile , "--signing-key-file" @@ -273,10 +426,48 @@ hprop_dijkstra_sub_transaction_sign_rejects_byron_key = , "--out-file" , outFile ] + exitCode H.=== ExitFailure 1 + H.assertWith + stderr + ("Byron (bootstrap) witnesses are not supported for sub-transactions" `isInfixOf`) + H.evalIO (doesFileExist outFile) >>= (H.=== False) + -- A correctly encoded Dijkstra bootstrap witness must also be refused. + bodyFile <- H.noteTempFile tempDir "tx.body" + witnessFile <- H.noteTempFile tempDir "byron.witness" + void $ + execCardanoCLI + ["dijkstra", "transaction", "build-raw", "--tx-in", txIn, "--fee", "0", "--out-file", bodyFile] + void $ + execCardanoCLI + [ "dijkstra" + , "transaction" + , "witness" + , "--tx-body-file" + , bodyFile + , "--signing-key-file" + , byronKeyFile + , "--testnet-magic" + , "42" + , "--out-file" + , witnessFile + ] + (exitCode, _, stderr) <- + execDetailCardanoCLI + [ "dijkstra" + , "sub-transaction" + , "assemble" + , "--sub-tx-file" + , unsignedFile + , "--witness-file" + , witnessFile + , "--out-file" + , outFile + ] exitCode H.=== ExitFailure 1 H.assertWith stderr ("Byron (bootstrap) witnesses are not supported for sub-transactions" `isInfixOf`) + H.evalIO (doesFileExist outFile) >>= (H.=== False) -- | A large output list uses indefinite-length CBOR by default. Canonicalising -- the batch must fail rather than invalidate the embedded signature.