Skip to content

Commit

Permalink
Merge pull request #1974 from input-output-hk/jpraynaud/1946-era-swit…
Browse files Browse the repository at this point in the history
…ch-e2e-tests

Feat: implement era switch in e2e tests
  • Loading branch information
jpraynaud authored Oct 10, 2024
2 parents 6849c3a + d3fe03f commit 03aa794
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 71 deletions.
43 changes: 36 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ jobs:
matrix:
mode: ["std"]
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras) }}
next_era: [""]
cardano_node_version: ["9.0.0", "9.1.0", "9.1.1", "9.2.0", "9.2.1"]
hard_fork_latest_era_at_epoch: [0]
run_id: ["#1"]
Expand All @@ -298,10 +299,27 @@ jobs:
# Include a test for the P2P mode
- mode: "p2p"
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}
next_era: [""]
cardano_node_version: "9.1.1"
hard_fork_latest_era_at_epoch: 0
run_id: "#1"
extra_args: "--use-p2p-network"
# Include a test for the era switch without regenesis
- mode: "std"
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}
next_era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[1] }}
cardano_node_version: "9.1.1"
hard_fork_latest_era_at_epoch: 0
run_id: "#1"
extra_args: ""
# Include a test for the era switch with regenesis
- mode: "std"
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}
next_era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[1] }}
cardano_node_version: "9.1.1"
hard_fork_latest_era_at_epoch: 0
run_id: "#1"
extra_args: "--mithril-era-regenesis-on-switch"
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand All @@ -328,13 +346,24 @@ jobs:
- name: Test
run: |
./mithril-end-to-end -vvv \
--bin-directory ./bin \
--work-directory=./artifacts \
--devnet-scripts-directory=./mithril-test-lab/mithril-devnet \
--mithril-era=${{ matrix.era }} \
--cardano-node-version ${{ matrix.cardano_node_version }} \
--cardano-hard-fork-latest-era-at-epoch ${{ matrix.hard_fork_latest_era_at_epoch }} ${{ matrix.extra_args }}
cat > ./mithril-end-to-end.sh << EOF
#!/bin/bash
set -x
./mithril-end-to-end -vvv \\
--bin-directory ./bin \\
--work-directory=./artifacts \\
--devnet-scripts-directory=./mithril-test-lab/mithril-devnet \\
--mithril-era=${{ matrix.era }} \\
--cardano-node-version ${{ matrix.cardano_node_version }} \\
--cardano-hard-fork-latest-era-at-epoch ${{ matrix.hard_fork_latest_era_at_epoch }} ${{ matrix.extra_args }} \\
EOF
# If there is a next era, we need to specify it with '--mithril-next-era'
if [[ "${{ matrix.next_era }}" != "" ]]; then
echo " --mithril-next-era=${{ matrix.next_era }}" >> ./mithril-end-to-end.sh
fi
chmod u+x ./mithril-end-to-end.sh
./mithril-end-to-end.sh
rm ./mithril-end-to-end.sh
- name: Upload E2E Tests Artifacts
if: ${{ failure() }}
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ As a minor extension, we have adopted a slightly different versioning convention

- Support for stable Cardano transaction client library, CLI and WASM.

- Support for Mithril era switch in end to end test.

- Crates versions:

| Crate | Version |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mithril-test-lab/mithril-devnet/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.1
0.4.2
2 changes: 0 additions & 2 deletions mithril-test-lab/mithril-devnet/mkfiles/mkfiles-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ GENESIS_SECRET_KEY=5b3131382c3138342c3232342c3137332c3136302c3234312c36312c31343
CHAIN_OBSERVER_TYPE=pallas

cat >> docker-compose.yaml <<EOF
version: "3.9"
services:
EOF

Expand Down
48 changes: 33 additions & 15 deletions mithril-test-lab/mithril-devnet/mkfiles/mkfiles-mithril-era.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,19 @@ function send_funds_to_era_address {
--tx-file node-pool${N}/tx/tx${N}-era-funds.tx \\
--testnet-magic ${NETWORK_MAGIC}
## Compute the submitted transaction id
TX_ID_SUBMITTED=\$(CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI \${CURRENT_CARDANO_ERA} transaction txid --tx-file node-pool${N}/tx/tx${N}-era-funds.tx)
## Wait at least for 10 blocks so that the transaction is confirmed
wait_for_elapsed_blocks 10
## Wait for all pool nodes to see the new funds
## Wait for all pool nodes to see the new transaction
for (( i=1; i<=${NUM_POOL_NODES}; i++ )); do
AMOUNT_RETRIEVED=\$(CARDANO_NODE_SOCKET_PATH=node-pool\${i}/ipc/node.sock $CARDANO_CLI query utxo \\
TOTAL_UTXOS_FOR_TX_ID=\$(CARDANO_NODE_SOCKET_PATH=node-pool\${i}/ipc/node.sock $CARDANO_CLI query utxo \\
--testnet-magic ${NETWORK_MAGIC} --address \$(cat addresses/${ADDR}.addr) --out-file /dev/stdout \\
| jq '. [] | select(.value.lovelace | . != null and . != "") | .value.lovelace')
| jq '. | with_entries(select(.key | startswith("${TX_ID_SUBMITTED}"))) | length')
echo ">>>>>> Era address funds retrieved on node-pool\${i}: \${AMOUNT_RETRIEVED}"
if [ "\${AMOUNT_RETRIEVED}" != "${AMOUNT_TRANSFERRED}" ]; then
if [ "\${TOTAL_UTXOS_FOR_TX_ID}" == "0" ]; then
touch ${MITHRIL_ERA_ERROR_FILE}
break
fi
Expand Down Expand Up @@ -139,20 +142,35 @@ function write_datums_for_era_address {
# Remove if exists previous error file
rm -f ${MITHRIL_ERA_ERROR_FILE}
# Write the era datum on chain
TX_IN=\$(CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI query utxo \\
# Fetch transactions from UTxOs of the era address
TX_IN_DATUM=\$(CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI query utxo \\
--testnet-magic ${NETWORK_MAGIC} --address \$(cat addresses/${ADDR}.addr) --out-file /dev/stdout \\
| jq -r 'to_entries | map({utxo: .key} + .value) | . [] | select(.inlineDatum | . != null and . != "") | .utxo')
TX_IN_NO_DATUM=\$(CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI query utxo \\
--testnet-magic ${NETWORK_MAGIC} --address \$(cat addresses/${ADDR}.addr) --out-file /dev/stdout \\
| jq -r 'to_entries | [last] | .[0].key')
## Build the transaction
CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI \${CURRENT_CARDANO_ERA} transaction build \\
--tx-in \${TX_IN} \\
--tx-out \$(cat addresses/${ADDR}.addr)+${SCRIPT_TX_VALUE} \\
--tx-out-inline-datum-file \${DATUM_FILE} \\
--change-address \$(cat addresses/${ADDR}.addr) \\
--testnet-magic ${NETWORK_MAGIC} \\
--invalid-hereafter 100000 \\
--out-file node-pool${N}/tx/tx${N}-era-datum.txbody
if [ "\${TX_IN_DATUM}" == "" ]; then
CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI \${CURRENT_CARDANO_ERA} transaction build \\
--tx-in \${TX_IN_NO_DATUM} \\
--tx-out \$(cat addresses/${ADDR}.addr)+${SCRIPT_TX_VALUE} \\
--tx-out-inline-datum-file \${DATUM_FILE} \\
--change-address \$(cat addresses/${ADDR}.addr) \\
--testnet-magic ${NETWORK_MAGIC} \\
--invalid-hereafter 100000 \\
--out-file node-pool${N}/tx/tx${N}-era-datum.txbody
else
CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI \${CURRENT_CARDANO_ERA} transaction build \\
--tx-in \${TX_IN_DATUM} \\
--tx-in \${TX_IN_NO_DATUM} \\
--tx-out \$(cat addresses/${ADDR}.addr)+${SCRIPT_TX_VALUE} \\
--tx-out-inline-datum-file \${DATUM_FILE} \\
--change-address \$(cat addresses/${ADDR}.addr) \\
--testnet-magic ${NETWORK_MAGIC} \\
--invalid-hereafter 100000 \\
--out-file node-pool${N}/tx/tx${N}-era-datum.txbody
fi
## Sign the transaction
CARDANO_NODE_SOCKET_PATH=node-pool${N}/ipc/node.sock $CARDANO_CLI \${CURRENT_CARDANO_ERA} transaction sign \\
Expand All @@ -173,7 +191,7 @@ function write_datums_for_era_address {
for (( i=1; i<=${NUM_POOL_NODES}; i++ )); do
INLINE_DATUM=\$(CARDANO_NODE_SOCKET_PATH=node-pool\${i}/ipc/node.sock $CARDANO_CLI query utxo \\
--testnet-magic ${NETWORK_MAGIC} --address \$(cat addresses/${ADDR}.addr) --out-file /dev/stdout \\
| jq -r '. [] | select(.inlineDatum | . != null and . != "") | .inlineDatum.fields[].bytes' | xxd -r -p)
| jq -r '. [] | select(.inlineDatum | . != null and . != "") | .inlineDatum.fields[].bytes' | xxd -r -p | jq)
echo ">>>>>> Era address inline datum retrieved on node-pool\${i}: \${INLINE_DATUM}"
if [ "\${INLINE_DATUM}" == "" ]; then
touch ${MITHRIL_ERA_ERROR_FILE}
Expand Down
2 changes: 1 addition & 1 deletion mithril-test-lab/mithril-end-to-end/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-end-to-end"
version = "0.4.36"
version = "0.4.37"
authors = { workspace = true }
edition = { workspace = true }
documentation = { workspace = true }
Expand Down
9 changes: 5 additions & 4 deletions mithril-test-lab/mithril-end-to-end/src/assertions/exec.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use crate::{Aggregator, Devnet};
use mithril_common::entities::ProtocolParameters;
use mithril_common::entities::{Epoch, ProtocolParameters};
use mithril_common::StdResult;
use slog_scope::info;

Expand All @@ -22,18 +22,19 @@ pub async fn register_era_marker(
aggregator: &mut Aggregator,
devnet: &Devnet,
mithril_era: &str,
era_epoch: Epoch,
) -> StdResult<()> {
info!("Register era marker");
info!("Register '{mithril_era}' era marker");

info!("> generating era marker tx datum...");
let tx_datum_file_path = devnet
.artifacts_dir()
.join(PathBuf::from("era-tx-datum.txt".to_string()));
aggregator
.era_generate_tx_datum(&tx_datum_file_path, mithril_era)
.era_generate_tx_datum(&tx_datum_file_path, mithril_era, era_epoch)
.await?;

info!("> writing era marker on the Cardano chain...");
info!("> writing '{mithril_era}' era marker on the Cardano chain...");
devnet.write_era_marker(&tx_datum_file_path).await?;

Ok(())
Expand Down
77 changes: 71 additions & 6 deletions mithril-test-lab/mithril-end-to-end/src/end_to_end_spec.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
use crate::assertions;
use crate::MithrilInfrastructure;
use mithril_common::StdResult;
use mithril_common::{
entities::{Epoch, SignedEntityTypeDiscriminants},
StdResult,
};

pub struct Spec<'a> {
pub infrastructure: &'a mut MithrilInfrastructure,
is_signing_cardano_transactions: bool,
is_signing_cardano_stake_distribution: bool,
next_era: Option<String>,
regenesis_on_era_switch: bool,
}

impl<'a> Spec<'a> {
pub fn new(infrastructure: &'a mut MithrilInfrastructure) -> Self {
Self { infrastructure }
pub fn new(
infrastructure: &'a mut MithrilInfrastructure,
signed_entity_types: Vec<String>,
next_era: Option<String>,
regenesis_on_era_switch: bool,
) -> Self {
Self {
infrastructure,
is_signing_cardano_transactions: signed_entity_types.contains(
&SignedEntityTypeDiscriminants::CardanoTransactions
.as_ref()
.to_string(),
),
is_signing_cardano_stake_distribution: signed_entity_types.contains(
&SignedEntityTypeDiscriminants::CardanoStakeDistribution
.as_ref()
.to_string(),
),
next_era,
regenesis_on_era_switch,
}
}

pub async fn run(&mut self) -> StdResult<()> {
Expand Down Expand Up @@ -71,6 +97,45 @@ impl<'a> Spec<'a> {
)
.await?;

// Verify that artifacts are produced and signed correctly
let mut target_epoch = self.verify_artifacts_production(target_epoch).await?;

// Verify that artifacts are produced and signed correctly after era switch
if let Some(next_era) = &self.next_era {
// Switch to next era
self.infrastructure
.register_switch_to_next_era(next_era)
.await?;
target_epoch += 5;
assertions::wait_for_target_epoch(
self.infrastructure.chain_observer(),
target_epoch,
"epoch after which the era switch will have triggered".to_string(),
)
.await?;

// Proceed to a re-genesis of the certificate chain
if self.regenesis_on_era_switch {
assertions::bootstrap_genesis_certificate(self.infrastructure.aggregator_mut())
.await?;
target_epoch += 5;
assertions::wait_for_target_epoch(
self.infrastructure.chain_observer(),
target_epoch,
"epoch after which the re-genesis on era switch will be completed".to_string(),
)
.await?;
}

// Verify that artifacts are produced and signed correctly
self.verify_artifacts_production(target_epoch).await?;
}

Ok(())
}

async fn verify_artifacts_production(&self, target_epoch: Epoch) -> StdResult<Epoch> {
let aggregator_endpoint = self.infrastructure.aggregator().endpoint();
let expected_epoch_min = target_epoch - 3;
// Verify that mithril stake distribution artifacts are produced and signed correctly
{
Expand Down Expand Up @@ -116,7 +181,7 @@ impl<'a> Spec<'a> {
}

// Verify that Cardano transactions artifacts are produced and signed correctly
if self.infrastructure.is_signing_cardano_transactions() {
if self.is_signing_cardano_transactions {
let hash = assertions::assert_node_producing_cardano_transactions(&aggregator_endpoint)
.await?;
let certificate_hash = assertions::assert_signer_is_signing_cardano_transactions(
Expand All @@ -143,7 +208,7 @@ impl<'a> Spec<'a> {
}

// Verify that Cardano stake distribution artifacts are produced and signed correctly
if self.infrastructure.is_signing_cardano_stake_distribution() {
if self.is_signing_cardano_stake_distribution {
{
let (hash, epoch) = assertions::assert_node_producing_cardano_stake_distribution(
&aggregator_endpoint,
Expand Down Expand Up @@ -173,6 +238,6 @@ impl<'a> Spec<'a> {
}
}

Ok(())
Ok(target_epoch)
}
}
18 changes: 16 additions & 2 deletions mithril-test-lab/mithril-end-to-end/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ pub struct Args {
#[clap(long, default_value = "thales")]
mithril_era: String,

/// Mithril next era to run
#[clap(long)]
mithril_next_era: Option<String>,

/// Mithril re-genesis on era switch (used only when 'mithril_next_era' is set)
#[clap(long, default_value_t = false)]
mithril_era_regenesis_on_switch: bool,

/// Mithril era reader adapter
#[clap(long, default_value = "cardano-chain")]
mithril_era_reader_adapter: String,
Expand Down Expand Up @@ -191,10 +199,11 @@ async fn main() -> StdResult<()> {
mithril_run_interval: args.mithril_run_interval,
mithril_era: args.mithril_era,
mithril_era_reader_adapter: args.mithril_era_reader_adapter,
signed_entity_types: args.signed_entity_types,
signed_entity_types: args.signed_entity_types.clone(),
run_only_mode,
use_p2p_network_mode,
use_p2p_passive_relays,
use_era_specific_work_dir: args.mithril_next_era.is_some(),
})
.await?;

Expand All @@ -204,7 +213,12 @@ async fn main() -> StdResult<()> {
run_only.start().await
}
false => {
let mut spec = Spec::new(&mut infrastructure);
let mut spec = Spec::new(
&mut infrastructure,
args.signed_entity_types,
args.mithril_next_era,
args.mithril_era_regenesis_on_switch,
);
spec.run().await
}
};
Expand Down
Loading

0 comments on commit 03aa794

Please sign in to comment.