CBOR test case generator and deserializer for cross-checking other implementations.
❯ testgen-hs --help
Usage: testgen-hs COMMAND
Test case generator for cross-checking CBOR (de)serializers
Available options:
-h,--help Show this help text
Available commands:
generate Generate random CBOR test cases
deserialize Deserialize CBOR of ‘HardForkApplyTxErr’ that you got
from cardano-node
❯ testgen-hs generate --help
Usage: testgen-hs generate [-s|--seed SEED] [-g|--generator-size SIZE]
[-n|--number NUM] COMMAND
Generate random CBOR test cases
Available options:
-s,--seed SEED Random seed integer (UNIX timestamp by default)
-g,--generator-size SIZE Set the relative ‘size’ of the test cases
-n,--number NUM How many test cases to generate
-h,--help Show this help text
Available commands:
ApplyTxErr_Byron Generate CBOR of ApplyTxErr'Byron
ApplyTxErr_Shelley Generate CBOR of ApplyTxErr'Shelley
ApplyTxErr_Allegra Generate CBOR of ApplyTxErr'Allegra
ApplyTxErr_Mary Generate CBOR of ApplyTxErr'Mary
ApplyTxErr_Alonzo Generate CBOR of ApplyTxErr'Alonzo
ApplyTxErr_Babbage Generate CBOR of ApplyTxErr'Babbage
ApplyTxErr_Conway Generate CBOR of ApplyTxErr'Conway
GHCInteger Generate CBOR of GHCInteger
DataText Generate CBOR of DataText
ExampleADT Generate CBOR of ExampleADT
❯ testgen-hs generate -g1 -n1 ApplyTxErr_Conway
{
"seed": 1731690796,
"testCases": [
{
"cbor": "81820682820182018082038210581de0988807a48f6c7871bfa29d3ea70a6328c5fa35beb8c48589c676dc7b",
"haskellRepr": "ApplyTxError (ConwayUtxowFailure (InvalidWitnessesUTXOW []) :| [ConwayGovFailure (ProposalReturnAccountDoesNotExist (RewardAccount {raNetwork = Testnet, raCredential = KeyHashObj (KeyHash {unKeyHash = \"988807a48f6c7871bfa29d3ea70a6328c5fa35beb8c48589c676dc7b\"})}))])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayUtxowFailure (InvalidWitnessesUTXOW [])",
"ConwayGovFailure (ProposalReturnAccountDoesNotExist (RewardAccount {raNetwork = Testnet, raCredential = KeyHashObj (KeyHash {unKeyHash = \"988807a48f6c7871bfa29d3ea70a6328c5fa35beb8c48589c676dc7b\"})}))"
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}
]
}With a little of Bash, it's possible to search for a particular error:
❯ while true ; do
output=$(testgen-hs generate -g1 -n1 ApplyTxErr_Conway)
if grep -q FeeTooSmall <<<"$output" ; then
jq . <<<"$output"
break
fi
sleep 0.01
done{
"seed": 1732539592414,
"testCases": [
{
"cbor": "81820682830601008201820083051a000aa8a91a000291ff",
"haskellRepr": "ApplyTxError (ConwayTxRefScriptsSizeTooBig 1 0 :| [ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 698537) (Coin 168447)))])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayTxRefScriptsSizeTooBig 1 0",
"ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 698537) (Coin 168447)))"
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}
]
}And then easily reproduce it by providing the same seed that was found:
❯ testgen-hs generate -s1732539592414 -g1 -n1 ApplyTxErr_Conway
{
"seed": 1732539592414,
"testCases": [
{
"cbor": "81820682830601008201820083051a000aa8a91a000291ff",
"haskellRepr": "ApplyTxError (ConwayTxRefScriptsSizeTooBig 1 0 :| [ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 698537) (Coin 168447)))])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayTxRefScriptsSizeTooBig 1 0",
"ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 698537) (Coin 168447)))"
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}
]
}❯ testgen-hs generate -s1732187056519 -g1 -n1 ApplyTxErr_Conway
{
"seed": 1732187056519,
"testCases": [
{
"cbor": "818206828201820083051a000151351a00074b8582076162",
"haskellRepr": "ApplyTxError (ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 86325) (Coin 478085))) :| [ConwayMempoolFailure \"b\"])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 86325) (Coin 478085)))",
"ConwayMempoolFailure \"b\""
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}
]
}❯ testgen-hs generate -s1732186210861 -g1 -n1 ApplyTxErr_Conway
{
"seed": 1732186210861,
"testCases": [
{
"cbor": "818206828201820083051a000a63d11a0009580683051a0008d00a1a0001ebc4",
"haskellRepr": "ApplyTxError (ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 680913) (Coin 612358))) :| [ConwayTreasuryValueMismatch (Coin 577546) (Coin 125892)])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 680913) (Coin 612358)))",
"ConwayTreasuryValueMismatch (Coin 577546) (Coin 125892)"
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}
]
}❯ testgen-hs deserialize 818206828201820083051a000a63d11a0009580683051a0008d00a1a0001ebc4
{
"cbor": "818206828201820083051a000a63d11a0009580683051a0008d00a1a0001ebc4",
"haskellRepr": "ApplyTxError (ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 680913) (Coin 612358))) :| [ConwayTreasuryValueMismatch (Coin 577546) (Coin 125892)])",
"json": {
"contents": {
"contents": {
"contents": {
"era": "ShelleyBasedEraConway",
"error": [
"ConwayUtxowFailure (UtxoFailure (FeeTooSmallUTxO (Coin 680913) (Coin 612358)))",
"ConwayTreasuryValueMismatch (Coin 577546) (Coin 125892)"
],
"kind": "ShelleyTxValidationError"
},
"tag": "TxValidationErrorInCardanoMode"
},
"tag": "TxCmdTxSubmitValidationError"
},
"tag": "TxSubmitFail"
},
"typeTag": "ApplyTxError (ConwayEra StandardCrypto)"
}❯ ( echo 8182068182028200a0
echo 81820681820481581cc0231342a5c66b25d652a7116559d02cbe9515ef890fd698de38d456
) | testgen-hs deserialize-stream
{"cbor":"8182068182028200a0","haskellRepr":"ApplyTxError (ConwayCertsFailure (WithdrawalsNotInRewardsCERTS (fromList [])) :| [])","json":{"contents":{"contents":{"contents":{"era":"ShelleyBasedEraConway","error":["ConwayCertsFailure (WithdrawalsNotInRewardsCERTS (fromList []))"],"kind":"ShelleyTxValidationError"},"tag":"TxValidationErrorInCardanoMode"},"tag":"TxCmdTxSubmitValidationError"},"tag":"TxSubmitFail"},"typeTag":"ApplyTxError (ConwayEra StandardCrypto)"}
{"cbor":"81820681820481581cc0231342a5c66b25d652a7116559d02cbe9515ef890fd698de38d456","haskellRepr":"ApplyTxError (ConwayWdrlNotDelegatedToDRep (KeyHash {unKeyHash = \"c0231342a5c66b25d652a7116559d02cbe9515ef890fd698de38d456\"} :| []) :| [])","json":{"contents":{"contents":{"contents":{"era":"ShelleyBasedEraConway","error":["ConwayWdrlNotDelegatedToDRep (KeyHash {unKeyHash = \"c0231342a5c66b25d652a7116559d02cbe9515ef890fd698de38d456\"} :| [])"],"kind":"ShelleyTxValidationError"},"tag":"TxValidationErrorInCardanoMode"},"tag":"TxCmdTxSubmitValidationError"},"tag":"TxSubmitFail"},"typeTag":"ApplyTxError (ConwayEra StandardCrypto)"}This project provides a Nix devshell with GHC and HLS. To get full IDE
support you need direnv with
nix-direnv so that the
.envrc is picked up automatically. See their official documentation for
installation instructions.
The instructions below use VS Code as an example, but any editor with LSP and
direnv support (Neovim, Emacs, etc.) works the same way. The devshell puts
both haskell-language-server and haskell-language-server-wrapper on
PATH, so most editors should pick up HLS automatically.
-
Install the extensions Haskell (
haskell.haskell) and direnv (mkhl.direnv). -
Tell the Haskell extension to use the HLS provided by the devshell instead of managing its own. Add this to your VS Code settings:
{ "haskell.manageHLS": "PATH" }Optionally, enable semantic highlighting (richer colours for types, type variables, etc.):
{ "haskell.plugin.semanticTokens.globalOn": true } -
Allow direnv for this project and restart HLS:
direnv allowThen in VS Code:
Ctrl+Shift+P→ Haskell: Restart Haskell LSP Server.
Note: The first HLS session takes roughly 10 minutes while
hie-biosbuilds all dependencies viacabal v2-repl. Subsequent loads use the cache at~/.cache/hie-bios/.