Skip to content
Snippets Groups Projects
Commit 2d2799e3 authored by Éloïs's avatar Éloïs
Browse files

fix(gdev): add constant tx fees (2 cents by tx) to prevent #62

Fix #62
parent 38690cfe
No related branches found
No related tags found
1 merge request!63fix(gdev): add constant tx fees (2 cents by tx) to prevent #62
# Duniter-v2s integration tests # Duniter-v2s end2end tests
## cucumber functionnal tests ## cucumber functionnal tests
...@@ -47,37 +47,9 @@ Feature: My awesome feature ...@@ -47,37 +47,9 @@ Feature: My awesome feature
Then We should observe that Then We should observe that
``` ```
### Test users ### Steps
6 test users are provided:
- alice
- bob
- charlie
- dave
- eve
- ferdie
### genesis state
Each scenario bootstraps its own blockchain with its own genesis state.
By default, all scenarios use the same configuration for the genesis, which is located in the file
`/cucumber-genesis/default.json`.
You can define a custom genesis state for each scenario with the tag `@genesis.confName`. Each scenario is a list of steps. In our context (blockchain), only the `When` and `Then` steps make sense, `Given` being the genesis.
The genesis configuration must then be defined in a json file located at
`/cucumber-genesis/confName.json`.
You can also define a custom genesis at the feature level, all the scenarios of this feature will
then inherit the genesis configuration.
### Currency amounts
Amounts must be expressed as an integer of `ĞD` or `UD`, decimal numbers are not supported.
If you need more precision, you can express amounts in cents of ĞD (write `cĞD`), or in thousandths
of UD (write `mUD`).
#### When #### When
...@@ -95,23 +67,54 @@ List of possible actions: ...@@ -95,23 +67,54 @@ List of possible actions:
Example: `alice should have 10 ĞD` Example: `alice should have 10 ĞD`
### Universal dividend creation
#### Then
- Check the current UD amount - Check the current UD amount
Usage: `Current UD amount should be {amount}.{cents} ĞD` Usage: `Current UD amount should be {amount}.{cents} ĞD`
Example: `Current UD amount should be 10.00 ĞD` Example: `Current UD amount should be 10.00 ĞD`
- Check the monetary mass - Check the monetary mass
Usage: `Monetary mass should be {amount}.{cents} ĞD` Usage: `Monetary mass should be {amount}.{cents} ĞD`
Example: `Monetary mass should be 30.00 ĞD` Example: `Monetary mass should be 30.00 ĞD`
### Test users
6 test users are provided:
- alice
- bob
- charlie
- dave
- eve
- ferdie
### Currency amounts
Amounts must be expressed as an integer of `ĞD` or `UD`, decimal numbers are not supported.
If you need more precision, you can express amounts in cents of ĞD (write `cĞD`), or in thousandths
of UD (write `mUD`).
### genesis state
Each scenario bootstraps its own blockchain with its own genesis state.
By default, all scenarios use the same configuration for the genesis, which is located in the file
`/cucumber-genesis/default.json`.
You can define a custom genesis state for each scenario with the tag `@genesis.confName`.
The genesis configuration must then be defined in a json file located at
`/cucumber-genesis/confName.json`.
You can also define a custom genesis at the feature level, all the scenarios of this feature will
then inherit the genesis configuration.
### ignoreErrors
For some scenarios, you may need to perform an action (When) that fails voluntarily, in this case you must add the tag @ignoreErrors to your scenario, otherwise it will be considered as failed
### Run cucumber functional tests ### Run cucumber functional tests
To run the cucumber tests, you will need to have the rust toolchain installed locally. To run the cucumber tests, you will need to have the rust toolchain installed locally.
......
...@@ -26,6 +26,7 @@ Feature: Balance transfer ...@@ -26,6 +26,7 @@ Feature: Balance transfer
""" """
Then eve should have 2 ĞD Then eve should have 2 ĞD
@ignoreErrors
Scenario: Create a new account without any founds Scenario: Create a new account without any founds
Then eve should have 0 ĞD Then eve should have 0 ĞD
When eve send 0 ĞD to alice When eve send 0 ĞD to alice
......
@genesis.default @genesis.default
Feature: Balance transfer all Feature: Balance transfer all
Scenario: If alice sends all her ĞDs to Dave, Dave will get 8 ĞD Scenario: If bob sends all his ĞDs to Dave
When alice sends all her ĞDs to dave When bob sends all her ĞDs to dave
""" """
Alice is a smith member, as such she is not allowed to empty her account completely, Bob is a member, as such he is not allowed to empty his account completely,
if she tries to do so, the existence deposit (2 ĞD) must remain. if he tries to do so, the existence deposit (2 ĞD) must remain.
""" """
Then alice should have 2 ĞD Then bob should have 2 ĞD
Then dave should have 8 ĞD """
10 ĞD (initial Bob balance) - 2 ĞD (Existential deposit) - 0.02 ĞD (transaction fees)
"""
Then dave should have 798 cĞD
...@@ -29,33 +29,44 @@ use std::sync::{ ...@@ -29,33 +29,44 @@ use std::sync::{
}; };
#[derive(WorldInit)] #[derive(WorldInit)]
pub struct DuniterWorld(Option<DuniterWorldInner>); pub struct DuniterWorld {
ignore_errors: bool,
inner: Option<DuniterWorldInner>,
}
impl DuniterWorld { impl DuniterWorld {
// Write methods
async fn init(&mut self, maybe_genesis_conf_file: Option<PathBuf>) { async fn init(&mut self, maybe_genesis_conf_file: Option<PathBuf>) {
if let Some(ref mut inner) = self.0 { if let Some(ref mut inner) = self.inner {
inner.kill();
}
self.inner = Some(DuniterWorldInner::new(maybe_genesis_conf_file).await);
}
fn kill(&mut self) {
if let Some(ref mut inner) = self.inner {
inner.kill(); inner.kill();
} }
self.0 = Some(DuniterWorldInner::new(maybe_genesis_conf_file).await);
} }
fn set_ignore_errors(&mut self, ignore_errors: bool) {
self.ignore_errors = ignore_errors;
}
// Read methods
fn api(&self) -> &Api { fn api(&self) -> &Api {
if let Some(ref inner) = self.0 { if let Some(ref inner) = self.inner {
&inner.api &inner.api
} else { } else {
panic!("uninit") panic!("uninit")
} }
} }
fn client(&self) -> &Client { fn client(&self) -> &Client {
if let Some(ref inner) = self.0 { if let Some(ref inner) = self.inner {
&inner.client &inner.client
} else { } else {
panic!("uninit") panic!("uninit")
} }
} }
fn kill(&mut self) { fn ignore_errors(&self) -> bool {
if let Some(ref mut inner) = self.0 { self.ignore_errors
inner.kill();
}
} }
} }
...@@ -71,7 +82,10 @@ impl World for DuniterWorld { ...@@ -71,7 +82,10 @@ impl World for DuniterWorld {
type Error = Infallible; type Error = Infallible;
async fn new() -> std::result::Result<Self, Infallible> { async fn new() -> std::result::Result<Self, Infallible> {
Ok(DuniterWorld(None)) Ok(Self {
ignore_errors: false,
inner: None,
})
} }
} }
...@@ -148,10 +162,16 @@ async fn transfer( ...@@ -148,10 +162,16 @@ async fn transfer(
let to = AccountKeyring::from_str(&to).expect("unknown to"); let to = AccountKeyring::from_str(&to).expect("unknown to");
let (amount, is_ud) = parse_amount(amount, &unit); let (amount, is_ud) = parse_amount(amount, &unit);
if is_ud { let res = if is_ud {
common::balances::transfer_ud(world.api(), world.client(), from, amount, to).await common::balances::transfer_ud(world.api(), world.client(), from, amount, to).await
} else { } else {
common::balances::transfer(world.api(), world.client(), from, amount, to).await common::balances::transfer(world.api(), world.client(), from, amount, to).await
};
if world.ignore_errors() {
Ok(())
} else {
res
} }
} }
...@@ -164,13 +184,18 @@ async fn send_all_to(world: &mut DuniterWorld, from: String, to: String) -> Resu ...@@ -164,13 +184,18 @@ async fn send_all_to(world: &mut DuniterWorld, from: String, to: String) -> Resu
common::balances::transfer_all(world.api(), world.client(), from, to).await common::balances::transfer_all(world.api(), world.client(), from, to).await
} }
#[then(regex = r"([a-zA-Z]+) should have (\d+) ĞD")] #[then(regex = r"([a-zA-Z]+) should have (\d+) (ĞD|cĞD)")]
async fn should_have(world: &mut DuniterWorld, who: String, amount: u64) -> Result<()> { async fn should_have(
world: &mut DuniterWorld,
who: String,
amount: u64,
unit: String,
) -> Result<()> {
// Parse inputs // Parse inputs
let who = AccountKeyring::from_str(&who) let who = AccountKeyring::from_str(&who)
.expect("unknown to") .expect("unknown to")
.to_account_id(); .to_account_id();
let amount = amount * 100; let (amount, _is_ud) = parse_amount(amount, &unit);
let who_account = world.api().storage().system().account(who, None).await?; let who_account = world.api().storage().system().account(who, None).await?;
assert_eq!(who_account.data.free, amount); assert_eq!(who_account.data.free, amount);
...@@ -250,6 +275,7 @@ async fn main() { ...@@ -250,6 +275,7 @@ async fn main() {
"{}.json", "{}.json",
genesis_conf_name(&feature.tags, &scenario.tags) genesis_conf_name(&feature.tags, &scenario.tags)
)); ));
world.set_ignore_errors(ignore_errors(&scenario.tags));
Box::pin(world.init(Some(genesis_conf_file_path))) Box::pin(world.init(Some(genesis_conf_file_path)))
}) })
.after(move |_feature, _rule, _scenario, maybe_world| { .after(move |_feature, _rule, _scenario, maybe_world| {
...@@ -280,3 +306,12 @@ fn genesis_conf_name(feature_tags: &[String], scenario_tags: &[String]) -> Strin ...@@ -280,3 +306,12 @@ fn genesis_conf_name(feature_tags: &[String], scenario_tags: &[String]) -> Strin
} }
"default".to_owned() "default".to_owned()
} }
fn ignore_errors(scenario_tags: &[String]) -> bool {
for tag in scenario_tags {
if tag == "ignoreErrors" {
return true;
}
}
false
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
pub use frame_support::weights::{ pub use frame_support::weights::{
Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
}; };
use sp_arithmetic::traits::{BaseArithmetic, Unsigned, Zero}; use sp_arithmetic::traits::{BaseArithmetic, One, Unsigned};
pub struct WeightToFeeImpl<T>(sp_std::marker::PhantomData<T>); pub struct WeightToFeeImpl<T>(sp_std::marker::PhantomData<T>);
...@@ -35,8 +35,8 @@ where ...@@ -35,8 +35,8 @@ where
degree: 1, degree: 1,
}) })
} }
// Force disable fees // Force constant fees
fn calc(_weight: &Weight) -> Self::Balance { fn calc(_weight: &Weight) -> Self::Balance {
Zero::zero() One::one()
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment