Skip to content

Conversation

@smelc
Copy link
Contributor

@smelc smelc commented Feb 5, 2025

Description

Fixes #6069

Fixes #6137

This PR makes it possible for callers of the cardano-testnet binary to pass a custom node configuration file, as well as custom genesis files. To do so, a new --node-config flag is added to the cardano-testnet executable:

Usage: cardano-testnet cardano [--num-pool-nodes COUNT | --node-config FILEPATH]
  ...

Available options:
  --num-pool-nodes COUNT   Number of pool nodes. Note this uses a default node
                           configuration for all nodes. (default: 1)
  --node-config FILEPATH   Path to the node's configuration file (which is
                           generated otherwise). This option also allows to pass
                           custom genesis files: if an era genesis file pointed
                           to in this file (fields "AlonzoGenesisFile",
                           "ShelleyGenesisFile", etc.) doesn't exist, it is
                           automatically generated. So point to an existing
                           genesis file to use your own file, or simply omit it
                           to have it generated by cardano-testnet. See
                           https://github.com/IntersectMBO/cardano-node/blob/master/cardano-testnet/test/cardano-testnet-test/Cardano/Testnet/Test/CommandLineExecutable.hs
                           for an example of usage.

As explained above, this flag also allows to pass custom genesis files.

How to trust this PR

Execute the new test

The new behavior is tested in the new test CommandLineExecutable.hs which you can execute locally as follows:

> cabal test cardano-testnet-test --test-options '-p "/cardano-testnet-executable/"'
Running 1 test suites...
Test suite cardano-testnet-test: RUNNING...
test/Spec.hs
  Spec
    CLI
      cardano-testnet-executable: OK (60.07s)
          ✓ cardano-testnet-executable passed 1 test.

All 1 tests passed (60.07s)
Test suite cardano-testnet-test: PASS
Test suite logged to:
/home/churlin/dev/cardano-node/dist-newstyle/build/x86_64-linux/ghc-8.10.7/cardano-testnet-10.0.0/t/cardano-testnet-test/noopt/test/cardano-testnet-10.0.0-cardano-tes

Note how the test finishes in 60 seconds, which is a duration chosen in CommandLineExecutable.hs, during which we check that nodes have been produced.

Execute the cardano-testnet binary directly

You can also run the cardano-testnet binary directly as follows (here using a custom node configuration file and a custom alonzo and conway genesis, but leaving the shelley genesis (the hardest to tweak) to be autogenerated:

> cat test-cardano-testnet.sh
#!/usr/bin/env bash
set -eux

TMP_DIR=$(mktemp -d)

for config_file in alonzo-genesis.json configuration.json conway-genesis.json
do
  cp cardano-testnet/test/cardano-testnet-test/files/input/executable/$config_file $TMP_DIR/.
done

cabal run cardano-testnet -- cardano --node-config $TMP_DIR/configuration.json --output-dir $TMP_DIR --testnet-magic 42
> ./test-cardano-testnet.sh
  ✗ <interactive> failed at src/Testnet/Property/Run.hs:89:7
    after 1 test.
    shrink path: 1:
  
    forAll0 =
      ━━━━ File: /tmp/nix-shell.iZ2TPc/tmp.ly3nO21w1e/current-stake-pools.json ━━━━
      [
          "pool1r8fuwkk3kkfekh6el0kzydrn009yqd89mrv4zpjq77wg6639ese"
      ]
    
    forAll1 =
      Reading file: /tmp/nix-shell.iZ2TPc/tmp.ly3nO21w1e/current-stake-pools.json
    
    forAll2 =
      ━━━━ command ━━━━
      /home/churlin/.local/state/cabal/store/ghc-8.10.7/cardano-cli-10.4.0.0-e-cardano-cli-3b9fee1097cc434bbca7740006a83745fcc229aa57d45fcca2712990862bc6b9/bin/cardano-cli latest query stake-pools --out-file /tmp/nix-shell.iZ2TPc/tmp.ly3nO21w1e/current-stake-pools.json
    
    forAll3 =
      /tmp/nix-shell.iZ2TPc/tmp.ly3nO21w1e/current-stake-pools.json
...
... lots of output
...
forAll75 =
      Reusing /tmp/nix-shell.iZ2TPc/tmp.ly3nO21w1e
  
    This failure can be reproduced by running:
    > recheckAt (Seed 1622863211725641548 12217359344083085813) "1:" <property>
  
Testnet is running.  Type CTRL-C to exit.

At this point the testnet is running and you can kill this process using CTRL-C, but it doesn't kill the cardano-node process. ⚠️ This will need to be fixed soon as proposed below. Also we will want to unplug ourselves from the test monad in this scenario and this is already tracked here: #6122

In the meantime, users can either do killall cardano-node to clean up or use a combination of pidof cardano-node and kill. I didn't want to do in this PR, as this one is quite big already.

Follow-up issues to create

@Jimbo4350> please tick them if you agree 🙂 I'll create them

  • Have pTestnetNodeOptions return a list of TestnetNodeOption and TestnetNodeOption be UserProvidedNodeOptions Filepath | SpoNodeOptions [Srting] | RelayNodeOptions [ String]. In other words merge the types TestnetNodeOptions and AutomaticNodeOption. This will generalize the behavior so that the user can create multiple nodes, no matter whether they are using custom options or using default behavior (Spo or Relay). This will require a bit of generalization in Cardano.hs but not much.
  • Check consistency of the value passed to cardanoTestnet: if the user passes a custom node configuration file and a custom genesis file (as a Haskell value right now), we should check that the genesis file pointed to by the node configuration file (if any) contains the same Haskell value as the custom genesis file.
  • Change cardanoTestnet to take Filepath for genesis files instead of Haskell values, maybe?
  • Check that the CLI flags changing Shelley genesis values are not used when passing a custom Shelley genesis file (TODOs are added in the code too about this).
  • Created already: cardano-testnet: runTestnet: don't tie it with H.Integration #6122

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • CI passes.
  • New tests are added
  • Self-reviewed the diff

@smelc smelc changed the title cardano-testnet: allow to take config files as input cardano-testnet: allow to take node config and genesis files as input Feb 5, 2025
Base automatically changed from smelc/cardano-testnet-support-custom-node-config-file to master February 5, 2025 16:14
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from 3894926 to 8e37423 Compare February 7, 2025 13:53
@smelc smelc marked this pull request as ready for review February 7, 2025 13:53
@smelc smelc requested a review from a team as a code owner February 7, 2025 13:53
Copy link
Contributor

@Jimbo4350 Jimbo4350 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you plan to deal with conflicts in the node configuration yaml file? I think this is the wrong approach. We don't want to be forced to reconcile configuration file differences. All we should need the is the node configuration yaml file.

@smelc smelc force-pushed the smelc/testnet-pass-config-files branch 2 times, most recently from 63c60a5 to 6ca79c5 Compare February 11, 2025 16:16
@smelc
Copy link
Contributor Author

smelc commented Feb 12, 2025

For future reference, if we leave the call to cardano-cli debug check-node-configuration, we have the following failures with the following genesis files:

> cabal run cardano-testnet -- cardano --output-dir cl-output-dir --node-config cl-example/configuration.json --testnet-magic 44
  ✗ <interactive> failed at src/Testnet/Start/Cardano.hs:283:3
    after 1 test.
    shrink path: 1:
  
    forAll0 =
      Process exited with non-zero exit-code: 1
      ━━━━ stdout ━━━━
      Checking byron genesis file: cl-example/byron.genesis.spec.json
      
      ━━━━ stderr ━━━━
      Error reading node configuration at: cl-example/byron.genesis.spec.json: Incorrect schema for GenesisData.
       Error: expected field protocolConsts

It seems the code is requiring too much data here when deserializing the Byron genesis. This data is actually not required to start the node (i.e. if we remove the check, the testnet starts fine). So it seems overkill to require this data when starting a testnet.

[edit] Oh well, it seems the node doesn't like it either actually:

<interactive> failed at src/Testnet/Start/Cardano.hs:342:5
    after 1 test.
    shrink path: 1:
  
    forAll0 =
      Cardano node process did not start: CardanoProtocolInstantiationError (CardanoProtocolInstantiationErrorByron (GenesisReadError "/home/churlin/dev/cardano-node/cl-example/byron.genesis.spec.json" (GenesisDataSchemaError (SchemaError {seExpected = "field protocolConsts", seActual = Nothing}))))
      
      cardano-node: There was an error parsing the genesis file: "/home/churlin/dev/cardano-node/cl-example/byron.genesis.spec.json" Error: GenesisDataSchemaError (SchemaError {seExpected = "field protocolConsts", seActual = Nothing})

smelc added a commit that referenced this pull request Feb 12, 2025
The node itself, when it starts, doesn't require hashes of genesis
files. So it seems overkill to require it to start a testnet.
See also
#6103 (comment)
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from 6ca79c5 to d67ff61 Compare February 12, 2025 10:38
smelc added a commit that referenced this pull request Feb 12, 2025
The node itself, when it starts, doesn't require hashes of genesis
files. So it seems overkill to require it to start a testnet.
See also
#6103 (comment)
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from d67ff61 to c78c34f Compare February 12, 2025 10:39
smelc added a commit that referenced this pull request Feb 12, 2025
The node itself, when it starts, doesn't require hashes of genesis
files. So it seems overkill to require it to start a testnet.
See also
#6103 (comment)
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from c78c34f to 1f7c3d8 Compare February 12, 2025 14:25
smelc added a commit that referenced this pull request Feb 12, 2025
The node itself, when it starts, doesn't require hashes of genesis
files. So it seems overkill to require it to start a testnet.
See also
#6103 (comment)
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from 18c0d3e to 50849e1 Compare February 12, 2025 15:30
smelc added a commit that referenced this pull request Feb 12, 2025
The node itself, when it starts, doesn't require hashes of genesis
files. So it seems overkill to require it to start a testnet.
See also
#6103 (comment)
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch 3 times, most recently from 8117ffc to 3671f83 Compare February 18, 2025 12:14
@smelc smelc changed the title cardano-testnet: allow to take node config and genesis files as input cardano-testnet: allow to take node config file as input Feb 18, 2025
@smelc
Copy link
Contributor Author

smelc commented Feb 18, 2025

All we should need the is the node configuration yaml file.

@Jimbo4350> Updated version of this PR now does that 👍

smelc added a commit that referenced this pull request Feb 18, 2025
… node configuration file (it was unused)

This will be done differently in
#6103
smelc added a commit that referenced this pull request Feb 18, 2025
… node configuration file (it was unused)

This will be done differently in
#6103
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from c25acc3 to 6dc7fb4 Compare February 18, 2025 14:52
Copy link
Contributor

@Jimbo4350 Jimbo4350 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an improvement 👍 . Have a look at my comments.

<> OA.showDefault
<> OA.value 1)
, UserNodeOptions
<$> strOption ( long "node-config"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is an improvement however the resultant type should be [TestnetNodeOptions]. Users (or QA) may want to for example create forking conditions whereby nodes have different configurations. This will have to be done in another PR at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I agree, but as you say, this ought to be done later. This PR does a lot of changes already.

Nothing -> error $ "Genesis files not specified in node configuration file: " <> nodeInputConfigFile
Just x -> x
adjustedProtocolConfig =
-- Make all the files be relative to the location of the config file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

alonzoGenesisFile
conwayGenesisFile
where
getShelleyGenesises (NodeProtocolConfigurationCardano _byron shelley alonzo conway _hardForkConfig) =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also want to confirm the validity of the byron genesis but that can be a separate PR in the future.

where
nSpoNodes =
case cardanoNodes of
UserNodeOptions _ -> 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding this isn't great. This is related to my comment above regarding [TestnetNodeOptions]

-- to run a testnet. "create-staked" is not a good way to do this especially because it
-- makes assumptions about where things should go and where genesis template files should be.
-- See all of the ad hoc file creation/renaming/dir creation etc below.
H.failMessage GHC.callStack "Specifying node configuration files per node not supported yet."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to note that we want to support configuration files per node. However it's not urgent to do this now.

cardanoNumRelays CardanoTestnetOptions{cardanoNodes} =
NumRelays . length $ filter isRelayNodeOptions cardanoNodes
cardanoNumRelays CardanoTestnetOptions{cardanoNodes=_} =
undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

=> HasCallStack
=> CardanoTestnetOptions -- ^ The options to use
-> Conf
-> UserNodeConfig -- ^ The node configuration file to use. If omitted it's generated.
Copy link
Contributor

@Jimbo4350 Jimbo4350 Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an indication that TestnetNodeOptions ought to be renamed to TestnetNodeConfiguration.
A type like the following would be more indicative:

data TestnetNodeConfiguration
  = UserSpecifiedConfiguration FilePath
  | DefaultConfiguration [AutomaticNodeOption]

However what we really want is:

data TestnetNodeConfiguration
  = UserSpecifiedConfiguration FilePath
  | DefaultSpoConfiguration [String]
  | DefaultRelayConfiguration [String]

This gives users the most flexibility in that they can spin up a testnet with a mixture of nodes. Haddocks are desperately needed to indicate that [String] types are command line executable modifiers.

@smelc smelc changed the title cardano-testnet: allow to take node config file as input cardano-testnet executable: take node config file as optional input Mar 11, 2025
@smelc smelc force-pushed the smelc/per-genesis-file-origin branch from ad8dbd6 to 70c0e00 Compare March 11, 2025 14:51
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from 1b6c518 to c4aba77 Compare March 11, 2025 15:04
@smelc smelc force-pushed the smelc/per-genesis-file-origin branch from 70c0e00 to 9cd0ae0 Compare March 11, 2025 15:07
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from c4aba77 to 4d424b6 Compare March 11, 2025 15:51
@smelc smelc force-pushed the smelc/per-genesis-file-origin branch from 9cd0ae0 to 72ea5dc Compare March 11, 2025 18:45
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from 4d424b6 to fa3a62e Compare March 12, 2025 13:37
Base automatically changed from smelc/per-genesis-file-origin to master March 12, 2025 16:15
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch 8 times, most recently from 89d6e24 to d922fb3 Compare March 12, 2025 17:03
@smelc smelc marked this pull request as ready for review March 12, 2025 17:04
@smelc smelc force-pushed the smelc/testnet-pass-config-files branch from d922fb3 to 47f3da4 Compare March 13, 2025 13:32
adjustFilePaths (takeDirectory nodeInputConfigFile </>) protocolConfig
(shelley, alonzo, conway) = getShelleyGenesises adjustedProtocolConfig
-- The paths to the genesis files have to exist in the node configuration file,
-- but the files themselves don't have to exist. So if the user wants to pass
Copy link
Contributor

@Jimbo4350 Jimbo4350 Mar 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user wants to call cardanoTestnet and mix and match their genesis files then fine but this should not be possible at the executable level. If all the genesis files do not exist in the user provided configuration we fail hard. We do not provide them with our defaults. They only use our defaults if they provide no configuration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but this should not be possible at the executable level.

Why not? I'm not sure there's much value in requiring all configuration files from the user.

Let's continue discussion here: #6137 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jimbo4350> design you prefer implemented here: #6148

Approve the one you want merged!

@smelc
Copy link
Contributor Author

smelc commented Mar 14, 2025

Closed in favor of #6148

@smelc smelc closed this Mar 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants