Skip to content

Commit

Permalink
feat(integration_tests): new test for downed substates (#798)
Browse files Browse the repository at this point in the history
Description
---
* Refactored the VN util of the integration test so method calls return
a result, making it easier to assert expected errors.
* New cucumber test for downed local substates.

Motivation and Context
---
We want to assert that a substate that has been downed cannot be used
again as an input. There are two situations:
* The substate is local to the VN
* The substate is a remote committee

This PR adds a new test for the first situation, downed local substates.
The second situation requires a more advance integration test setup
where we can manipulate multiple committees deterministically, so it's
left out of scope of this PR.

Ref #387

How Has This Been Tested?
---
New test passes

What process can a PR reviewer use to test or verify this change?
---
Execute the test

Breaking Changes
---

- [x] None
- [ ] Requires data directory to be deleted
- [ ] Other - Please specify
  • Loading branch information
mrnaveira authored Dec 7, 2023
1 parent 095fcd8 commit 5a0c47a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ cucumber = { version = "0.18.0", features = [
"libtest",
"output-junit",
] }
futures = "0.3.29"
httpmock = "0.6.8"
indexmap = "1.9.1"
log = { version = "0.4.8", features = ["std"] }
Expand Down
9 changes: 5 additions & 4 deletions integration_tests/src/validator_node_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::{collections::HashMap, path::PathBuf, str::FromStr};

use tari_engine_types::{
commit_result::RejectReason,
instruction::Instruction,
substate::{SubstateAddress, SubstateDiff},
};
Expand Down Expand Up @@ -215,7 +216,7 @@ pub async fn call_method(
fq_component_name: String,
outputs_name: String,
method_call: String,
) -> SubmitTransactionResponse {
) -> Result<SubmitTransactionResponse, RejectReason> {
let data_dir = get_cli_data_dir(world);
let (input_group, component_name) = fq_component_name.split_once('/').unwrap_or_else(|| {
panic!(
Expand Down Expand Up @@ -256,16 +257,16 @@ pub async fn call_method(
let mut client = world.get_validator_node(&vn_name).get_client();
let resp = handle_submit(args, data_dir, &mut client).await.unwrap();

if let Some(ref failure) = resp.dry_run_result.as_ref().unwrap().finalize.reject() {
panic!("Transaction failed: {:?}", failure);
if let Some(failure) = resp.dry_run_result.as_ref().unwrap().finalize.reject() {
return Err(failure.clone());
}
// store the account component address and other substate addresses for later reference
add_substate_addresses(
world,
outputs_name,
resp.dry_run_result.as_ref().unwrap().finalize.result.accept().unwrap(),
);
resp
Ok(resp)
}

pub async fn submit_manifest(
Expand Down
33 changes: 29 additions & 4 deletions integration_tests/tests/cucumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,34 @@ async fn call_component_method(
method_call: String,
output_name: String,
) {
let resp = validator_node_cli::call_method(world, vn_name, component_name, output_name, method_call).await;
let resp = validator_node_cli::call_method(world, vn_name, component_name, output_name, method_call)
.await
.unwrap();
assert_eq!(resp.dry_run_result.unwrap().decision, QuorumDecision::Accept);

// give it some time between transactions
// tokio::time::sleep(Duration::from_secs(4)).await;
}

#[when(
expr = r#"I invoke on {word} on component {word} the method call "{word}" named "{word}" the result is error {string}"#
)]
async fn call_component_method_must_error(
world: &mut TariWorld,
vn_name: String,
component_name: String,
method_call: String,
output_name: String,
error_msg: String,
) {
let res = validator_node_cli::call_method(world, vn_name, component_name, output_name, method_call).await;
if let Err(reject) = res {
assert!(reject.to_string().contains(&error_msg));
} else {
panic!("Expected an error but the call was successful");
}
}

#[when(expr = r#"I invoke on all validator nodes on component {word} the method call "{word}" named "{word}""#)]
async fn call_component_method_on_all_vns(
world: &mut TariWorld,
Expand All @@ -230,7 +251,8 @@ async fn call_component_method_on_all_vns(
output_name.clone(),
method_call.clone(),
)
.await;
.await
.unwrap();
assert_eq!(resp.dry_run_result.unwrap().decision, QuorumDecision::Accept);
}
// give it some time between transactions
Expand All @@ -246,7 +268,9 @@ async fn call_component_method_and_check_result(
expected_result: String,
) {
let resp =
validator_node_cli::call_method(world, vn_name, component_name, "dummy_outputs".to_string(), method_call).await;
validator_node_cli::call_method(world, vn_name, component_name, "dummy_outputs".to_string(), method_call)
.await
.unwrap();
let finalize_result = resp.dry_run_result.unwrap();
assert_eq!(finalize_result.decision, QuorumDecision::Accept);

Expand Down Expand Up @@ -283,7 +307,8 @@ async fn call_component_method_on_all_vns_and_check_result(
"dummy_outputs".to_string(),
method_call.clone(),
)
.await;
.await
.unwrap();
let finalize_result = resp.dry_run_result.unwrap();
assert_eq!(finalize_result.decision, QuorumDecision::Accept);

Expand Down
48 changes: 48 additions & 0 deletions integration_tests/tests/features/substates.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2022 The Tari Project
# SPDX-License-Identifier: BSD-3-Clause

Feature: Substates

@serial
Scenario: Transactions with DOWN local substates are rejected
Given fees are disabled
# Initialize a base node, wallet, miner and VN
Given a base node BASE
Given a wallet WALLET connected to base node BASE
Given a miner MINER connected to base node BASE and wallet WALLET

# Initialize a VN
Given a validator node VAL_1 connected to base node BASE and wallet WALLET

# The wallet must have some funds before the VN sends transactions
When miner MINER mines 6 new blocks
When wallet WALLET has at least 20 T

# VN registration
When validator node VAL_1 sends a registration transaction

# Register the "counter" template
When validator node VAL_1 registers the template "counter"
When miner MINER mines 13 new blocks
Then VAL_1 has scanned to height 16
Then the validator node VAL_1 is listed as registered
Then the template "counter" is listed as registered by the validator node VAL_1

# A file-base CLI account must be created to sign future calls
When I use an account key named K1

# Create a new Counter component
When I create a component COUNTER_1 of template "counter" on VAL_1 using "new"

# Increase the counter an check the value
When I invoke on VAL_1 on component COUNTER_1/components/Counter the method call "increase" named "TX1"
When I invoke on VAL_1 on component TX1/components/Counter the method call "value" the result is "1"

# We should get an error if we se as inputs the same component version thas has already been downed from previous transactions
# We can achieve this by reusing inputs from COUNTER_1 instead of the most recent TX1
When I invoke on VAL_1 on component COUNTER_1/components/Counter the method call "increase" named "TX2" the result is error "Shard was rejected"

# Check that the counter has NOT been increased by the previous erroneous transaction
When I invoke on VAL_1 on component TX1/components/Counter the method call "value" the result is "1"


0 comments on commit 5a0c47a

Please sign in to comment.