From 413d3f48c4bdebfa6c9c72f4161da4c1236d6444 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 19:26:13 +0100 Subject: [PATCH 001/104] Add ICS02 model --- modules/tests/support/model_based/.gitignore | 7 + modules/tests/support/model_based/ICS02.cfg | 10 ++ modules/tests/support/model_based/ICS02.tla | 146 ++++++++++++++++++ .../tests/support/model_based/ICS02Tests.cfg | 12 ++ .../tests/support/model_based/ICS02Tests.tla | 22 +++ modules/tests/support/model_based/Makefile | 6 + .../support/model_based/counterexample.tla | 39 +++++ modules/tests/support/model_based/test.json | 14 ++ 8 files changed, 256 insertions(+) create mode 100644 modules/tests/support/model_based/.gitignore create mode 100644 modules/tests/support/model_based/ICS02.cfg create mode 100644 modules/tests/support/model_based/ICS02.tla create mode 100644 modules/tests/support/model_based/ICS02Tests.cfg create mode 100644 modules/tests/support/model_based/ICS02Tests.tla create mode 100644 modules/tests/support/model_based/Makefile create mode 100644 modules/tests/support/model_based/counterexample.tla create mode 100644 modules/tests/support/model_based/test.json diff --git a/modules/tests/support/model_based/.gitignore b/modules/tests/support/model_based/.gitignore new file mode 100644 index 0000000000..46e548cea0 --- /dev/null +++ b/modules/tests/support/model_based/.gitignore @@ -0,0 +1,7 @@ +*.out +states/ +x/ +detailed.log +bfs.csv +log0.smt +profile-rules.txt diff --git a/modules/tests/support/model_based/ICS02.cfg b/modules/tests/support/model_based/ICS02.cfg new file mode 100644 index 0000000000..ecddb236a6 --- /dev/null +++ b/modules/tests/support/model_based/ICS02.cfg @@ -0,0 +1,10 @@ +CONSTANTS + MaxClientId = 5 + MaxHeight = 5 + +INIT Init +NEXT Next + +INVARIANTS + TypeOK + ModelNeverErrors \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla new file mode 100644 index 0000000000..a7be842874 --- /dev/null +++ b/modules/tests/support/model_based/ICS02.tla @@ -0,0 +1,146 @@ +--------------------------- MODULE ICS02 ---------------------------- + +EXTENDS Integers, FiniteSets + +\* max client identifier +CONSTANT MaxClientId +ASSUME MaxClientId > 0 +\* max height which clients can reach +CONSTANT MaxHeight +ASSUME MaxHeight > 0 + +\* set of client data +VARIABLE clients +\* counter used to generate client identifiers +VARIABLE nextClientId +\* last action performed +VARIABLE action +\* string with the outcome of the last operation +VARIABLE actionOutcome + +(********************* TYPE ANNOTATIONS FOR APALACHE ***********************) +\* operator for type annotations +a <: b == a + +ActionType == [ + type |-> STRING, + clientId |-> Int, + height |-> Int +] +AsAction(a) == a <: ActionType +(****************** END OF TYPE ANNOTATIONS FOR APALACHE ********************) + +\* set of possible client identifiers +ClientIds == 1..MaxClientId +\* set of possible heights +Heights == 1..MaxHeight +\* if a client has a null height then the client does not exist +NullHeight == 0 +\* set of possible actions +NullActions == [ + type: {"Null"} +] <: {ActionType} +CreateClientActions == [ + type: {"CreateClient"}, + height: Heights +] <: {ActionType} +UpdateClientActions == [ + type: {"UpdateClient"}, + clientId: ClientIds, + height: Heights +] <: {ActionType} +Actions == NullActions \union CreateClientActions \union UpdateClientActions +\* set of possible outcomes +ActionOutcomes == {"Null", "CreateOK", "UpdateOK", "UpdateClientNotFound", "UpdateHeightVerificationFailure", "ModelError"} + + +(*************************************************************************** + Specification + ***************************************************************************) + +\* check if a client exists +ClientExists(clientId) == + clients[clientId] /= NullHeight + +SetClientHeight(clientId, clientHeight) == + [clients EXCEPT ![clientId] = clientHeight] + +CreateClient(clientHeight) == + \* check if the client exists (it shouldn't) + IF ClientExists(nextClientId) THEN + \* if the client to be created already exists, + \* then there's an error in the model + /\ actionOutcome' = "ModelError" + /\ UNCHANGED <> + ELSE + \* set the new client's height to `clientHeight` + /\ clients' = SetClientHeight(nextClientId, clientHeight) + \* update `nextClientId` + /\ nextClientId' = nextClientId + 1 + \* set `outcome` + /\ actionOutcome' = "CreateOK" + +UpdateClient(clientId, clientHeight) == + \* check if the client exists + IF ClientExists(clientId) THEN + \* if the client exists, check its height + IF clients[clientId] < clientHeight THEN + \* if its height is lower than the one being updated to + \* then, update the client + /\ clients' = SetClientHeight(clientId, clientHeight) + \* set outcome + /\ actionOutcome' = "UpdateOK" + /\ UNCHANGED <> + ELSE + /\ actionOutcome' = "UpdateHeightVerificationFailure" + /\ UNCHANGED <> + ELSE + \* if the client does not exist, then return an error + /\ actionOutcome' = "UpdateClientNotFound" + /\ UNCHANGED <> + +CreateClientAction == + \* only create client if the model constant `MaxClientId` allows it + /\ nextClientId < MaxClientId + \* select a height for the client to be created at + /\ \E clientHeight \in Heights: + /\ action' = AsAction([type |-> "CreateClient", + height |-> clientHeight]) + /\ CreateClient(clientHeight) + +UpdateClientAction == + \* select a client to be updated (which may not exist) + \E clientId \in ClientIds: + \* select a height for the client to be updated + \E clientHeight \in Heights: + /\ action' = AsAction([type |-> "UpdateClient", + clientId |-> clientId, + height |-> clientHeight]) + /\ UpdateClient(clientId, clientHeight) + + Init == + /\ clients = [clientId \in ClientIds |-> NullHeight] + /\ nextClientId = 1 + /\ action = AsAction([type |-> "Null"]) + /\ actionOutcome = "Null" + +Next == + \/ CreateClientAction + \/ UpdateClientAction + \/ UNCHANGED <> + +(*************************************************************************** + Invariants + ***************************************************************************) + +TypeOK == + /\ nextClientId \in ClientIds \union {MaxClientId + 1} + /\ clients \in [ClientIds -> Heights \union {NullHeight}] + /\ action \in Actions + /\ actionOutcome \in ActionOutcomes + +\* the model never erros +ModelNeverErrors == + actionOutcome /= "ModelError" + +============================================================================= diff --git a/modules/tests/support/model_based/ICS02Tests.cfg b/modules/tests/support/model_based/ICS02Tests.cfg new file mode 100644 index 0000000000..3cad4d28ed --- /dev/null +++ b/modules/tests/support/model_based/ICS02Tests.cfg @@ -0,0 +1,12 @@ +CONSTANTS + MaxClientId = 5 + MaxHeight = 5 + +INIT Init +NEXT Next + +INVARIANTS + \* CreateOKTest + \* UpdateOKTest + \* UpdateClientNotFoundTest + UpdateHeightVerificationFailureTest \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02Tests.tla b/modules/tests/support/model_based/ICS02Tests.tla new file mode 100644 index 0000000000..3664de67ab --- /dev/null +++ b/modules/tests/support/model_based/ICS02Tests.tla @@ -0,0 +1,22 @@ +------------------------- MODULE ICS02Tests --------------------------- + +EXTENDS ICS02 + +CreateOK == + /\ actionOutcome = "CreateOK" + +UpdateOK == + /\ actionOutcome = "UpdateOK" + +UpdateClientNotFound == + /\ actionOutcome = "UpdateClientNotFound" + +UpdateHeightVerificationFailure == + /\ actionOutcome = "UpdateHeightVerificationFailure" + +CreateOKTest == ~CreateOK +UpdateOKTest == ~UpdateOK +UpdateClientNotFoundTest == ~UpdateClientNotFound +UpdateHeightVerificationFailureTest == ~UpdateHeightVerificationFailure + +============================================================================= \ No newline at end of file diff --git a/modules/tests/support/model_based/Makefile b/modules/tests/support/model_based/Makefile new file mode 100644 index 0000000000..9e5318a5f2 --- /dev/null +++ b/modules/tests/support/model_based/Makefile @@ -0,0 +1,6 @@ +test: + apalache-mc check ICS02Tests.tla + +check: + apalache-mc check ICS02.tla + diff --git a/modules/tests/support/model_based/counterexample.tla b/modules/tests/support/model_based/counterexample.tla new file mode 100644 index 0000000000..f3c00c968d --- /dev/null +++ b/modules/tests/support/model_based/counterexample.tla @@ -0,0 +1,39 @@ +------------------------- MODULE counterexample ------------------------- + +EXTENDS ICS02Tests + +(* Initial state *) + +State1 == +TRUE +(* Transition 0 to State2 *) + +State2 == +/\ action = [type |-> "Null"] +/\ actionOutcome = "Null" +/\ clients = 1 :> 0 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 +/\ nextClientId = 1 + +(* Transition 1 to State3 *) + +State3 == +/\ action = [height |-> 1, type |-> "CreateClient"] +/\ actionOutcome = "CreateOK" +/\ clients = 1 :> 1 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 +/\ nextClientId = 2 + +(* Transition 5 to State4 *) + +State4 == +/\ action = [clientId |-> 1, height |-> 1, type |-> "UpdateClient"] +/\ actionOutcome = "UpdateHeightVerificationFailure" +/\ clients = 1 :> 1 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 +/\ nextClientId = 2 + +(* The following formula holds true in the last state and violates the invariant *) + +InvariantViolation == actionOutcome = "UpdateHeightVerificationFailure" + +================================================================================ +\* Created by Apalache on Tue Feb 02 19:12:27 CET 2021 +\* https://github.com/informalsystems/apalache diff --git a/modules/tests/support/model_based/test.json b/modules/tests/support/model_based/test.json new file mode 100644 index 0000000000..b39b88b238 --- /dev/null +++ b/modules/tests/support/model_based/test.json @@ -0,0 +1,14 @@ +[ + { + "action": {"type": "Null"}, + "actionOutcome": "Null" + }, + { + "action": {"height": 1, "type": "CreateClient"}, + "actionOutcome": "CreateOK" + }, + { + "action": {"clientId": 1, "height": 1, "type": "UpdateClient"}, + "actionOutcome": "UpdateHeightVerificationFailure" + } +] \ No newline at end of file From 065631ed45b0943a8b3a1bfb5c82ab3c02aefd3e Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 20:44:19 +0100 Subject: [PATCH 002/104] Add MBT test driver --- modules/Cargo.toml | 2 + modules/tests/Makefile | 2 + modules/tests/model_based.rs | 62 +++++++++++++++++++++ modules/tests/modelator.rs | 41 ++++++++++++++ modules/tests/support/model_based/test.json | 15 ++++- 5 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 modules/tests/Makefile create mode 100644 modules/tests/model_based.rs create mode 100644 modules/tests/modelator.rs diff --git a/modules/Cargo.toml b/modules/Cargo.toml index 5c303f4512..00c4a51ae8 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -37,6 +37,8 @@ dyn-clonable = "0.9.0" regex = "1" bech32 = "0.7.2" +eyre = "0.6.5" + [dependencies.tendermint] version = "=0.18.0" diff --git a/modules/tests/Makefile b/modules/tests/Makefile new file mode 100644 index 0000000000..7ec1b1e4d1 --- /dev/null +++ b/modules/tests/Makefile @@ -0,0 +1,2 @@ +test: + cargo t -- --nocapture main diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs new file mode 100644 index 0000000000..841ecdae87 --- /dev/null +++ b/modules/tests/model_based.rs @@ -0,0 +1,62 @@ +mod modelator; + +use serde::Deserialize; +use std::fmt::Debug; + +#[derive(Debug, Clone, Deserialize)] +struct State { + action: Action, + + #[serde(alias = "actionOutcome")] + action_outcome: ActionOutcome, +} + +#[derive(Debug, Clone, Deserialize)] +struct Action { + #[serde(alias = "type")] + action_type: ActionType, + + #[serde(alias = "clientId")] + client_id: Option, + + height: Option, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +enum ActionType { + Null, + CreateClient, + UpdateClient, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +enum ActionOutcome { + Null, + CreateOK, + UpdateHeightVerificationFailure, +} + +struct ICS02TestExecutor; + +impl modelator::TestExecutor for ICS02TestExecutor { + fn check_initial_state(&mut self, state: State) -> bool { + let type_is_null = state.action.action_type == ActionType::Null; + let outcome_is_null = state.action_outcome == ActionOutcome::Null; + type_is_null && outcome_is_null + } + + fn check_next_state(&mut self, state: State) -> bool { + todo!() + } +} + +#[test] +fn main() { + let path = "tests/support/model_based/test.json"; + let test_executor = ICS02TestExecutor; + // we should be able to just return the `Result` once the following issue + // is fixed: https://github.com/rust-lang/rust/issues/43301 + if let Err(e) = modelator::test_driver(test_executor, path) { + panic!("{:?}", e); + } +} diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs new file mode 100644 index 0000000000..bf16912319 --- /dev/null +++ b/modules/tests/modelator.rs @@ -0,0 +1,41 @@ +use eyre::{eyre, Context, Result}; +use serde::de::DeserializeOwned; +use std::fmt::Debug; +use std::fs::File; +use std::path::Path; + +pub trait TestExecutor { + fn check_initial_state(&mut self, state: S) -> bool; + + fn check_next_state(&mut self, state: S) -> bool; +} + +pub fn test_driver(mut test_executor: E, path: P) -> Result<()> +where + E: TestExecutor, + S: DeserializeOwned + Debug + Clone, + P: AsRef, +{ + let reader = File::open(path.as_ref()) + .wrap_err_with(|| format!("test file {:?} not found.", path.as_ref()))?; + let states: Vec = serde_json::de::from_reader(reader) + .wrap_err_with(|| format!("test file {:?} could not be deserialized", path.as_ref()))?; + + let mut states = states.into_iter(); + + if let Some(state) = states.next() { + if !test_executor.check_initial_state(state.clone()) { + return Err(eyre!("check failed on initial state {:?}", state)); + } + } else { + println!("WARNING: test file {:?} had 0 states", path.as_ref()); + return Ok(()); + } + + for state in states { + if !test_executor.check_next_state(state.clone()) { + return Err(eyre!("check failed on state {:?}", state)); + } + } + Ok(()) +} diff --git a/modules/tests/support/model_based/test.json b/modules/tests/support/model_based/test.json index b39b88b238..f826069b6e 100644 --- a/modules/tests/support/model_based/test.json +++ b/modules/tests/support/model_based/test.json @@ -1,14 +1,23 @@ [ { - "action": {"type": "Null"}, + "action": { + "type": "Null" + }, "actionOutcome": "Null" }, { - "action": {"height": 1, "type": "CreateClient"}, + "action": { + "height": 1, + "type": "CreateClient" + }, "actionOutcome": "CreateOK" }, { - "action": {"clientId": 1, "height": 1, "type": "UpdateClient"}, + "action": { + "clientId": 1, + "height": 1, + "type": "UpdateClient" + }, "actionOutcome": "UpdateHeightVerificationFailure" } ] \ No newline at end of file From b98c7d3ee07a8de60418b6f13bf35f8aba5879c5 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 21:52:40 +0100 Subject: [PATCH 003/104] Add ICS02TestExecutor --- .../src/ics02_client/msgs/create_client.rs | 6 +- modules/tests/Makefile | 2 +- modules/tests/model_based.rs | 140 +++++++++++++----- modules/tests/modelator.rs | 16 +- modules/tests/state.rs | 35 +++++ 5 files changed, 155 insertions(+), 44 deletions(-) create mode 100644 modules/tests/state.rs diff --git a/modules/src/ics02_client/msgs/create_client.rs b/modules/src/ics02_client/msgs/create_client.rs index 114e2e30c4..35280124a8 100644 --- a/modules/src/ics02_client/msgs/create_client.rs +++ b/modules/src/ics02_client/msgs/create_client.rs @@ -22,9 +22,9 @@ pub const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; /// A type of message that triggers the creation of a new on-chain (IBC) client. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgCreateAnyClient { - client_state: AnyClientState, - consensus_state: AnyConsensusState, - signer: AccountId, + pub client_state: AnyClientState, + pub consensus_state: AnyConsensusState, + pub signer: AccountId, } impl MsgCreateAnyClient { diff --git a/modules/tests/Makefile b/modules/tests/Makefile index 7ec1b1e4d1..7d64c99e0d 100644 --- a/modules/tests/Makefile +++ b/modules/tests/Makefile @@ -1,2 +1,2 @@ test: - cargo t -- --nocapture main + cargo t --features mocks -- --nocapture main diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 841ecdae87..5320d0ee16 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -1,43 +1,50 @@ mod modelator; +mod state; -use serde::Deserialize; +use ibc::ics02_client::client_def::AnyHeader; +use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; +use ibc::ics02_client::client_type::ClientType; +use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; +use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; +use ibc::ics02_client::msgs::ClientMsg; +use ibc::ics24_host::identifier::ChainId; +use ibc::ics24_host::identifier::ClientId; +use ibc::ics26_routing::msgs::ICS26Envelope; +use ibc::mock::client_state::{MockClientState, MockConsensusState}; +use ibc::mock::context::MockContext; +use ibc::mock::header::MockHeader; +use ibc::mock::host::HostType; +use ibc::Height; +use state::{ActionOutcome, ActionType, State}; use std::fmt::Debug; +use tendermint::account::Id as AccountId; -#[derive(Debug, Clone, Deserialize)] -struct State { - action: Action, - - #[serde(alias = "actionOutcome")] - action_outcome: ActionOutcome, -} - -#[derive(Debug, Clone, Deserialize)] -struct Action { - #[serde(alias = "type")] - action_type: ActionType, - - #[serde(alias = "clientId")] - client_id: Option, - - height: Option, +#[derive(Debug)] +struct ICS02TestExecutor { + version: u64, + ctx: MockContext, } -#[derive(Debug, Clone, PartialEq, Deserialize)] -enum ActionType { - Null, - CreateClient, - UpdateClient, -} +impl ICS02TestExecutor { + fn new() -> Self { + let version = 1; + let ctx = MockContext::new( + ChainId::new("mock".to_string(), version), + HostType::Mock, + 1, + Height::new(version, 0), + ); + // let ctx = MockContext::new( + // ChainId::new("mock".to_string(), cv), + // HostType::SyntheticTendermint, + // 1, + // Height::new(cv, 0), + // ); -#[derive(Debug, Clone, PartialEq, Deserialize)] -enum ActionOutcome { - Null, - CreateOK, - UpdateHeightVerificationFailure, + Self { version, ctx } + } } -struct ICS02TestExecutor; - impl modelator::TestExecutor for ICS02TestExecutor { fn check_initial_state(&mut self, state: State) -> bool { let type_is_null = state.action.action_type == ActionType::Null; @@ -46,16 +53,81 @@ impl modelator::TestExecutor for ICS02TestExecutor { } fn check_next_state(&mut self, state: State) -> bool { - todo!() + match state.action.action_type { + ActionType::Null => panic!("next state action type cannot be null"), + ActionType::CreateClient => { + // get action parameters + let height = state + .action + .height + .expect("update client action should have a height"); + + // create client and consensus state from parameters + let client_state = AnyClientState::Mock(MockClientState(self.mock_header(height))); + let consensus_state = + AnyConsensusState::Mock(MockConsensusState(self.mock_header(height))); + + // create dummy signer + let signer = self.dummy_signer(); + + // create ICS26 message + let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { + client_state, + consensus_state, + signer, + })); + self.ctx.deliver(msg).unwrap(); + true + } + ActionType::UpdateClient => { + // TODO: rename clientId to clientCounter in the model + // get action parameters + let client_id = state + .action + .client_id + .expect("update client action should have a client identifier"); + let height = state + .action + .height + .expect("update client action should have a height"); + + // create client id and header from action parameters + let client_id = ClientId::new(ClientType::Mock, client_id) + .expect("it should be possible to create the client identifier"); + let header = AnyHeader::Mock(self.mock_header(height)); + + // create dummy signer + let signer = self.dummy_signer(); + + // create ICS26 message + let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { + client_id, + header, + signer, + })); + self.ctx.deliver(msg).unwrap(); + true + } + } + } +} + +impl ICS02TestExecutor { + fn dummy_signer(&self) -> AccountId { + AccountId::new([0; 20]) + } + + fn mock_header(&self, height: u64) -> MockHeader { + MockHeader(Height::new(self.version, height)) } } #[test] fn main() { let path = "tests/support/model_based/test.json"; - let test_executor = ICS02TestExecutor; + let test_executor = ICS02TestExecutor::new(); // we should be able to just return the `Result` once the following issue - // is fixed: https://github.com/rust-lang/rust/issues/43301 + // is fixed: https://github.com/rust-lang/rust/issues/43301 if let Err(e) = modelator::test_driver(test_executor, path) { panic!("{:?}", e); } diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index bf16912319..8663e205e8 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -10,9 +10,9 @@ pub trait TestExecutor { fn check_next_state(&mut self, state: S) -> bool; } -pub fn test_driver(mut test_executor: E, path: P) -> Result<()> +pub fn test_driver(mut executor: E, path: P) -> Result<()> where - E: TestExecutor, + E: TestExecutor + Debug, S: DeserializeOwned + Debug + Clone, P: AsRef, { @@ -24,8 +24,8 @@ where let mut states = states.into_iter(); if let Some(state) = states.next() { - if !test_executor.check_initial_state(state.clone()) { - return Err(eyre!("check failed on initial state {:?}", state)); + if !executor.check_initial_state(state.clone()) { + return Err(eyre!("check failed on initial state:\n{:#?}", state)); } } else { println!("WARNING: test file {:?} had 0 states", path.as_ref()); @@ -33,8 +33,12 @@ where } for state in states { - if !test_executor.check_next_state(state.clone()) { - return Err(eyre!("check failed on state {:?}", state)); + if !executor.check_next_state(state.clone()) { + return Err(eyre!( + "check failed on state:\n{:#?}\n\nexecutor:\n{:#?}", + state, + executor + )); } } Ok(()) diff --git a/modules/tests/state.rs b/modules/tests/state.rs new file mode 100644 index 0000000000..a88c303bd7 --- /dev/null +++ b/modules/tests/state.rs @@ -0,0 +1,35 @@ +use serde::Deserialize; +use std::fmt::Debug; + +#[derive(Debug, Clone, Deserialize)] +pub struct State { + pub action: Action, + + #[serde(alias = "actionOutcome")] + pub action_outcome: ActionOutcome, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Action { + #[serde(alias = "type")] + pub action_type: ActionType, + + #[serde(alias = "clientId")] + pub client_id: Option, + + pub height: Option, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub enum ActionType { + Null, + CreateClient, + UpdateClient, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub enum ActionOutcome { + Null, + CreateOK, + UpdateHeightVerificationFailure, +} From 6685cc103b6e4887d4a6395a5ef5a4218703e671 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 22:02:58 +0100 Subject: [PATCH 004/104] Add another apalache counterexample --- ... UpdateHeightVerificationFailureTest.json} | 0 .../support/model_based/UpdateOKTest.json | 23 +++++++++++ .../support/model_based/counterexample.tla | 39 ------------------- 3 files changed, 23 insertions(+), 39 deletions(-) rename modules/tests/support/model_based/{test.json => UpdateHeightVerificationFailureTest.json} (100%) create mode 100644 modules/tests/support/model_based/UpdateOKTest.json delete mode 100644 modules/tests/support/model_based/counterexample.tla diff --git a/modules/tests/support/model_based/test.json b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json similarity index 100% rename from modules/tests/support/model_based/test.json rename to modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json diff --git a/modules/tests/support/model_based/UpdateOKTest.json b/modules/tests/support/model_based/UpdateOKTest.json new file mode 100644 index 0000000000..06a9531db5 --- /dev/null +++ b/modules/tests/support/model_based/UpdateOKTest.json @@ -0,0 +1,23 @@ +[ + { + "action": { + "type": "Null" + }, + "actionOutcome": "Null" + }, + { + "action": { + "height": 1, + "type": "CreateClient" + }, + "actionOutcome": "CreateOK" + }, + { + "action": { + "clientId": 1, + "height": 2, + "type": "UpdateClient" + }, + "actionOutcome": "UpdateOK" + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/counterexample.tla b/modules/tests/support/model_based/counterexample.tla deleted file mode 100644 index f3c00c968d..0000000000 --- a/modules/tests/support/model_based/counterexample.tla +++ /dev/null @@ -1,39 +0,0 @@ -------------------------- MODULE counterexample ------------------------- - -EXTENDS ICS02Tests - -(* Initial state *) - -State1 == -TRUE -(* Transition 0 to State2 *) - -State2 == -/\ action = [type |-> "Null"] -/\ actionOutcome = "Null" -/\ clients = 1 :> 0 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 -/\ nextClientId = 1 - -(* Transition 1 to State3 *) - -State3 == -/\ action = [height |-> 1, type |-> "CreateClient"] -/\ actionOutcome = "CreateOK" -/\ clients = 1 :> 1 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 -/\ nextClientId = 2 - -(* Transition 5 to State4 *) - -State4 == -/\ action = [clientId |-> 1, height |-> 1, type |-> "UpdateClient"] -/\ actionOutcome = "UpdateHeightVerificationFailure" -/\ clients = 1 :> 1 @@ 2 :> 0 @@ 3 :> 0 @@ 4 :> 0 @@ 5 :> 0 -/\ nextClientId = 2 - -(* The following formula holds true in the last state and violates the invariant *) - -InvariantViolation == actionOutcome = "UpdateHeightVerificationFailure" - -================================================================================ -\* Created by Apalache on Tue Feb 02 19:12:27 CET 2021 -\* https://github.com/informalsystems/apalache From f86348614c58770bcf4de617fb9a4d2f1025dcec Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 22:14:50 +0100 Subject: [PATCH 005/104] Fix ICS02.tla: client counter starts at 0 --- modules/tests/model_based.rs | 19 +++++---- modules/tests/state.rs | 2 + modules/tests/support/model_based/.gitignore | 2 + modules/tests/support/model_based/ICS02.cfg | 2 +- modules/tests/support/model_based/ICS02.tla | 40 +++++++++---------- .../tests/support/model_based/ICS02Tests.cfg | 2 +- .../UpdateHeightVerificationFailureTest.json | 2 +- .../support/model_based/UpdateOKTest.json | 2 +- 8 files changed, 40 insertions(+), 31 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 5320d0ee16..6ed8d8c7cf 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -80,7 +80,6 @@ impl modelator::TestExecutor for ICS02TestExecutor { true } ActionType::UpdateClient => { - // TODO: rename clientId to clientCounter in the model // get action parameters let client_id = state .action @@ -122,13 +121,19 @@ impl ICS02TestExecutor { } } +const TESTS_DIR: &str = "tests/support/model_based"; + #[test] fn main() { - let path = "tests/support/model_based/test.json"; - let test_executor = ICS02TestExecutor::new(); - // we should be able to just return the `Result` once the following issue - // is fixed: https://github.com/rust-lang/rust/issues/43301 - if let Err(e) = modelator::test_driver(test_executor, path) { - panic!("{:?}", e); + let tests = vec!["UpdateOKTest", "UpdateHeightVerificationFailureTest"]; + + for test in tests { + let path = format!("{}/{}.json", TESTS_DIR, test); + let test_executor = ICS02TestExecutor::new(); + // we should be able to just return the `Result` once the following issue + // is fixed: https://github.com/rust-lang/rust/issues/43301 + if let Err(e) = modelator::test_driver(test_executor, path) { + panic!("{:?}", e); + } } } diff --git a/modules/tests/state.rs b/modules/tests/state.rs index a88c303bd7..7b4cfdb06d 100644 --- a/modules/tests/state.rs +++ b/modules/tests/state.rs @@ -31,5 +31,7 @@ pub enum ActionType { pub enum ActionOutcome { Null, CreateOK, + UpdateOK, + UpdateClientNotFound, UpdateHeightVerificationFailure, } diff --git a/modules/tests/support/model_based/.gitignore b/modules/tests/support/model_based/.gitignore index 46e548cea0..a8ddd534bf 100644 --- a/modules/tests/support/model_based/.gitignore +++ b/modules/tests/support/model_based/.gitignore @@ -5,3 +5,5 @@ detailed.log bfs.csv log0.smt profile-rules.txt +counterexample.json +counterexample.tla diff --git a/modules/tests/support/model_based/ICS02.cfg b/modules/tests/support/model_based/ICS02.cfg index ecddb236a6..c23bd845b2 100644 --- a/modules/tests/support/model_based/ICS02.cfg +++ b/modules/tests/support/model_based/ICS02.cfg @@ -1,5 +1,5 @@ CONSTANTS - MaxClientId = 5 + MaxClients = 5 MaxHeight = 5 INIT Init diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index a7be842874..5dd5690c50 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -2,9 +2,9 @@ EXTENDS Integers, FiniteSets -\* max client identifier -CONSTANT MaxClientId -ASSUME MaxClientId > 0 +\* max number of client to be created +CONSTANT MaxClients +ASSUME MaxClients > 0 \* max height which clients can reach CONSTANT MaxHeight ASSUME MaxHeight > 0 @@ -12,7 +12,7 @@ ASSUME MaxHeight > 0 \* set of client data VARIABLE clients \* counter used to generate client identifiers -VARIABLE nextClientId +VARIABLE clientIdCounter \* last action performed VARIABLE action \* string with the outcome of the last operation @@ -31,7 +31,7 @@ AsAction(a) == a <: ActionType (****************** END OF TYPE ANNOTATIONS FOR APALACHE ********************) \* set of possible client identifiers -ClientIds == 1..MaxClientId +ClientIds == 0..(MaxClients - 1) \* set of possible heights Heights == 1..MaxHeight \* if a client has a null height then the client does not exist @@ -67,16 +67,16 @@ SetClientHeight(clientId, clientHeight) == CreateClient(clientHeight) == \* check if the client exists (it shouldn't) - IF ClientExists(nextClientId) THEN + IF ClientExists(clientIdCounter) THEN \* if the client to be created already exists, \* then there's an error in the model /\ actionOutcome' = "ModelError" - /\ UNCHANGED <> + /\ UNCHANGED <> ELSE \* set the new client's height to `clientHeight` - /\ clients' = SetClientHeight(nextClientId, clientHeight) - \* update `nextClientId` - /\ nextClientId' = nextClientId + 1 + /\ clients' = SetClientHeight(clientIdCounter, clientHeight) + \* update `clientIdCounter` + /\ clientIdCounter' = clientIdCounter + 1 \* set `outcome` /\ actionOutcome' = "CreateOK" @@ -90,51 +90,51 @@ UpdateClient(clientId, clientHeight) == /\ clients' = SetClientHeight(clientId, clientHeight) \* set outcome /\ actionOutcome' = "UpdateOK" - /\ UNCHANGED <> + /\ UNCHANGED <> ELSE /\ actionOutcome' = "UpdateHeightVerificationFailure" - /\ UNCHANGED <> + /\ UNCHANGED <> ELSE \* if the client does not exist, then return an error /\ actionOutcome' = "UpdateClientNotFound" - /\ UNCHANGED <> + /\ UNCHANGED <> CreateClientAction == - \* only create client if the model constant `MaxClientId` allows it - /\ nextClientId < MaxClientId + \* only create client if the model constant `MaxClients` allows it + /\ clientIdCounter \in ClientIds \* select a height for the client to be created at /\ \E clientHeight \in Heights: + /\ CreateClient(clientHeight) /\ action' = AsAction([type |-> "CreateClient", height |-> clientHeight]) - /\ CreateClient(clientHeight) UpdateClientAction == \* select a client to be updated (which may not exist) \E clientId \in ClientIds: \* select a height for the client to be updated \E clientHeight \in Heights: + /\ UpdateClient(clientId, clientHeight) /\ action' = AsAction([type |-> "UpdateClient", clientId |-> clientId, height |-> clientHeight]) - /\ UpdateClient(clientId, clientHeight) Init == /\ clients = [clientId \in ClientIds |-> NullHeight] - /\ nextClientId = 1 + /\ clientIdCounter = 0 /\ action = AsAction([type |-> "Null"]) /\ actionOutcome = "Null" Next == \/ CreateClientAction \/ UpdateClientAction - \/ UNCHANGED <> + \/ UNCHANGED <> (*************************************************************************** Invariants ***************************************************************************) TypeOK == - /\ nextClientId \in ClientIds \union {MaxClientId + 1} + /\ clientIdCounter \in 0..MaxClients /\ clients \in [ClientIds -> Heights \union {NullHeight}] /\ action \in Actions /\ actionOutcome \in ActionOutcomes diff --git a/modules/tests/support/model_based/ICS02Tests.cfg b/modules/tests/support/model_based/ICS02Tests.cfg index 3cad4d28ed..79b45ebaf0 100644 --- a/modules/tests/support/model_based/ICS02Tests.cfg +++ b/modules/tests/support/model_based/ICS02Tests.cfg @@ -1,5 +1,5 @@ CONSTANTS - MaxClientId = 5 + MaxClients = 5 MaxHeight = 5 INIT Init diff --git a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json index f826069b6e..430dbc02bb 100644 --- a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json +++ b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json @@ -14,7 +14,7 @@ }, { "action": { - "clientId": 1, + "clientId": 0, "height": 1, "type": "UpdateClient" }, diff --git a/modules/tests/support/model_based/UpdateOKTest.json b/modules/tests/support/model_based/UpdateOKTest.json index 06a9531db5..13a5f1ebab 100644 --- a/modules/tests/support/model_based/UpdateOKTest.json +++ b/modules/tests/support/model_based/UpdateOKTest.json @@ -14,7 +14,7 @@ }, { "action": { - "clientId": 1, + "clientId": 0, "height": 2, "type": "UpdateClient" }, From cd0d0a6ac976f443f19ac13c07651b7a39017843 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 22:40:33 +0100 Subject: [PATCH 006/104] Check for errors in MockContext.deliver --- modules/tests/model_based.rs | 54 ++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 6ed8d8c7cf..1288b49a72 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -7,6 +7,7 @@ use ibc::ics02_client::client_type::ClientType; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; +use ibc::ics18_relayer::error::Kind as ICS18ErrorKind; use ibc::ics24_host::identifier::ChainId; use ibc::ics24_host::identifier::ClientId; use ibc::ics26_routing::msgs::ICS26Envelope; @@ -47,14 +48,22 @@ impl ICS02TestExecutor { impl modelator::TestExecutor for ICS02TestExecutor { fn check_initial_state(&mut self, state: State) -> bool { - let type_is_null = state.action.action_type == ActionType::Null; - let outcome_is_null = state.action_outcome == ActionOutcome::Null; - type_is_null && outcome_is_null + assert_eq!( + state.action.action_type, + ActionType::Null, + "unexpected action type" + ); + assert_eq!( + state.action_outcome, + ActionOutcome::Null, + "unexpected action outcome" + ); + true } fn check_next_state(&mut self, state: State) -> bool { match state.action.action_type { - ActionType::Null => panic!("next state action type cannot be null"), + ActionType::Null => panic!("unexpected action type"), ActionType::CreateClient => { // get action parameters let height = state @@ -70,13 +79,23 @@ impl modelator::TestExecutor for ICS02TestExecutor { // create dummy signer let signer = self.dummy_signer(); - // create ICS26 message + // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { client_state, consensus_state, signer, })); - self.ctx.deliver(msg).unwrap(); + let result = self.ctx.deliver(msg); + + // check the expected outcome: client create always succeeds + assert_eq!( + state.action_outcome, + ActionOutcome::CreateOK, + "unexpected action outcome" + ); + if let Err(e) = result { + panic!("{:?}", e); + } true } ActionType::UpdateClient => { @@ -98,13 +117,32 @@ impl modelator::TestExecutor for ICS02TestExecutor { // create dummy signer let signer = self.dummy_signer(); - // create ICS26 message + // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { client_id, header, signer, })); - self.ctx.deliver(msg).unwrap(); + let result = self.ctx.deliver(msg); + + match state.action_outcome { + ActionOutcome::Null | ActionOutcome::CreateOK => { + panic!("unexpected action outcome") + } + ActionOutcome::UpdateOK => { + // check that there were no errors + assert!(result.is_ok(), "UpdateOK outcome expected"); + } + ActionOutcome::UpdateClientNotFound => { + assert!(result.is_err(), "UpdateClientNotFound outcome expected"); + todo!() + } + ActionOutcome::UpdateHeightVerificationFailure => { + let error = + result.expect_err("UpdateHeightVerificationFailure outcome expected"); + assert!(matches!(error.kind(), ICS18ErrorKind::TransactionFailed)); + } + } true } } From 02c020b03e93b9f4e908a2ac2e050ab5bf740b08 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 23:07:17 +0100 Subject: [PATCH 007/104] Handle errors in MBT tests --- modules/tests/model_based.rs | 46 ++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 1288b49a72..bc9f2ef2ac 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -4,12 +4,14 @@ mod state; use ibc::ics02_client::client_def::AnyHeader; use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use ibc::ics02_client::client_type::ClientType; +use ibc::ics02_client::error::{Error as ICS02Error, Kind as ICS02ErrorKind}; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; -use ibc::ics18_relayer::error::Kind as ICS18ErrorKind; +use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; use ibc::ics24_host::identifier::ChainId; use ibc::ics24_host::identifier::ClientId; +use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; use ibc::ics26_routing::msgs::ICS26Envelope; use ibc::mock::client_state::{MockClientState, MockConsensusState}; use ibc::mock::context::MockContext; @@ -17,6 +19,7 @@ use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; use ibc::Height; use state::{ActionOutcome, ActionType, State}; +use std::error::Error; use std::fmt::Debug; use tendermint::account::Id as AccountId; @@ -119,7 +122,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { - client_id, + client_id: client_id.clone(), header, signer, })); @@ -134,13 +137,18 @@ impl modelator::TestExecutor for ICS02TestExecutor { assert!(result.is_ok(), "UpdateOK outcome expected"); } ActionOutcome::UpdateClientNotFound => { - assert!(result.is_err(), "UpdateClientNotFound outcome expected"); - todo!() + let handler_error_kind = Self::extract_ics02_handler_error_kind(result); + assert!(matches!( + handler_error_kind, + ICS02ErrorKind::ClientNotFound(id) if id == client_id + )); } ActionOutcome::UpdateHeightVerificationFailure => { - let error = - result.expect_err("UpdateHeightVerificationFailure outcome expected"); - assert!(matches!(error.kind(), ICS18ErrorKind::TransactionFailed)); + let handler_error_kind = Self::extract_ics02_handler_error_kind(result); + assert!(matches!( + handler_error_kind, + ICS02ErrorKind::HeaderVerificationFailure + )); } } true @@ -157,6 +165,30 @@ impl ICS02TestExecutor { fn mock_header(&self, height: u64) -> MockHeader { MockHeader(Height::new(self.version, height)) } + + fn extract_ics02_handler_error_kind(result: Result<(), ICS18Error>) -> ICS02ErrorKind { + let ics18_error = result.expect_err("ICS18 error expected"); + assert!(matches!( + ics18_error.kind(), + ICS18ErrorKind::TransactionFailed + )); + let ics26_error = ics18_error + .source() + .expect("expected source in ICS18 error") + .downcast_ref::() + .expect("ICS18 source should be an ICS26 error"); + assert!(matches!( + ics26_error.kind(), + ICS26ErrorKind::HandlerRaisedError, + )); + ics26_error + .source() + .expect("expected source in ICS26 error") + .downcast_ref::() + .expect("ICS26 source should be an ICS02 error") + .kind() + .clone() + } } const TESTS_DIR: &str = "tests/support/model_based"; From a5d06c53dccf822a5576a1248f1d09a7b6ece1eb Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 23:09:31 +0100 Subject: [PATCH 008/104] Remove SyntheticTendermint mock context --- modules/tests/model_based.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index bc9f2ef2ac..89bc4c020b 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -32,19 +32,15 @@ struct ICS02TestExecutor { impl ICS02TestExecutor { fn new() -> Self { let version = 1; + let max_history_size = 1; + let initial_height = 0; let ctx = MockContext::new( ChainId::new("mock".to_string(), version), HostType::Mock, - 1, - Height::new(version, 0), + // HostType::SyntheticTendermint, + max_history_size, + Height::new(version, initial_height), ); - // let ctx = MockContext::new( - // ChainId::new("mock".to_string(), cv), - // HostType::SyntheticTendermint, - // 1, - // Height::new(cv, 0), - // ); - Self { version, ctx } } } From 356c6d231c2506ca61d3075336c6fccf8fcc3e31 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 2 Feb 2021 23:18:31 +0100 Subject: [PATCH 009/104] More idiomatic check_next_state --- modules/tests/model_based.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 89bc4c020b..bc672d9b03 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -68,7 +68,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { let height = state .action .height - .expect("update client action should have a height"); + .expect("create client action should have a height"); // create client and consensus state from parameters let client_state = AnyClientState::Mock(MockClientState(self.mock_header(height))); @@ -92,10 +92,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { ActionOutcome::CreateOK, "unexpected action outcome" ); - if let Err(e) = result { - panic!("{:?}", e); - } - true + result.is_ok() } ActionType::UpdateClient => { // get action parameters @@ -130,24 +127,20 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionOutcome::UpdateOK => { // check that there were no errors - assert!(result.is_ok(), "UpdateOK outcome expected"); + result.is_ok() } ActionOutcome::UpdateClientNotFound => { - let handler_error_kind = Self::extract_ics02_handler_error_kind(result); - assert!(matches!( + let handler_error_kind = self.extract_ics02_handler_error_kind(result); + matches!( handler_error_kind, ICS02ErrorKind::ClientNotFound(id) if id == client_id - )); + ) } ActionOutcome::UpdateHeightVerificationFailure => { - let handler_error_kind = Self::extract_ics02_handler_error_kind(result); - assert!(matches!( - handler_error_kind, - ICS02ErrorKind::HeaderVerificationFailure - )); + let handler_error_kind = self.extract_ics02_handler_error_kind(result); + handler_error_kind == ICS02ErrorKind::HeaderVerificationFailure } } - true } } } @@ -162,7 +155,7 @@ impl ICS02TestExecutor { MockHeader(Height::new(self.version, height)) } - fn extract_ics02_handler_error_kind(result: Result<(), ICS18Error>) -> ICS02ErrorKind { + fn extract_ics02_handler_error_kind(&self, result: Result<(), ICS18Error>) -> ICS02ErrorKind { let ics18_error = result.expect_err("ICS18 error expected"); assert!(matches!( ics18_error.kind(), From 6ab8611cf6c34485a8a9cae46196afc9c60a2a97 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 10:21:33 +0100 Subject: [PATCH 010/104] Buffered file reads --- modules/tests/modelator.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index 8663e205e8..d395119e20 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -2,6 +2,7 @@ use eyre::{eyre, Context, Result}; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::fs::File; +use std::io::BufReader; use std::path::Path; pub trait TestExecutor { @@ -16,13 +17,18 @@ where S: DeserializeOwned + Debug + Clone, P: AsRef, { - let reader = File::open(path.as_ref()) + // open test file + let file = File::open(path.as_ref()) .wrap_err_with(|| format!("test file {:?} not found.", path.as_ref()))?; + let reader = BufReader::new(file); + + // parse test file let states: Vec = serde_json::de::from_reader(reader) .wrap_err_with(|| format!("test file {:?} could not be deserialized", path.as_ref()))?; let mut states = states.into_iter(); + // check the initial state if let Some(state) = states.next() { if !executor.check_initial_state(state.clone()) { return Err(eyre!("check failed on initial state:\n{:#?}", state)); @@ -32,6 +38,7 @@ where return Ok(()); } + // check all the remaining states for state in states { if !executor.check_next_state(state.clone()) { return Err(eyre!( From 490d77bd5a4218865398deef1024a2539e90de00 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 16:23:58 +0100 Subject: [PATCH 011/104] Make extract_handler_error_kind generic over the IBC handler --- modules/tests/model_based.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index bc672d9b03..1ee6408e86 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -4,7 +4,7 @@ mod state; use ibc::ics02_client::client_def::AnyHeader; use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use ibc::ics02_client::client_type::ClientType; -use ibc::ics02_client::error::{Error as ICS02Error, Kind as ICS02ErrorKind}; +use ibc::ics02_client::error::Kind as ICS02ErrorKind; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; @@ -20,7 +20,7 @@ use ibc::mock::host::HostType; use ibc::Height; use state::{ActionOutcome, ActionType, State}; use std::error::Error; -use std::fmt::Debug; +use std::fmt::{Debug, Display}; use tendermint::account::Id as AccountId; #[derive(Debug)] @@ -92,6 +92,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { ActionOutcome::CreateOK, "unexpected action outcome" ); + // the implementaion matches the model if no error occurs result.is_ok() } ActionType::UpdateClient => { @@ -126,18 +127,24 @@ impl modelator::TestExecutor for ICS02TestExecutor { panic!("unexpected action outcome") } ActionOutcome::UpdateOK => { - // check that there were no errors + // the implementaion matches the model if no error occurs result.is_ok() } ActionOutcome::UpdateClientNotFound => { - let handler_error_kind = self.extract_ics02_handler_error_kind(result); + let handler_error_kind = + self.extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome matches!( handler_error_kind, ICS02ErrorKind::ClientNotFound(id) if id == client_id ) } ActionOutcome::UpdateHeightVerificationFailure => { - let handler_error_kind = self.extract_ics02_handler_error_kind(result); + let handler_error_kind = + self.extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome handler_error_kind == ICS02ErrorKind::HeaderVerificationFailure } } @@ -155,7 +162,10 @@ impl ICS02TestExecutor { MockHeader(Height::new(self.version, height)) } - fn extract_ics02_handler_error_kind(&self, result: Result<(), ICS18Error>) -> ICS02ErrorKind { + fn extract_handler_error_kind(&self, result: Result<(), ICS18Error>) -> K + where + K: Clone + Debug + Display + Into + 'static, + { let ics18_error = result.expect_err("ICS18 error expected"); assert!(matches!( ics18_error.kind(), @@ -173,8 +183,8 @@ impl ICS02TestExecutor { ics26_error .source() .expect("expected source in ICS26 error") - .downcast_ref::() - .expect("ICS26 source should be an ICS02 error") + .downcast_ref::>() + .expect("ICS26 source should be an error") .kind() .clone() } From 92b843c64d9660e7408d975222d95590340f0bdb Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 16:44:22 +0100 Subject: [PATCH 012/104] Support multiple chains in MBT --- modules/tests/model_based.rs | 141 ++++++++------- modules/tests/state.rs | 3 + modules/tests/support/model_based/ICS02.cfg | 5 +- modules/tests/support/model_based/ICS02.tla | 164 ++++++++++++------ .../tests/support/model_based/ICS02Tests.cfg | 5 +- .../tests/support/model_based/ICS02Tests.tla | 2 +- modules/tests/support/model_based/Makefile | 6 +- .../UpdateHeightVerificationFailureTest.json | 2 + .../support/model_based/UpdateOKTest.json | 36 ++++ 9 files changed, 240 insertions(+), 124 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 1ee6408e86..fa57b0139a 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -19,29 +19,75 @@ use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; use ibc::Height; use state::{ActionOutcome, ActionType, State}; +use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; use tendermint::account::Id as AccountId; +// all chains use the same version +const VERSION: u64 = 0; + #[derive(Debug)] struct ICS02TestExecutor { - version: u64, - ctx: MockContext, + // mapping from chain identifier to its context + contexts: HashMap, } impl ICS02TestExecutor { fn new() -> Self { - let version = 1; - let max_history_size = 1; - let initial_height = 0; - let ctx = MockContext::new( - ChainId::new("mock".to_string(), version), - HostType::Mock, - // HostType::SyntheticTendermint, - max_history_size, - Height::new(version, initial_height), - ); - Self { version, ctx } + Self { + contexts: Default::default(), + } + } + + /// Find the `MockContext` of a given `chain_id`. + /// If no context is found, a new one is created. + fn get_chain_context_or_init(&mut self, chain_id: String) -> &mut MockContext { + self.contexts.entry(chain_id.clone()).or_insert_with(|| { + let max_history_size = 1; + let initial_height = 0; + MockContext::new( + ChainId::new(chain_id, VERSION), + HostType::Mock, + max_history_size, + Height::new(VERSION, initial_height), + ) + }) + } + + fn dummy_signer() -> AccountId { + AccountId::new([0; 20]) + } + + fn mock_header(height: u64) -> MockHeader { + MockHeader(Height::new(VERSION, height)) + } + + fn extract_handler_error_kind(result: Result<(), ICS18Error>) -> K + where + K: Clone + Debug + Display + Into + 'static, + { + let ics18_error = result.expect_err("ICS18 error expected"); + assert!(matches!( + ics18_error.kind(), + ICS18ErrorKind::TransactionFailed + )); + let ics26_error = ics18_error + .source() + .expect("expected source in ICS18 error") + .downcast_ref::() + .expect("ICS18 source should be an ICS26 error"); + assert!(matches!( + ics26_error.kind(), + ICS26ErrorKind::HandlerRaisedError, + )); + ics26_error + .source() + .expect("expected source in ICS26 error") + .downcast_ref::>() + .expect("ICS26 source should be an error") + .kind() + .clone() } } @@ -65,18 +111,25 @@ impl modelator::TestExecutor for ICS02TestExecutor { ActionType::Null => panic!("unexpected action type"), ActionType::CreateClient => { // get action parameters + let chain_id = state + .action + .chain_id + .expect("create client action should have a chain identifier"); let height = state .action .height .expect("create client action should have a height"); + // get chain's context + let ctx = self.get_chain_context_or_init(chain_id); + // create client and consensus state from parameters - let client_state = AnyClientState::Mock(MockClientState(self.mock_header(height))); + let client_state = AnyClientState::Mock(MockClientState(Self::mock_header(height))); let consensus_state = - AnyConsensusState::Mock(MockConsensusState(self.mock_header(height))); + AnyConsensusState::Mock(MockConsensusState(Self::mock_header(height))); // create dummy signer - let signer = self.dummy_signer(); + let signer = Self::dummy_signer(); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { @@ -84,7 +137,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { consensus_state, signer, })); - let result = self.ctx.deliver(msg); + let result = ctx.deliver(msg); // check the expected outcome: client create always succeeds assert_eq!( @@ -97,6 +150,10 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionType::UpdateClient => { // get action parameters + let chain_id = state + .action + .chain_id + .expect("update client action should have a chain identifier"); let client_id = state .action .client_id @@ -106,13 +163,16 @@ impl modelator::TestExecutor for ICS02TestExecutor { .height .expect("update client action should have a height"); + // get chain's context + let ctx = self.get_chain_context_or_init(chain_id); + // create client id and header from action parameters let client_id = ClientId::new(ClientType::Mock, client_id) .expect("it should be possible to create the client identifier"); - let header = AnyHeader::Mock(self.mock_header(height)); + let header = AnyHeader::Mock(Self::mock_header(height)); // create dummy signer - let signer = self.dummy_signer(); + let signer = Self::dummy_signer(); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { @@ -120,7 +180,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { header, signer, })); - let result = self.ctx.deliver(msg); + let result = ctx.deliver(msg); match state.action_outcome { ActionOutcome::Null | ActionOutcome::CreateOK => { @@ -132,7 +192,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionOutcome::UpdateClientNotFound => { let handler_error_kind = - self.extract_handler_error_kind::(result); + Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an // error matching the expected outcome matches!( @@ -142,7 +202,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionOutcome::UpdateHeightVerificationFailure => { let handler_error_kind = - self.extract_handler_error_kind::(result); + Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an // error matching the expected outcome handler_error_kind == ICS02ErrorKind::HeaderVerificationFailure @@ -153,43 +213,6 @@ impl modelator::TestExecutor for ICS02TestExecutor { } } -impl ICS02TestExecutor { - fn dummy_signer(&self) -> AccountId { - AccountId::new([0; 20]) - } - - fn mock_header(&self, height: u64) -> MockHeader { - MockHeader(Height::new(self.version, height)) - } - - fn extract_handler_error_kind(&self, result: Result<(), ICS18Error>) -> K - where - K: Clone + Debug + Display + Into + 'static, - { - let ics18_error = result.expect_err("ICS18 error expected"); - assert!(matches!( - ics18_error.kind(), - ICS18ErrorKind::TransactionFailed - )); - let ics26_error = ics18_error - .source() - .expect("expected source in ICS18 error") - .downcast_ref::() - .expect("ICS18 source should be an ICS26 error"); - assert!(matches!( - ics26_error.kind(), - ICS26ErrorKind::HandlerRaisedError, - )); - ics26_error - .source() - .expect("expected source in ICS26 error") - .downcast_ref::>() - .expect("ICS26 source should be an error") - .kind() - .clone() - } -} - const TESTS_DIR: &str = "tests/support/model_based"; #[test] diff --git a/modules/tests/state.rs b/modules/tests/state.rs index 7b4cfdb06d..eff0fd72a4 100644 --- a/modules/tests/state.rs +++ b/modules/tests/state.rs @@ -14,6 +14,9 @@ pub struct Action { #[serde(alias = "type")] pub action_type: ActionType, + #[serde(alias = "chainId")] + pub chain_id: Option, + #[serde(alias = "clientId")] pub client_id: Option, diff --git a/modules/tests/support/model_based/ICS02.cfg b/modules/tests/support/model_based/ICS02.cfg index c23bd845b2..5445bf7d9b 100644 --- a/modules/tests/support/model_based/ICS02.cfg +++ b/modules/tests/support/model_based/ICS02.cfg @@ -1,6 +1,7 @@ CONSTANTS - MaxClients = 5 - MaxHeight = 5 + ChainIds = {"chain-A", "chain-B"} + MaxClientsPerChain = 4 + MaxClientHeight = 4 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 5dd5690c50..756d11cb76 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -2,17 +2,17 @@ EXTENDS Integers, FiniteSets +\* ids of existing chains +CONSTANT ChainIds \* max number of client to be created -CONSTANT MaxClients -ASSUME MaxClients > 0 +CONSTANT MaxClientsPerChain +ASSUME MaxClientsPerChain > 0 \* max height which clients can reach -CONSTANT MaxHeight -ASSUME MaxHeight > 0 +CONSTANT MaxClientHeight +ASSUME MaxClientHeight > 0 -\* set of client data -VARIABLE clients -\* counter used to generate client identifiers -VARIABLE clientIdCounter +\* mapping from chain id to its data +VARIABLE chains \* last action performed VARIABLE action \* string with the outcome of the last operation @@ -24,6 +24,7 @@ a <: b == a ActionType == [ type |-> STRING, + chainId |-> STRING, clientId |-> Int, height |-> Int ] @@ -31,111 +32,160 @@ AsAction(a) == a <: ActionType (****************** END OF TYPE ANNOTATIONS FOR APALACHE ********************) \* set of possible client identifiers -ClientIds == 0..(MaxClients - 1) -\* set of possible heights -Heights == 1..MaxHeight +ClientIds == 0..(MaxClientsPerChain - 1) +\* set of possible client heights +ClientHeights == 1..MaxClientHeight \* if a client has a null height then the client does not exist NullHeight == 0 + +Clients == [ + ClientIds -> ClientHeights \union {NullHeight} +] +Chain == [ + clientIdCounter: 0..MaxClientsPerChain, + clients: Clients +] + \* set of possible actions NullActions == [ type: {"Null"} ] <: {ActionType} CreateClientActions == [ type: {"CreateClient"}, - height: Heights + chainId: ChainIds, + height: ClientHeights ] <: {ActionType} UpdateClientActions == [ type: {"UpdateClient"}, + chainId: ChainIds, clientId: ClientIds, - height: Heights + height: ClientHeights ] <: {ActionType} -Actions == NullActions \union CreateClientActions \union UpdateClientActions -\* set of possible outcomes -ActionOutcomes == {"Null", "CreateOK", "UpdateOK", "UpdateClientNotFound", "UpdateHeightVerificationFailure", "ModelError"} - +Actions == + NullActions \union + CreateClientActions \union + UpdateClientActions + +\* set of possible action outcomes +ActionOutcomes == { + "Null", + "CreateOK", + "UpdateOK", + "UpdateClientNotFound", + "UpdateHeightVerificationFailure", + "ModelError" +} (*************************************************************************** Specification ***************************************************************************) -\* check if a client exists -ClientExists(clientId) == - clients[clientId] /= NullHeight +\* retrieves `clientId`'s height +GetClientHeight(clients, clientId) == + clients[clientId] -SetClientHeight(clientId, clientHeight) == +\* check if a `clientId` exists +ClientExists(clients, clientId) == + GetClientHeight(clients, clientId) /= NullHeight + +\* update the heigth of `clientId` to `clientHeight` +SetClientHeight(clients, clientId, clientHeight) == [clients EXCEPT ![clientId] = clientHeight] -CreateClient(clientHeight) == +CreateClient(chainId, clientHeight) == + LET clients == chains[chainId].clients + clientIdCounter == chains[chainId].clientIdCounter IN \* check if the client exists (it shouldn't) - IF ClientExists(clientIdCounter) THEN + IF ClientExists(clients, clientIdCounter) THEN \* if the client to be created already exists, \* then there's an error in the model /\ actionOutcome' = "ModelError" - /\ UNCHANGED <> + /\ UNCHANGED <> ELSE - \* set the new client's height to `clientHeight` - /\ clients' = SetClientHeight(clientIdCounter, clientHeight) - \* update `clientIdCounter` - /\ clientIdCounter' = clientIdCounter + 1 + LET chain == [ + \* set the new client's height to `clientHeight` + clients |-> SetClientHeight(clients, clientIdCounter, clientHeight), + \* update `clientIdCounter` + clientIdCounter |-> clientIdCounter + 1 + ] IN + \* update `chains` + /\ chains' = [chains EXCEPT ![chainId] = chain] \* set `outcome` /\ actionOutcome' = "CreateOK" -UpdateClient(clientId, clientHeight) == +UpdateClient(chainId, clientId, clientHeight) == + LET clients == chains[chainId].clients + clientIdCounter == chains[chainId].clientIdCounter IN \* check if the client exists - IF ClientExists(clientId) THEN + IF ClientExists(clients, clientId) THEN \* if the client exists, check its height - IF clients[clientId] < clientHeight THEN + IF GetClientHeight(clients, clientId) < clientHeight THEN \* if its height is lower than the one being updated to \* then, update the client - /\ clients' = SetClientHeight(clientId, clientHeight) + LET chain == [ + \* set the client's height to `clientHeight` + clients |-> SetClientHeight(clients, clientId, clientHeight), + \* keep `clientIdCounter` + clientIdCounter |-> clientIdCounter + ] IN + \* update `chains` + /\ chains' = [chains EXCEPT ![chainId] = chain] \* set outcome /\ actionOutcome' = "UpdateOK" - /\ UNCHANGED <> ELSE /\ actionOutcome' = "UpdateHeightVerificationFailure" - /\ UNCHANGED <> + /\ UNCHANGED <> ELSE \* if the client does not exist, then return an error /\ actionOutcome' = "UpdateClientNotFound" - /\ UNCHANGED <> + /\ UNCHANGED <> CreateClientAction == - \* only create client if the model constant `MaxClients` allows it - /\ clientIdCounter \in ClientIds - \* select a height for the client to be created at - /\ \E clientHeight \in Heights: - /\ CreateClient(clientHeight) - /\ action' = AsAction([type |-> "CreateClient", - height |-> clientHeight]) - -UpdateClientAction == - \* select a client to be updated (which may not exist) - \E clientId \in ClientIds: - \* select a height for the client to be updated - \E clientHeight \in Heights: - /\ UpdateClient(clientId, clientHeight) - /\ action' = AsAction([type |-> "UpdateClient", - clientId |-> clientId, + \* select a chain + \E chainId \in ChainIds: + \* only create client if the model constant `MaxClientsPerChain` allows it + /\ chains[chainId].clientIdCounter \in ClientIds + \* select a height for the client to be created at + /\ \E clientHeight \in ClientHeights: + /\ CreateClient(chainId, clientHeight) + /\ action' = AsAction([type |-> "CreateClient", + chainId |-> chainId, height |-> clientHeight]) - Init == - /\ clients = [clientId \in ClientIds |-> NullHeight] - /\ clientIdCounter = 0 +UpdateClientAction == + \* select a chain + \E chainId \in ChainIds: + \* select a client to be updated (which may not exist) + \E clientId \in ClientIds: + \* select a height for the client to be updated + \E clientHeight \in ClientHeights: + /\ UpdateClient(chainId, clientId, clientHeight) + /\ action' = AsAction([type |-> "UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + height |-> clientHeight]) + +Init == + \* create an empty chain + LET emptyChain == [ + clients |-> [clientId \in ClientIds |-> NullHeight], + clientIdCounter |-> 0 + ] IN + /\ chains = [chainId \in ChainIds |-> emptyChain] /\ action = AsAction([type |-> "Null"]) /\ actionOutcome = "Null" Next == \/ CreateClientAction \/ UpdateClientAction - \/ UNCHANGED <> + \/ UNCHANGED <> (*************************************************************************** Invariants ***************************************************************************) TypeOK == - /\ clientIdCounter \in 0..MaxClients - /\ clients \in [ClientIds -> Heights \union {NullHeight}] + /\ chains \in [ChainIds -> Chain] /\ action \in Actions /\ actionOutcome \in ActionOutcomes diff --git a/modules/tests/support/model_based/ICS02Tests.cfg b/modules/tests/support/model_based/ICS02Tests.cfg index 79b45ebaf0..0950dd0e71 100644 --- a/modules/tests/support/model_based/ICS02Tests.cfg +++ b/modules/tests/support/model_based/ICS02Tests.cfg @@ -1,6 +1,7 @@ CONSTANTS - MaxClients = 5 - MaxHeight = 5 + ChainIds = {"chain-A", "chain-B"} + MaxClientsPerChain = 4 + MaxClientHeight = 4 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/ICS02Tests.tla b/modules/tests/support/model_based/ICS02Tests.tla index 3664de67ab..f700a50624 100644 --- a/modules/tests/support/model_based/ICS02Tests.tla +++ b/modules/tests/support/model_based/ICS02Tests.tla @@ -1,6 +1,6 @@ ------------------------- MODULE ICS02Tests --------------------------- -EXTENDS ICS02 +EXTENDS IBC CreateOK == /\ actionOutcome = "CreateOK" diff --git a/modules/tests/support/model_based/Makefile b/modules/tests/support/model_based/Makefile index 9e5318a5f2..21e2f7c8a3 100644 --- a/modules/tests/support/model_based/Makefile +++ b/modules/tests/support/model_based/Makefile @@ -1,6 +1,6 @@ +check: + apalache-mc check --inv=ModelNeverErrors ICS02.tla + test: apalache-mc check ICS02Tests.tla -check: - apalache-mc check ICS02.tla - diff --git a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json index 430dbc02bb..0ae9ca9289 100644 --- a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json +++ b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json @@ -7,6 +7,7 @@ }, { "action": { + "chainId": "chain-B", "height": 1, "type": "CreateClient" }, @@ -14,6 +15,7 @@ }, { "action": { + "chainId": "chain-B", "clientId": 0, "height": 1, "type": "UpdateClient" diff --git a/modules/tests/support/model_based/UpdateOKTest.json b/modules/tests/support/model_based/UpdateOKTest.json index 13a5f1ebab..a3d4867b14 100644 --- a/modules/tests/support/model_based/UpdateOKTest.json +++ b/modules/tests/support/model_based/UpdateOKTest.json @@ -7,6 +7,7 @@ }, { "action": { + "chainId": "chain-B", "height": 1, "type": "CreateClient" }, @@ -14,10 +15,45 @@ }, { "action": { + "chainId": "chain-B", "clientId": 0, "height": 2, "type": "UpdateClient" }, "actionOutcome": "UpdateOK" + }, + { + "action": { + "chainId": "chain-A", + "height": 1, + "type": "CreateClient" + }, + "actionOutcome": "CreateOK" + }, + { + "action": { + "chainId": "chain-A", + "clientId": 0, + "height": 2, + "type": "UpdateClient" + }, + "actionOutcome": "UpdateOK" + }, + { + "action": { + "chainId": "chain-A", + "height": 1, + "type": "CreateClient" + }, + "actionOutcome": "CreateOK" + }, + { + "action": { + "chainId": "chain-A", + "clientId": 1, + "height": 2, + "type": "UpdateClient" + }, + "actionOutcome": "UpdateOK" } ] \ No newline at end of file From d57cf4119a9dbfe5260ef7c1afc212bc5c305458 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 16:48:31 +0100 Subject: [PATCH 013/104] Make eyre a dev-dependency --- modules/Cargo.toml | 3 +-- modules/src/ics02_client/handler/update_client.rs | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/Cargo.toml b/modules/Cargo.toml index 00c4a51ae8..ff08417d61 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -37,8 +37,6 @@ dyn-clonable = "0.9.0" regex = "1" bech32 = "0.7.2" -eyre = "0.6.5" - [dependencies.tendermint] version = "=0.18.0" @@ -54,6 +52,7 @@ version = "=0.18.0" optional = true [dev-dependencies] +eyre = "0.6.5" tokio = { version = "1.0", features = ["macros"] } subtle-encoding = { version = "0.5" } tendermint-testgen = { version = "=0.18.0" } # Needed for generating (synthetic) light blocks. diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index 56f3062456..d09d6c0d13 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -37,6 +37,8 @@ pub fn process( .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; let client_def = AnyClient::from_client_type(client_type); + // ClientType ClientState ConsensusState + // X X X // Read client state from the host chain store. let client_state = ctx From f4dbe00b98b105480de3eb148beb98758747b264 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 16:53:55 +0100 Subject: [PATCH 014/104] s/ICS0/IBC on TLA files --- modules/tests/support/model_based/{ICS02.cfg => IBC.cfg} | 0 modules/tests/support/model_based/{ICS02.tla => IBC.tla} | 2 +- .../support/model_based/{ICS02Tests.cfg => IBCTests.cfg} | 0 .../support/model_based/{ICS02Tests.tla => IBCTests.tla} | 2 +- modules/tests/support/model_based/Makefile | 5 ++--- 5 files changed, 4 insertions(+), 5 deletions(-) rename modules/tests/support/model_based/{ICS02.cfg => IBC.cfg} (100%) rename modules/tests/support/model_based/{ICS02.tla => IBC.tla} (98%) rename modules/tests/support/model_based/{ICS02Tests.cfg => IBCTests.cfg} (100%) rename modules/tests/support/model_based/{ICS02Tests.tla => IBCTests.tla} (87%) diff --git a/modules/tests/support/model_based/ICS02.cfg b/modules/tests/support/model_based/IBC.cfg similarity index 100% rename from modules/tests/support/model_based/ICS02.cfg rename to modules/tests/support/model_based/IBC.cfg diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/IBC.tla similarity index 98% rename from modules/tests/support/model_based/ICS02.tla rename to modules/tests/support/model_based/IBC.tla index 756d11cb76..81b9df6401 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,4 +1,4 @@ ---------------------------- MODULE ICS02 ---------------------------- +--------------------------- MODULE IBC ---------------------------- EXTENDS Integers, FiniteSets diff --git a/modules/tests/support/model_based/ICS02Tests.cfg b/modules/tests/support/model_based/IBCTests.cfg similarity index 100% rename from modules/tests/support/model_based/ICS02Tests.cfg rename to modules/tests/support/model_based/IBCTests.cfg diff --git a/modules/tests/support/model_based/ICS02Tests.tla b/modules/tests/support/model_based/IBCTests.tla similarity index 87% rename from modules/tests/support/model_based/ICS02Tests.tla rename to modules/tests/support/model_based/IBCTests.tla index f700a50624..f24eb10cc2 100644 --- a/modules/tests/support/model_based/ICS02Tests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -1,4 +1,4 @@ -------------------------- MODULE ICS02Tests --------------------------- +------------------------- MODULE IBCTests --------------------------- EXTENDS IBC diff --git a/modules/tests/support/model_based/Makefile b/modules/tests/support/model_based/Makefile index 21e2f7c8a3..e0cdfbb248 100644 --- a/modules/tests/support/model_based/Makefile +++ b/modules/tests/support/model_based/Makefile @@ -1,6 +1,5 @@ check: - apalache-mc check --inv=ModelNeverErrors ICS02.tla + apalache-mc check --inv=ModelNeverErrors IBC.tla test: - apalache-mc check ICS02Tests.tla - + apalache-mc check IBCTests.tla From 20867a5affebaad55d1151de9e479788935e6624 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 18:52:10 +0100 Subject: [PATCH 015/104] Initial support for conn open init --- modules/tests/model_based.rs | 28 ++-- modules/tests/state.rs | 11 +- modules/tests/support/model_based/IBC.cfg | 5 +- modules/tests/support/model_based/IBC.tla | 132 +++++++++++------- .../UpdateHeightVerificationFailureTest.json | 4 +- .../support/model_based/UpdateOKTest.json | 12 +- 6 files changed, 116 insertions(+), 76 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index fa57b0139a..51b1f32494 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -140,13 +140,13 @@ impl modelator::TestExecutor for ICS02TestExecutor { let result = ctx.deliver(msg); // check the expected outcome: client create always succeeds - assert_eq!( - state.action_outcome, - ActionOutcome::CreateOK, - "unexpected action outcome" - ); - // the implementaion matches the model if no error occurs - result.is_ok() + match state.action_outcome { + ActionOutcome::ICS02OK => { + // the implementaion matches the model if no error occurs + result.is_ok() + } + action => panic!("unexpected action outcome {:?}", action), + } } ActionType::UpdateClient => { // get action parameters @@ -182,15 +182,13 @@ impl modelator::TestExecutor for ICS02TestExecutor { })); let result = ctx.deliver(msg); + // check the expected outcome match state.action_outcome { - ActionOutcome::Null | ActionOutcome::CreateOK => { - panic!("unexpected action outcome") - } - ActionOutcome::UpdateOK => { + ActionOutcome::ICS02OK => { // the implementaion matches the model if no error occurs result.is_ok() } - ActionOutcome::UpdateClientNotFound => { + ActionOutcome::ICS02ClientNotFound => { let handler_error_kind = Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an @@ -200,15 +198,19 @@ impl modelator::TestExecutor for ICS02TestExecutor { ICS02ErrorKind::ClientNotFound(id) if id == client_id ) } - ActionOutcome::UpdateHeightVerificationFailure => { + ActionOutcome::ICS02HeaderVerificationFailure => { let handler_error_kind = Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an // error matching the expected outcome handler_error_kind == ICS02ErrorKind::HeaderVerificationFailure } + action => panic!("unexpected action outcome {:?}", action), } } + ActionType::ConnectionOpenInit => { + todo!() + } } } } diff --git a/modules/tests/state.rs b/modules/tests/state.rs index eff0fd72a4..82e9255fd3 100644 --- a/modules/tests/state.rs +++ b/modules/tests/state.rs @@ -28,13 +28,16 @@ pub enum ActionType { Null, CreateClient, UpdateClient, + ConnectionOpenInit, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionOutcome { Null, - CreateOK, - UpdateOK, - UpdateClientNotFound, - UpdateHeightVerificationFailure, + #[serde(alias = "ICS02_OK")] + ICS02OK, + #[serde(alias = "ICS02_ClientNotFound")] + ICS02ClientNotFound, + #[serde(alias = "ICS02_HeaderVerificationFailure")] + ICS02HeaderVerificationFailure, } diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 5445bf7d9b..75f117802a 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,7 +1,8 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxClientsPerChain = 4 - MaxClientHeight = 4 + MaxClientsPerChain = 2 + MaxClientHeight = 2 + MaxConnectionsPerChain = 2 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 81b9df6401..a854fc5415 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -4,12 +4,15 @@ EXTENDS Integers, FiniteSets \* ids of existing chains CONSTANT ChainIds -\* max number of client to be created +\* max number of client to be created per chain CONSTANT MaxClientsPerChain ASSUME MaxClientsPerChain > 0 \* max height which clients can reach CONSTANT MaxClientHeight ASSUME MaxClientHeight > 0 +\* max number of connections to be created per chain +CONSTANT MaxConnectionsPerChain +ASSUME MaxConnectionsPerChain > 0 \* mapping from chain id to its data VARIABLE chains @@ -25,8 +28,9 @@ a <: b == a ActionType == [ type |-> STRING, chainId |-> STRING, + height |-> Int, clientId |-> Int, - height |-> Int + counterpartyClientId |-> Int ] AsAction(a) == a <: ActionType (****************** END OF TYPE ANNOTATIONS FOR APALACHE ********************) @@ -37,13 +41,18 @@ ClientIds == 0..(MaxClientsPerChain - 1) ClientHeights == 1..MaxClientHeight \* if a client has a null height then the client does not exist NullHeight == 0 +\* set of possible connection identifiers +ConnectionIds == 0..(MaxConnectionsPerChain- 1) +\* mapping from client identifier to its height Clients == [ ClientIds -> ClientHeights \union {NullHeight} ] +\* data kept per chain Chain == [ + clients: Clients, clientIdCounter: 0..MaxClientsPerChain, - clients: Clients + connectionIdCounter: 0..MaxConnectionsPerChain ] \* set of possible actions @@ -61,18 +70,24 @@ UpdateClientActions == [ clientId: ClientIds, height: ClientHeights ] <: {ActionType} +ConnectionOpenInitActions == [ + type: {"ConnectionOpenInit"}, + chainId: ChainIds, + clientId: ClientIds, + counterpartyClientId: ClientIds +] <: {ActionType} Actions == NullActions \union CreateClientActions \union - UpdateClientActions + UpdateClientActions \union + ConnectionOpenInitActions \* set of possible action outcomes ActionOutcomes == { "Null", - "CreateOK", - "UpdateOK", - "UpdateClientNotFound", - "UpdateHeightVerificationFailure", + "ICS02_OK", + "ICS02_ClientNotFound", + "ICS02_HeaderVerificationFailure", "ModelError" } @@ -93,8 +108,9 @@ SetClientHeight(clients, clientId, clientHeight) == [clients EXCEPT ![clientId] = clientHeight] CreateClient(chainId, clientHeight) == - LET clients == chains[chainId].clients - clientIdCounter == chains[chainId].clientIdCounter IN + LET chain == chains[chainId] IN + LET clients == chain.clients IN + LET clientIdCounter == chain.clientIdCounter IN \* check if the client exists (it shouldn't) IF ClientExists(clients, clientIdCounter) THEN \* if the client to be created already exists, @@ -102,74 +118,91 @@ CreateClient(chainId, clientHeight) == /\ actionOutcome' = "ModelError" /\ UNCHANGED <> ELSE - LET chain == [ + LET updatedChain == [chain EXCEPT \* set the new client's height to `clientHeight` - clients |-> SetClientHeight(clients, clientIdCounter, clientHeight), + !.clients = SetClientHeight(clients, clientIdCounter, clientHeight), \* update `clientIdCounter` - clientIdCounter |-> clientIdCounter + 1 + !.clientIdCounter = clientIdCounter + 1 ] IN - \* update `chains` - /\ chains' = [chains EXCEPT ![chainId] = chain] - \* set `outcome` - /\ actionOutcome' = "CreateOK" + \* update `chains` and set the outcome + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ actionOutcome' = "ICS02_OK" UpdateClient(chainId, clientId, clientHeight) == - LET clients == chains[chainId].clients - clientIdCounter == chains[chainId].clientIdCounter IN + LET chain == chains[chainId] IN + LET clients == chain.clients IN \* check if the client exists IF ClientExists(clients, clientId) THEN \* if the client exists, check its height IF GetClientHeight(clients, clientId) < clientHeight THEN - \* if its height is lower than the one being updated to + \* if the client's height is lower than the one being updated to \* then, update the client - LET chain == [ + LET updatedChain == [chain EXCEPT \* set the client's height to `clientHeight` - clients |-> SetClientHeight(clients, clientId, clientHeight), - \* keep `clientIdCounter` - clientIdCounter |-> clientIdCounter + !.clients = SetClientHeight(clients, clientId, clientHeight) ] IN - \* update `chains` - /\ chains' = [chains EXCEPT ![chainId] = chain] - \* set outcome - /\ actionOutcome' = "UpdateOK" + \* update `chains` and set the outcome + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ actionOutcome' = "ICS02_OK" ELSE - /\ actionOutcome' = "UpdateHeightVerificationFailure" + \* if the client's height is at least as high as the one being + \* updated to, then set an error outcome + /\ actionOutcome' = "ICS02_HeaderVerificationFailure" /\ UNCHANGED <> ELSE - \* if the client does not exist, then return an error - /\ actionOutcome' = "UpdateClientNotFound" + \* if the client does not exist, then set an error outcome + /\ actionOutcome' = "ICS02_ClientNotFound" /\ UNCHANGED <> +ConnectionOpenInit(chainId, clientId, counterpartyClientId) == + \* Kind::MissingClient + /\ UNCHANGED <> + /\ UNCHANGED <> + CreateClientAction == - \* select a chain + \* select a chain id \E chainId \in ChainIds: + \* select a height for the client to be created at + \E clientHeight \in ClientHeights: \* only create client if the model constant `MaxClientsPerChain` allows it /\ chains[chainId].clientIdCounter \in ClientIds - \* select a height for the client to be created at - /\ \E clientHeight \in ClientHeights: - /\ CreateClient(chainId, clientHeight) - /\ action' = AsAction([type |-> "CreateClient", - chainId |-> chainId, - height |-> clientHeight]) + /\ CreateClient(chainId, clientHeight) + /\ action' = AsAction([type |-> "CreateClient", + chainId |-> chainId, + height |-> clientHeight]) UpdateClientAction == - \* select a chain + \* select a chain id + \E chainId \in ChainIds: + \* select a client to be updated (which may not exist) + \E clientId \in ClientIds: + \* select a height for the client to be updated + \E clientHeight \in ClientHeights: + /\ UpdateClient(chainId, clientId, clientHeight) + /\ action' = AsAction([type |-> "UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + height |-> clientHeight]) + +ConnectionOpenInitAction == + \* select a chain id \E chainId \in ChainIds: - \* select a client to be updated (which may not exist) - \E clientId \in ClientIds: - \* select a height for the client to be updated - \E clientHeight \in ClientHeights: - /\ UpdateClient(chainId, clientId, clientHeight) - /\ action' = AsAction([type |-> "UpdateClient", - chainId |-> chainId, - clientId |-> clientId, - height |-> clientHeight]) + \* select a client id + \E clientId \in ClientIds: + \* select a couterparty client id + \E counterpartyClientId \in ClientIds: + /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) + /\ action' = AsAction([type |-> "ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId]) Init == \* create an empty chain LET emptyChain == [ clients |-> [clientId \in ClientIds |-> NullHeight], - clientIdCounter |-> 0 + clientIdCounter |-> 0, + connectionIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] /\ action = AsAction([type |-> "Null"]) @@ -178,6 +211,7 @@ Init == Next == \/ CreateClientAction \/ UpdateClientAction + \/ ConnectionOpenInitAction \/ UNCHANGED <> (*************************************************************************** diff --git a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json index 0ae9ca9289..2df6fbdcd2 100644 --- a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json +++ b/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json @@ -11,7 +11,7 @@ "height": 1, "type": "CreateClient" }, - "actionOutcome": "CreateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -20,6 +20,6 @@ "height": 1, "type": "UpdateClient" }, - "actionOutcome": "UpdateHeightVerificationFailure" + "actionOutcome": "ICS02_HeaderVerificationFailure" } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/UpdateOKTest.json b/modules/tests/support/model_based/UpdateOKTest.json index a3d4867b14..1ebc6caf2f 100644 --- a/modules/tests/support/model_based/UpdateOKTest.json +++ b/modules/tests/support/model_based/UpdateOKTest.json @@ -11,7 +11,7 @@ "height": 1, "type": "CreateClient" }, - "actionOutcome": "CreateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -20,7 +20,7 @@ "height": 2, "type": "UpdateClient" }, - "actionOutcome": "UpdateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -28,7 +28,7 @@ "height": 1, "type": "CreateClient" }, - "actionOutcome": "CreateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -37,7 +37,7 @@ "height": 2, "type": "UpdateClient" }, - "actionOutcome": "UpdateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -45,7 +45,7 @@ "height": 1, "type": "CreateClient" }, - "actionOutcome": "CreateOK" + "actionOutcome": "ICS02_OK" }, { "action": { @@ -54,6 +54,6 @@ "height": 2, "type": "UpdateClient" }, - "actionOutcome": "UpdateOK" + "actionOutcome": "ICS02_OK" } ] \ No newline at end of file From e5e2f7be32f5ede174c7412e62f5a26ee0df37f5 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 18:58:16 +0100 Subject: [PATCH 016/104] Start connection and channel identifiers at 0 --- modules/src/ics02_client/handler/update_client.rs | 2 -- modules/src/mock/context.rs | 9 +++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index d09d6c0d13..56f3062456 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -37,8 +37,6 @@ pub fn process( .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; let client_def = AnyClient::from_client_type(client_type); - // ClientType ClientState ConsensusState - // X X X // Read client state from the host chain store. let client_state = ctx diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index c656363513..47319c40c2 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -394,9 +394,9 @@ impl ChannelKeeper for MockContext { fn next_channel_id(&mut self) -> ChannelId { let prefix = ChannelId::default().to_string(); let suffix = self.channel_ids_counter; + let channel_id = ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap(); self.channel_ids_counter += 1; - - ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() + channel_id } fn store_channel( @@ -499,9 +499,10 @@ impl ConnectionKeeper for MockContext { fn next_connection_id(&mut self) -> ConnectionId { let prefix = ConnectionId::default().to_string(); let suffix = self.connection_ids_counter; + let connection_id = + ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap(); self.connection_ids_counter += 1; - - ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() + connection_id } fn store_connection( From b9ca90aa67b12428c1a0f0c3b6769bec2aab0ed3 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 20:24:14 +0100 Subject: [PATCH 017/104] Add conn open init to TLA spec --- modules/tests/support/model_based/IBC.tla | 93 +++++++++++++++++++++-- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index a854fc5415..4a3ef02a97 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -37,21 +37,45 @@ AsAction(a) == a <: ActionType \* set of possible client identifiers ClientIds == 0..(MaxClientsPerChain - 1) +\* if a client identifier is undefined then it is -1 +NullClientId == -1 \* set of possible client heights ClientHeights == 1..MaxClientHeight -\* if a client has a null height then the client does not exist -NullHeight == 0 +\* if a client identifier is undefined then it is -1 +NullHeight == -1 \* set of possible connection identifiers ConnectionIds == 0..(MaxConnectionsPerChain- 1) +\* if a connection identifier is undefined then it is -1 +NullConnectionId == -1 +\* set of possible connection states +ConnectionStates == { + "Uninit", + "Init", + "TryOpen", + "Open" +} \* mapping from client identifier to its height Clients == [ ClientIds -> ClientHeights \union {NullHeight} ] +\* data kept per connection +Connection == [ + state: ConnectionStates, + clientId: ClientIds \union {NullClientId}, + counterpartyClientId: ClientIds \union {NullClientId}, + connectionId: ConnectionIds \union {NullConnectionId}, + counterpartyConnectionId: ConnectionIds \union {NullConnectionId} +] +\* mapping from connection identifier to its data +Connections == [ + ConnectionIds -> Connection +] \* data kept per chain Chain == [ clients: Clients, clientIdCounter: 0..MaxClientsPerChain, + connections: Connections, connectionIdCounter: 0..MaxConnectionsPerChain ] @@ -88,6 +112,8 @@ ActionOutcomes == { "ICS02_OK", "ICS02_ClientNotFound", "ICS02_HeaderVerificationFailure", + "ICS03_OK", + "ICS03_MissingClient", "ModelError" } @@ -107,6 +133,18 @@ ClientExists(clients, clientId) == SetClientHeight(clients, clientId, clientHeight) == [clients EXCEPT ![clientId] = clientHeight] +\* retrieves `connectionId`'s data +GetConnection(connections, connectionId) == + connections[connectionId] + +\* check if a `connectionId` exists +ConnectionExists(connections, connectionId) == + GetConnection(connections, connectionId).state /= "Uninit" + +\* update the `connectionId`'s data +SetConnection(connections, connectionId, connectionData) == + [connections EXCEPT ![connectionId] = connectionData] + CreateClient(chainId, clientHeight) == LET chain == chains[chainId] IN LET clients == chain.clients IN @@ -118,8 +156,9 @@ CreateClient(chainId, clientHeight) == /\ actionOutcome' = "ModelError" /\ UNCHANGED <> ELSE + \* if it doesn't, create it LET updatedChain == [chain EXCEPT - \* set the new client's height to `clientHeight` + \* initialize the client's height to `clientHeight` !.clients = SetClientHeight(clients, clientIdCounter, clientHeight), \* update `clientIdCounter` !.clientIdCounter = clientIdCounter + 1 @@ -155,9 +194,41 @@ UpdateClient(chainId, clientId, clientHeight) == /\ UNCHANGED <> ConnectionOpenInit(chainId, clientId, counterpartyClientId) == - \* Kind::MissingClient - /\ UNCHANGED <> - /\ UNCHANGED <> + LET chain == chains[chainId] IN + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN + \* check if the client exists + IF ClientExists(clients, clientId) THEN + \* if the client exists, + \* then check if the connection exists (it shouldn't) + IF ConnectionExists(connections, connectionIdCounter) THEN + \* if the connection to be created already exists, + \* then there's an error in the model + /\ actionOutcome' = "ModelError" + /\ UNCHANGED <> + ELSE + \* if it doesn't, create it + LET connectionData == [ + state |-> "Init", + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId, + connectionId |-> connectionIdCounter, + counterpartyConnectionId |-> NullConnectionId + ] IN + LET updatedChain == [chain EXCEPT + \* initialize the connection's data + !.connections = SetConnection(connections, connectionIdCounter, connectionData), + \* update `clientIdCounter` + !.connectionIdCounter = connectionIdCounter + 1 + ] IN + \* update `chains` and set the outcome + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ actionOutcome' = "ICS03_OK" + ELSE + \* if the client does not exist, then set an error outcome + /\ actionOutcome' = "ICS03_MissingClient" + /\ UNCHANGED <> CreateClientAction == \* select a chain id @@ -191,6 +262,8 @@ ConnectionOpenInitAction == \E clientId \in ClientIds: \* select a couterparty client id \E counterpartyClientId \in ClientIds: + \* only create connection if the model constant `MaxConnectionsPerChain` allows it + /\ chains[chainId].connectionIdCounter \in ConnectionIds /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) /\ action' = AsAction([type |-> "ConnectionOpenInit", chainId |-> chainId, @@ -199,9 +272,17 @@ ConnectionOpenInitAction == Init == \* create an empty chain + LET emptyConnection == [ + state |-> "Uninit", + clientId |-> NullClientId, + counterpartyClientId |-> NullClientId, + connectionId |-> NullConnectionId, + counterpartyConnectionId |-> NullConnectionId + ] IN LET emptyChain == [ clients |-> [clientId \in ClientIds |-> NullHeight], clientIdCounter |-> 0, + connections |-> [connectionId \in ConnectionIds |-> emptyConnection], connectionIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] From f3cd4341922d3d554952ddcc600581229ff36146 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 21:09:12 +0100 Subject: [PATCH 018/104] Represent clients with a record in TLA spec --- modules/tests/support/model_based/IBC.tla | 71 ++++++++++++++--------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 4a3ef02a97..e70b3484ee 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -55,9 +55,13 @@ ConnectionStates == { "Open" } +\* data kept per cliennt +Client == [ + height: ClientHeights \union {NullHeight} +] \* mapping from client identifier to its height Clients == [ - ClientIds -> ClientHeights \union {NullHeight} + ClientIds -> Client ] \* data kept per connection Connection == [ @@ -78,6 +82,10 @@ Chain == [ connections: Connections, connectionIdCounter: 0..MaxConnectionsPerChain ] +\* mapping from chain identifier to its data +Chains == [ + ChainIds -> Chain +] \* set of possible actions NullActions == [ @@ -121,29 +129,29 @@ ActionOutcomes == { Specification ***************************************************************************) -\* retrieves `clientId`'s height -GetClientHeight(clients, clientId) == +\* retrieves `clientId`'s data +GetClient(clients, clientId) == clients[clientId] -\* check if a `clientId` exists +\* check if `clientId` exists ClientExists(clients, clientId) == - GetClientHeight(clients, clientId) /= NullHeight + GetClient(clients, clientId).height /= NullHeight -\* update the heigth of `clientId` to `clientHeight` -SetClientHeight(clients, clientId, clientHeight) == - [clients EXCEPT ![clientId] = clientHeight] +\* update `clientId`'s data +SetClient(clients, clientId, client) == + [clients EXCEPT ![clientId] = client] \* retrieves `connectionId`'s data GetConnection(connections, connectionId) == connections[connectionId] -\* check if a `connectionId` exists +\* check if `connectionId` exists ConnectionExists(connections, connectionId) == GetConnection(connections, connectionId).state /= "Uninit" -\* update the `connectionId`'s data -SetConnection(connections, connectionId, connectionData) == - [connections EXCEPT ![connectionId] = connectionData] +\* update `connectionId`'s data +SetConnection(connections, connectionId, connection) == + [connections EXCEPT ![connectionId] = connection] CreateClient(chainId, clientHeight) == LET chain == chains[chainId] IN @@ -157,10 +165,12 @@ CreateClient(chainId, clientHeight) == /\ UNCHANGED <> ELSE \* if it doesn't, create it + LET client == [ + height |-> clientHeight + ] IN + \* update the chain LET updatedChain == [chain EXCEPT - \* initialize the client's height to `clientHeight` - !.clients = SetClientHeight(clients, clientIdCounter, clientHeight), - \* update `clientIdCounter` + !.clients = SetClient(clients, clientIdCounter, client), !.clientIdCounter = clientIdCounter + 1 ] IN \* update `chains` and set the outcome @@ -173,12 +183,16 @@ UpdateClient(chainId, clientId, clientHeight) == \* check if the client exists IF ClientExists(clients, clientId) THEN \* if the client exists, check its height - IF GetClientHeight(clients, clientId) < clientHeight THEN + LET client == GetClient(clients, clientId) IN + IF client.height < clientHeight THEN \* if the client's height is lower than the one being updated to \* then, update the client + LET updatedClient == [client EXCEPT + !.height = clientHeight + ] IN + \* update the chain LET updatedChain == [chain EXCEPT - \* set the client's height to `clientHeight` - !.clients = SetClientHeight(clients, clientId, clientHeight) + !.clients = SetClient(clients, clientId, updatedClient) ] IN \* update `chains` and set the outcome /\ chains' = [chains EXCEPT ![chainId] = updatedChain] @@ -209,17 +223,16 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == /\ UNCHANGED <> ELSE \* if it doesn't, create it - LET connectionData == [ + LET connection == [ state |-> "Init", clientId |-> clientId, counterpartyClientId |-> counterpartyClientId, connectionId |-> connectionIdCounter, counterpartyConnectionId |-> NullConnectionId ] IN + \* update the chain LET updatedChain == [chain EXCEPT - \* initialize the connection's data - !.connections = SetConnection(connections, connectionIdCounter, connectionData), - \* update `clientIdCounter` + !.connections = SetConnection(connections, connectionIdCounter, connection), !.connectionIdCounter = connectionIdCounter + 1 ] IN \* update `chains` and set the outcome @@ -271,18 +284,22 @@ ConnectionOpenInitAction == counterpartyClientId |-> counterpartyClientId]) Init == - \* create an empty chain - LET emptyConnection == [ + \* create an null client and a null connection + LET nullClient == [ + height |-> NullHeight + ] IN + LET nullConnection == [ state |-> "Uninit", clientId |-> NullClientId, counterpartyClientId |-> NullClientId, connectionId |-> NullConnectionId, counterpartyConnectionId |-> NullConnectionId ] IN + \* create an empty chain LET emptyChain == [ - clients |-> [clientId \in ClientIds |-> NullHeight], + clients |-> [clientId \in ClientIds |-> nullClient], clientIdCounter |-> 0, - connections |-> [connectionId \in ConnectionIds |-> emptyConnection], + connections |-> [connectionId \in ConnectionIds |-> nullConnection], connectionIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] @@ -300,7 +317,7 @@ Next == ***************************************************************************) TypeOK == - /\ chains \in [ChainIds -> Chain] + /\ chains \in Chains /\ action \in Actions /\ actionOutcome \in ActionOutcomes From 4167d29fef7a2b299d79df21e34c27d722c83065 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 23:00:30 +0100 Subject: [PATCH 019/104] Finish connection open init --- modules/tests/model_based.rs | 162 +++++++++++++----- modules/tests/state.rs | 19 +- modules/tests/support/model_based/IBC.tla | 35 ++-- .../tests/support/model_based/IBCTests.cfg | 15 +- .../tests/support/model_based/IBCTests.tla | 32 ++-- ...> ICS02HeaderVerificationFailureTest.json} | 8 +- ...dateOKTest.json => ICS02UpdateOKTest.json} | 24 +-- .../ICS03ConnectionOpenInitOKTest.json | 25 +++ .../model_based/ICS03MissingClientTest.json | 25 +++ 9 files changed, 243 insertions(+), 102 deletions(-) rename modules/tests/support/model_based/{UpdateHeightVerificationFailureTest.json => ICS02HeaderVerificationFailureTest.json} (65%) rename modules/tests/support/model_based/{UpdateOKTest.json => ICS02UpdateOKTest.json} (62%) create mode 100644 modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json create mode 100644 modules/tests/support/model_based/ICS03MissingClientTest.json diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 51b1f32494..157fcac211 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -8,7 +8,13 @@ use ibc::ics02_client::error::Kind as ICS02ErrorKind; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; +use ibc::ics03_connection::connection::Counterparty; +use ibc::ics03_connection::error::Kind as ICS03ErrorKind; +use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use ibc::ics03_connection::msgs::ConnectionMsg; +use ibc::ics03_connection::version::Version; use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; +use ibc::ics23_commitment::commitment::CommitmentPrefix; use ibc::ics24_host::identifier::ChainId; use ibc::ics24_host::identifier::ClientId; use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; @@ -24,9 +30,6 @@ use std::error::Error; use std::fmt::{Debug, Display}; use tendermint::account::Id as AccountId; -// all chains use the same version -const VERSION: u64 = 0; - #[derive(Debug)] struct ICS02TestExecutor { // mapping from chain identifier to its context @@ -47,22 +50,14 @@ impl ICS02TestExecutor { let max_history_size = 1; let initial_height = 0; MockContext::new( - ChainId::new(chain_id, VERSION), + ChainId::new(chain_id, Self::epoch()), HostType::Mock, max_history_size, - Height::new(VERSION, initial_height), + Height::new(Self::epoch(), initial_height), ) }) } - fn dummy_signer() -> AccountId { - AccountId::new([0; 20]) - } - - fn mock_header(height: u64) -> MockHeader { - MockHeader(Height::new(VERSION, height)) - } - fn extract_handler_error_kind(result: Result<(), ICS18Error>) -> K where K: Clone + Debug + Display + Into + 'static, @@ -89,6 +84,53 @@ impl ICS02TestExecutor { .kind() .clone() } + + // TODO: this is sometimes called version/revision number but seems + // unrelated with the `Version` type below; is that so? + fn epoch() -> u64 { + 0 + } + + fn version() -> Version { + Version::default() + } + + fn client_id(client_id: u64) -> ClientId { + ClientId::new(ClientType::Mock, client_id) + .expect("it should be possible to create the client identifier") + } + + fn mock_header(height: u64) -> MockHeader { + MockHeader(Height::new(Self::epoch(), height)) + } + + fn header(height: u64) -> AnyHeader { + AnyHeader::Mock(Self::mock_header(height)) + } + + fn client_state(height: u64) -> AnyClientState { + AnyClientState::Mock(MockClientState(Self::mock_header(height))) + } + + fn consensus_state(height: u64) -> AnyConsensusState { + AnyConsensusState::Mock(MockConsensusState(Self::mock_header(height))) + } + + fn signer() -> AccountId { + AccountId::new([0; 20]) + } + + fn counterparty(counterparty_client_id: u64) -> Counterparty { + Counterparty::new( + Self::client_id(counterparty_client_id), + None, + CommitmentPrefix(Vec::new()), + ) + } + + fn delay_period() -> u64 { + 0 + } } impl modelator::TestExecutor for ICS02TestExecutor { @@ -109,7 +151,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { fn check_next_state(&mut self, state: State) -> bool { match state.action.action_type { ActionType::Null => panic!("unexpected action type"), - ActionType::CreateClient => { + ActionType::ICS02CreateClient => { // get action parameters let chain_id = state .action @@ -123,32 +165,24 @@ impl modelator::TestExecutor for ICS02TestExecutor { // get chain's context let ctx = self.get_chain_context_or_init(chain_id); - // create client and consensus state from parameters - let client_state = AnyClientState::Mock(MockClientState(Self::mock_header(height))); - let consensus_state = - AnyConsensusState::Mock(MockConsensusState(Self::mock_header(height))); - - // create dummy signer - let signer = Self::dummy_signer(); - // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { - client_state, - consensus_state, - signer, + client_state: Self::client_state(height), + consensus_state: Self::consensus_state(height), + signer: Self::signer(), })); let result = ctx.deliver(msg); // check the expected outcome: client create always succeeds match state.action_outcome { - ActionOutcome::ICS02OK => { + ActionOutcome::ICS02CreateOK => { // the implementaion matches the model if no error occurs result.is_ok() } action => panic!("unexpected action outcome {:?}", action), } } - ActionType::UpdateClient => { + ActionType::ICS02UpdateClient => { // get action parameters let chain_id = state .action @@ -166,25 +200,17 @@ impl modelator::TestExecutor for ICS02TestExecutor { // get chain's context let ctx = self.get_chain_context_or_init(chain_id); - // create client id and header from action parameters - let client_id = ClientId::new(ClientType::Mock, client_id) - .expect("it should be possible to create the client identifier"); - let header = AnyHeader::Mock(Self::mock_header(height)); - - // create dummy signer - let signer = Self::dummy_signer(); - // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { - client_id: client_id.clone(), - header, - signer, + client_id: Self::client_id(client_id), + header: Self::header(height), + signer: Self::signer(), })); let result = ctx.deliver(msg); // check the expected outcome match state.action_outcome { - ActionOutcome::ICS02OK => { + ActionOutcome::ICS02UpdateOK => { // the implementaion matches the model if no error occurs result.is_ok() } @@ -195,7 +221,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { // error matching the expected outcome matches!( handler_error_kind, - ICS02ErrorKind::ClientNotFound(id) if id == client_id + ICS02ErrorKind::ClientNotFound(id) if id == Self::client_id(client_id) ) } ActionOutcome::ICS02HeaderVerificationFailure => { @@ -208,8 +234,53 @@ impl modelator::TestExecutor for ICS02TestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - ActionType::ConnectionOpenInit => { - todo!() + ActionType::ICS03ConnectionOpenInit => { + // get action parameters + let chain_id = state + .action + .chain_id + .expect("connection open init action should have a chain identifier"); + let client_id = state + .action + .client_id + .expect("connection open init action should have a client identifier"); + let counterparty_client_id = state.action.counterparty_client_id.expect( + "connection open init action should have a counterparty client identifier", + ); + + // get chain's context + let ctx = self.get_chain_context_or_init(chain_id); + + // create ICS26 message and deliver it + let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenInit( + MsgConnectionOpenInit { + client_id: Self::client_id(client_id), + counterparty: Self::counterparty(counterparty_client_id), + version: Self::version(), + delay_period: Self::delay_period(), + signer: Self::signer(), + }, + )); + let result = ctx.deliver(msg); + + // check the expected outcome + match state.action_outcome { + ActionOutcome::ICS03ConnectionOpenInitOK => { + // the implementaion matches the model if no error occurs + result.is_ok() + } + ActionOutcome::ICS03MissingClient => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + matches!( + handler_error_kind, + ICS03ErrorKind::MissingClient(id) if id == Self::client_id(client_id) + ) + } + action => panic!("unexpected action outcome {:?}", action), + } } } } @@ -219,7 +290,12 @@ const TESTS_DIR: &str = "tests/support/model_based"; #[test] fn main() { - let tests = vec!["UpdateOKTest", "UpdateHeightVerificationFailureTest"]; + let tests = vec![ + "ICS02UpdateOKTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + ]; for test in tests { let path = format!("{}/{}.json", TESTS_DIR, test); diff --git a/modules/tests/state.rs b/modules/tests/state.rs index 82e9255fd3..fdbd0820dc 100644 --- a/modules/tests/state.rs +++ b/modules/tests/state.rs @@ -17,27 +17,30 @@ pub struct Action { #[serde(alias = "chainId")] pub chain_id: Option, + pub height: Option, + #[serde(alias = "clientId")] pub client_id: Option, - pub height: Option, + #[serde(alias = "counterpartyClientId")] + pub counterparty_client_id: Option, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionType { Null, - CreateClient, - UpdateClient, - ConnectionOpenInit, + ICS02CreateClient, + ICS02UpdateClient, + ICS03ConnectionOpenInit, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionOutcome { Null, - #[serde(alias = "ICS02_OK")] - ICS02OK, - #[serde(alias = "ICS02_ClientNotFound")] + ICS02CreateOK, + ICS02UpdateOK, ICS02ClientNotFound, - #[serde(alias = "ICS02_HeaderVerificationFailure")] ICS02HeaderVerificationFailure, + ICS03ConnectionOpenInitOK, + ICS03MissingClient, } diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index e70b3484ee..feff8046c9 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -92,18 +92,18 @@ NullActions == [ type: {"Null"} ] <: {ActionType} CreateClientActions == [ - type: {"CreateClient"}, + type: {"ICS02CreateClient"}, chainId: ChainIds, height: ClientHeights ] <: {ActionType} UpdateClientActions == [ - type: {"UpdateClient"}, + type: {"ICS02UpdateClient"}, chainId: ChainIds, clientId: ClientIds, height: ClientHeights ] <: {ActionType} ConnectionOpenInitActions == [ - type: {"ConnectionOpenInit"}, + type: {"ICS03ConnectionOpenInit"}, chainId: ChainIds, clientId: ClientIds, counterpartyClientId: ClientIds @@ -117,11 +117,12 @@ Actions == \* set of possible action outcomes ActionOutcomes == { "Null", - "ICS02_OK", - "ICS02_ClientNotFound", - "ICS02_HeaderVerificationFailure", - "ICS03_OK", - "ICS03_MissingClient", + "ICS02CreateOK", + "ICS02UpdateOK", + "ICS02ClientNotFound", + "ICS02HeaderVerificationFailure", + "ICS03ConnectionOpenInitOK", + "ICS03MissingClient", "ModelError" } @@ -175,7 +176,7 @@ CreateClient(chainId, clientHeight) == ] IN \* update `chains` and set the outcome /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS02_OK" + /\ actionOutcome' = "ICS02CreateOK" UpdateClient(chainId, clientId, clientHeight) == LET chain == chains[chainId] IN @@ -196,15 +197,15 @@ UpdateClient(chainId, clientId, clientHeight) == ] IN \* update `chains` and set the outcome /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS02_OK" + /\ actionOutcome' = "ICS02UpdateOK" ELSE \* if the client's height is at least as high as the one being \* updated to, then set an error outcome - /\ actionOutcome' = "ICS02_HeaderVerificationFailure" + /\ actionOutcome' = "ICS02HeaderVerificationFailure" /\ UNCHANGED <> ELSE \* if the client does not exist, then set an error outcome - /\ actionOutcome' = "ICS02_ClientNotFound" + /\ actionOutcome' = "ICS02ClientNotFound" /\ UNCHANGED <> ConnectionOpenInit(chainId, clientId, counterpartyClientId) == @@ -237,10 +238,10 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ] IN \* update `chains` and set the outcome /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS03_OK" + /\ actionOutcome' = "ICS03ConnectionOpenInitOK" ELSE \* if the client does not exist, then set an error outcome - /\ actionOutcome' = "ICS03_MissingClient" + /\ actionOutcome' = "ICS03MissingClient" /\ UNCHANGED <> CreateClientAction == @@ -251,7 +252,7 @@ CreateClientAction == \* only create client if the model constant `MaxClientsPerChain` allows it /\ chains[chainId].clientIdCounter \in ClientIds /\ CreateClient(chainId, clientHeight) - /\ action' = AsAction([type |-> "CreateClient", + /\ action' = AsAction([type |-> "ICS02CreateClient", chainId |-> chainId, height |-> clientHeight]) @@ -263,7 +264,7 @@ UpdateClientAction == \* select a height for the client to be updated \E clientHeight \in ClientHeights: /\ UpdateClient(chainId, clientId, clientHeight) - /\ action' = AsAction([type |-> "UpdateClient", + /\ action' = AsAction([type |-> "ICS02UpdateClient", chainId |-> chainId, clientId |-> clientId, height |-> clientHeight]) @@ -278,7 +279,7 @@ ConnectionOpenInitAction == \* only create connection if the model constant `MaxConnectionsPerChain` allows it /\ chains[chainId].connectionIdCounter \in ConnectionIds /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) - /\ action' = AsAction([type |-> "ConnectionOpenInit", + /\ action' = AsAction([type |-> "ICS03ConnectionOpenInit", chainId |-> chainId, clientId |-> clientId, counterpartyClientId |-> counterpartyClientId]) diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 0950dd0e71..79005a26bc 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,13 +1,16 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxClientsPerChain = 4 - MaxClientHeight = 4 + MaxClientsPerChain = 2 + MaxClientHeight = 2 + MaxConnectionsPerChain = 2 INIT Init NEXT Next INVARIANTS - \* CreateOKTest - \* UpdateOKTest - \* UpdateClientNotFoundTest - UpdateHeightVerificationFailureTest \ No newline at end of file + \* ICS02CreateOKTest + \* ICS02UpdateOKTest + \* ICS02ClientNotFoundTest + \* ICS02HeaderVerificationFailureTest + ICS03ConnectionOpenInitOKTest + \* ICS03MissingClientTest \ No newline at end of file diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index f24eb10cc2..660d9cd60d 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -2,21 +2,29 @@ EXTENDS IBC -CreateOK == - /\ actionOutcome = "CreateOK" +ICS02CreateOK == + /\ actionOutcome = "ICS02CreateOK" -UpdateOK == - /\ actionOutcome = "UpdateOK" +ICS02UpdateOK == + /\ actionOutcome = "ICS02UpdateOK" -UpdateClientNotFound == - /\ actionOutcome = "UpdateClientNotFound" +ICS02ClientNotFound == + /\ actionOutcome = "ICS02ClientNotFound" -UpdateHeightVerificationFailure == - /\ actionOutcome = "UpdateHeightVerificationFailure" +ICS02HeaderVerificationFailure == + /\ actionOutcome = "ICS02HeaderVerificationFailure" -CreateOKTest == ~CreateOK -UpdateOKTest == ~UpdateOK -UpdateClientNotFoundTest == ~UpdateClientNotFound -UpdateHeightVerificationFailureTest == ~UpdateHeightVerificationFailure +ICS03ConnectionOpenInitOK == + /\ actionOutcome = "ICS03ConnectionOpenInitOK" + +ICS03MissingClient == + /\ actionOutcome = "ICS03MissingClient" + +ICS02CreateOKTest == ~ICS02CreateOK +ICS02UpdateOKTest == ~ICS02UpdateOK +ICS02ClientNotFoundTest == ~ICS02ClientNotFound +ICS02HeaderVerificationFailureTest == ~ICS02HeaderVerificationFailure +ICS03ConnectionOpenInitOKTest == ~ICS03ConnectionOpenInitOK +ICS03MissingClientTest == ~ICS03MissingClient ============================================================================= \ No newline at end of file diff --git a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json similarity index 65% rename from modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json rename to modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index 2df6fbdcd2..cde46f8d20 100644 --- a/modules/tests/support/model_based/UpdateHeightVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -9,17 +9,17 @@ "action": { "chainId": "chain-B", "height": 1, - "type": "CreateClient" + "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02CreateOK" }, { "action": { "chainId": "chain-B", "clientId": 0, "height": 1, - "type": "UpdateClient" + "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02_HeaderVerificationFailure" + "actionOutcome": "ICS02HeaderVerificationFailure" } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json similarity index 62% rename from modules/tests/support/model_based/UpdateOKTest.json rename to modules/tests/support/model_based/ICS02UpdateOKTest.json index 1ebc6caf2f..8a78fa3bfa 100644 --- a/modules/tests/support/model_based/UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -9,51 +9,51 @@ "action": { "chainId": "chain-B", "height": 1, - "type": "CreateClient" + "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02CreateOK" }, { "action": { "chainId": "chain-B", "clientId": 0, "height": 2, - "type": "UpdateClient" + "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02UpdateOK" }, { "action": { "chainId": "chain-A", "height": 1, - "type": "CreateClient" + "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02CreateOK" }, { "action": { "chainId": "chain-A", "clientId": 0, "height": 2, - "type": "UpdateClient" + "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02UpdateOK" }, { "action": { "chainId": "chain-A", "height": 1, - "type": "CreateClient" + "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02CreateOK" }, { "action": { "chainId": "chain-A", "clientId": 1, "height": 2, - "type": "UpdateClient" + "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02_OK" + "actionOutcome": "ICS02UpdateOK" } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json new file mode 100644 index 0000000000..5ef27e6744 --- /dev/null +++ b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json @@ -0,0 +1,25 @@ +[ + { + "action": { + "type": "Null" + }, + "actionOutcome": "Null" + }, + { + "action": { + "chainId": "chain-A", + "height": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK" + }, + { + "action": { + "chainId": "chain-A", + "clientId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK" + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json new file mode 100644 index 0000000000..4f180b696b --- /dev/null +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -0,0 +1,25 @@ +[ + { + "action": { + "type": "Null" + }, + "actionOutcome": "Null" + }, + { + "action": { + "chainId": "chain-A", + "height": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK" + }, + { + "action": { + "chainId": "chain-B", + "clientId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03MissingClient" + } +] \ No newline at end of file From 7755fec99b2335ad46bceda6f1feb94289beebd8 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 3 Feb 2021 23:12:40 +0100 Subject: [PATCH 020/104] s/state/step --- modules/tests/model_based.rs | 38 ++++++++++++++--------------- modules/tests/modelator.rs | 35 +++++++++++++------------- modules/tests/{state.rs => step.rs} | 2 +- 3 files changed, 37 insertions(+), 38 deletions(-) rename modules/tests/{state.rs => step.rs} (98%) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 157fcac211..3d2d7852ed 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -1,5 +1,5 @@ mod modelator; -mod state; +mod step; use ibc::ics02_client::client_def::AnyHeader; use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; @@ -24,10 +24,10 @@ use ibc::mock::context::MockContext; use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; use ibc::Height; -use state::{ActionOutcome, ActionType, State}; use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; +use step::{ActionOutcome, ActionType, Step}; use tendermint::account::Id as AccountId; #[derive(Debug)] @@ -133,31 +133,31 @@ impl ICS02TestExecutor { } } -impl modelator::TestExecutor for ICS02TestExecutor { - fn check_initial_state(&mut self, state: State) -> bool { +impl modelator::TestExecutor for ICS02TestExecutor { + fn initial_step(&mut self, step: Step) -> bool { assert_eq!( - state.action.action_type, + step.action.action_type, ActionType::Null, "unexpected action type" ); assert_eq!( - state.action_outcome, + step.action_outcome, ActionOutcome::Null, "unexpected action outcome" ); true } - fn check_next_state(&mut self, state: State) -> bool { - match state.action.action_type { + fn next_step(&mut self, step: Step) -> bool { + match step.action.action_type { ActionType::Null => panic!("unexpected action type"), ActionType::ICS02CreateClient => { // get action parameters - let chain_id = state + let chain_id = step .action .chain_id .expect("create client action should have a chain identifier"); - let height = state + let height = step .action .height .expect("create client action should have a height"); @@ -174,7 +174,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { let result = ctx.deliver(msg); // check the expected outcome: client create always succeeds - match state.action_outcome { + match step.action_outcome { ActionOutcome::ICS02CreateOK => { // the implementaion matches the model if no error occurs result.is_ok() @@ -184,15 +184,15 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionType::ICS02UpdateClient => { // get action parameters - let chain_id = state + let chain_id = step .action .chain_id .expect("update client action should have a chain identifier"); - let client_id = state + let client_id = step .action .client_id .expect("update client action should have a client identifier"); - let height = state + let height = step .action .height .expect("update client action should have a height"); @@ -209,7 +209,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { let result = ctx.deliver(msg); // check the expected outcome - match state.action_outcome { + match step.action_outcome { ActionOutcome::ICS02UpdateOK => { // the implementaion matches the model if no error occurs result.is_ok() @@ -236,15 +236,15 @@ impl modelator::TestExecutor for ICS02TestExecutor { } ActionType::ICS03ConnectionOpenInit => { // get action parameters - let chain_id = state + let chain_id = step .action .chain_id .expect("connection open init action should have a chain identifier"); - let client_id = state + let client_id = step .action .client_id .expect("connection open init action should have a client identifier"); - let counterparty_client_id = state.action.counterparty_client_id.expect( + let counterparty_client_id = step.action.counterparty_client_id.expect( "connection open init action should have a counterparty client identifier", ); @@ -264,7 +264,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { let result = ctx.deliver(msg); // check the expected outcome - match state.action_outcome { + match step.action_outcome { ActionOutcome::ICS03ConnectionOpenInitOK => { // the implementaion matches the model if no error occurs result.is_ok() diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index d395119e20..91d60d6800 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -6,15 +6,14 @@ use std::io::BufReader; use std::path::Path; pub trait TestExecutor { - fn check_initial_state(&mut self, state: S) -> bool; - - fn check_next_state(&mut self, state: S) -> bool; + fn initial_step(&mut self, step: S) -> bool; + fn next_step(&mut self, step: S) -> bool; } -pub fn test_driver(mut executor: E, path: P) -> Result<()> +pub fn test_driver(mut executor: Executor, path: P) -> Result<()> where - E: TestExecutor + Debug, - S: DeserializeOwned + Debug + Clone, + Executor: TestExecutor + Debug, + Step: DeserializeOwned + Debug + Clone, P: AsRef, { // open test file @@ -23,27 +22,27 @@ where let reader = BufReader::new(file); // parse test file - let states: Vec = serde_json::de::from_reader(reader) + let steps: Vec = serde_json::de::from_reader(reader) .wrap_err_with(|| format!("test file {:?} could not be deserialized", path.as_ref()))?; - let mut states = states.into_iter(); + let mut steps = steps.into_iter(); - // check the initial state - if let Some(state) = states.next() { - if !executor.check_initial_state(state.clone()) { - return Err(eyre!("check failed on initial state:\n{:#?}", state)); + // check the initial step + if let Some(step) = steps.next() { + if !executor.initial_step(step.clone()) { + return Err(eyre!("check failed on initial step:\n{:#?}", step)); } } else { - println!("WARNING: test file {:?} had 0 states", path.as_ref()); + println!("WARNING: test file {:?} had 0 steps", path.as_ref()); return Ok(()); } - // check all the remaining states - for state in states { - if !executor.check_next_state(state.clone()) { + // check the remaining steps + for step in steps { + if !executor.next_step(step.clone()) { return Err(eyre!( - "check failed on state:\n{:#?}\n\nexecutor:\n{:#?}", - state, + "check failed on step:\n{:#?}\n\nexecutor:\n{:#?}", + step, executor )); } diff --git a/modules/tests/state.rs b/modules/tests/step.rs similarity index 98% rename from modules/tests/state.rs rename to modules/tests/step.rs index fdbd0820dc..a84e67bb33 100644 --- a/modules/tests/state.rs +++ b/modules/tests/step.rs @@ -2,7 +2,7 @@ use serde::Deserialize; use std::fmt::Debug; #[derive(Debug, Clone, Deserialize)] -pub struct State { +pub struct Step { pub action: Action, #[serde(alias = "actionOutcome")] From 70e70f63f1e60f2708822bec474601deb2ef7c89 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 09:12:25 +0100 Subject: [PATCH 021/104] Minimize diff --- modules/src/mock/context.rs | 9 ++++----- modules/tests/model_based.rs | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index 47319c40c2..c656363513 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -394,9 +394,9 @@ impl ChannelKeeper for MockContext { fn next_channel_id(&mut self) -> ChannelId { let prefix = ChannelId::default().to_string(); let suffix = self.channel_ids_counter; - let channel_id = ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap(); self.channel_ids_counter += 1; - channel_id + + ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() } fn store_channel( @@ -499,10 +499,9 @@ impl ConnectionKeeper for MockContext { fn next_connection_id(&mut self) -> ConnectionId { let prefix = ConnectionId::default().to_string(); let suffix = self.connection_ids_counter; - let connection_id = - ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap(); self.connection_ids_counter += 1; - connection_id + + ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() } fn store_connection( diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 3d2d7852ed..f4213fffaa 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -299,10 +299,10 @@ fn main() { for test in tests { let path = format!("{}/{}.json", TESTS_DIR, test); - let test_executor = ICS02TestExecutor::new(); + let executor = ICS02TestExecutor::new(); // we should be able to just return the `Result` once the following issue // is fixed: https://github.com/rust-lang/rust/issues/43301 - if let Err(e) = modelator::test_driver(test_executor, path) { + if let Err(e) = modelator::test_driver(executor, path) { panic!("{:?}", e); } } From 41d34d312adeaa60ff7600d6ac6ccead134e75d7 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 11:44:27 +0100 Subject: [PATCH 022/104] Modularize TLA spec --- modules/tests/support/model_based/IBC.tla | 156 +++++------------- .../support/model_based/IBCDefinitions.tla | 12 ++ modules/tests/support/model_based/ICS02.tla | 67 ++++++++ modules/tests/support/model_based/ICS03.tla | 52 ++++++ 4 files changed, 169 insertions(+), 118 deletions(-) create mode 100644 modules/tests/support/model_based/IBCDefinitions.tla create mode 100644 modules/tests/support/model_based/ICS02.tla create mode 100644 modules/tests/support/model_based/ICS03.tla diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index feff8046c9..deb2b2011b 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,6 +1,6 @@ --------------------------- MODULE IBC ---------------------------- -EXTENDS Integers, FiniteSets +EXTENDS Integers, FiniteSets, ICS02, ICS03 \* ids of existing chains CONSTANT ChainIds @@ -37,16 +37,10 @@ AsAction(a) == a <: ActionType \* set of possible client identifiers ClientIds == 0..(MaxClientsPerChain - 1) -\* if a client identifier is undefined then it is -1 -NullClientId == -1 \* set of possible client heights ClientHeights == 1..MaxClientHeight -\* if a client identifier is undefined then it is -1 -NullHeight == -1 \* set of possible connection identifiers ConnectionIds == 0..(MaxConnectionsPerChain- 1) -\* if a connection identifier is undefined then it is -1 -NullConnectionId == -1 \* set of possible connection states ConnectionStates == { "Uninit", @@ -130,119 +124,56 @@ ActionOutcomes == { Specification ***************************************************************************) -\* retrieves `clientId`'s data -GetClient(clients, clientId) == - clients[clientId] - -\* check if `clientId` exists -ClientExists(clients, clientId) == - GetClient(clients, clientId).height /= NullHeight - -\* update `clientId`'s data -SetClient(clients, clientId, client) == - [clients EXCEPT ![clientId] = client] - -\* retrieves `connectionId`'s data -GetConnection(connections, connectionId) == - connections[connectionId] - -\* check if `connectionId` exists -ConnectionExists(connections, connectionId) == - GetConnection(connections, connectionId).state /= "Uninit" - -\* update `connectionId`'s data -SetConnection(connections, connectionId, connection) == - [connections EXCEPT ![connectionId] = connection] - CreateClient(chainId, clientHeight) == LET chain == chains[chainId] IN LET clients == chain.clients IN LET clientIdCounter == chain.clientIdCounter IN - \* check if the client exists (it shouldn't) - IF ClientExists(clients, clientIdCounter) THEN - \* if the client to be created already exists, - \* then there's an error in the model - /\ actionOutcome' = "ModelError" - /\ UNCHANGED <> - ELSE - \* if it doesn't, create it - LET client == [ - height |-> clientHeight - ] IN - \* update the chain - LET updatedChain == [chain EXCEPT - !.clients = SetClient(clients, clientIdCounter, client), - !.clientIdCounter = clientIdCounter + 1 - ] IN - \* update `chains` and set the outcome - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS02CreateOK" + LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.clients = result.clients, + !.clientIdCounter = result.clientIdCounter + ] IN + \* update `chains`, set the action and its outcome + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([type |-> "ICS02CreateClient", + chainId |-> chainId, + height |-> clientHeight]) + /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, clientHeight) == LET chain == chains[chainId] IN LET clients == chain.clients IN - \* check if the client exists - IF ClientExists(clients, clientId) THEN - \* if the client exists, check its height - LET client == GetClient(clients, clientId) IN - IF client.height < clientHeight THEN - \* if the client's height is lower than the one being updated to - \* then, update the client - LET updatedClient == [client EXCEPT - !.height = clientHeight - ] IN - \* update the chain - LET updatedChain == [chain EXCEPT - !.clients = SetClient(clients, clientId, updatedClient) - ] IN - \* update `chains` and set the outcome - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS02UpdateOK" - ELSE - \* if the client's height is at least as high as the one being - \* updated to, then set an error outcome - /\ actionOutcome' = "ICS02HeaderVerificationFailure" - /\ UNCHANGED <> - ELSE - \* if the client does not exist, then set an error outcome - /\ actionOutcome' = "ICS02ClientNotFound" - /\ UNCHANGED <> + LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.clients = result.clients + ] IN + \* update `chains`, set the action and its outcome + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([type |-> "ICS02UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + height |-> clientHeight]) + /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == LET chain == chains[chainId] IN LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN - \* check if the client exists - IF ClientExists(clients, clientId) THEN - \* if the client exists, - \* then check if the connection exists (it shouldn't) - IF ConnectionExists(connections, connectionIdCounter) THEN - \* if the connection to be created already exists, - \* then there's an error in the model - /\ actionOutcome' = "ModelError" - /\ UNCHANGED <> - ELSE - \* if it doesn't, create it - LET connection == [ - state |-> "Init", - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId, - connectionId |-> connectionIdCounter, - counterpartyConnectionId |-> NullConnectionId - ] IN - \* update the chain - LET updatedChain == [chain EXCEPT - !.connections = SetConnection(connections, connectionIdCounter, connection), - !.connectionIdCounter = connectionIdCounter + 1 - ] IN - \* update `chains` and set the outcome - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ actionOutcome' = "ICS03ConnectionOpenInitOK" - ELSE - \* if the client does not exist, then set an error outcome - /\ actionOutcome' = "ICS03MissingClient" - /\ UNCHANGED <> + LET result == ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, counterpartyClientId) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.connections = result.connections, + !.connectionIdCounter = result.connectionIdCounter + ] IN + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([type |-> "ICS03ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId]) + /\ actionOutcome' = result.outcome CreateClientAction == \* select a chain id @@ -252,9 +183,6 @@ CreateClientAction == \* only create client if the model constant `MaxClientsPerChain` allows it /\ chains[chainId].clientIdCounter \in ClientIds /\ CreateClient(chainId, clientHeight) - /\ action' = AsAction([type |-> "ICS02CreateClient", - chainId |-> chainId, - height |-> clientHeight]) UpdateClientAction == \* select a chain id @@ -263,11 +191,7 @@ UpdateClientAction == \E clientId \in ClientIds: \* select a height for the client to be updated \E clientHeight \in ClientHeights: - /\ UpdateClient(chainId, clientId, clientHeight) - /\ action' = AsAction([type |-> "ICS02UpdateClient", - chainId |-> chainId, - clientId |-> clientId, - height |-> clientHeight]) + UpdateClient(chainId, clientId, clientHeight) ConnectionOpenInitAction == \* select a chain id @@ -279,10 +203,6 @@ ConnectionOpenInitAction == \* only create connection if the model constant `MaxConnectionsPerChain` allows it /\ chains[chainId].connectionIdCounter \in ConnectionIds /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) - /\ action' = AsAction([type |-> "ICS03ConnectionOpenInit", - chainId |-> chainId, - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId]) Init == \* create an null client and a null connection diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla new file mode 100644 index 0000000000..e8ac537c08 --- /dev/null +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -0,0 +1,12 @@ +--------------------------- MODULE IBCDefinitions ---------------------------- + +EXTENDS Integers, FiniteSets + +\* if a client identifier is undefined then it is -1 +NullClientId == -1 +\* if a client identifier is undefined then it is -1 +NullHeight == -1 +\* if a connection identifier is undefined then it is -1 +NullConnectionId == -1 + +============================================================================= diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla new file mode 100644 index 0000000000..7fe4d7dc0c --- /dev/null +++ b/modules/tests/support/model_based/ICS02.tla @@ -0,0 +1,67 @@ +------------------------- MODULE ICS02 -------------------------- + +EXTENDS Integers, FiniteSets, IBCDefinitions + +\* retrieves `clientId`'s data +ICS02_GetClient(clients, clientId) == + clients[clientId] + +\* check if `clientId` exists +ICS02_ClientExists(clients, clientId) == + ICS02_GetClient(clients, clientId).height /= NullHeight + +\* update `clientId`'s data +ICS02_SetClient(clients, clientId, client) == + [clients EXCEPT ![clientId] = client] + +ICS02_CreateClient(clients, clientIdCounter, clientHeight) == + \* check if the client exists (it shouldn't) + IF ICS02_ClientExists(clients, clientIdCounter) THEN + \* if the client to be created already exists, + \* then there's an error in the model + [ + clients |-> clients, + clientIdCounter |-> clientIdCounter, + outcome |-> "ModelError" + ] + ELSE + \* if it doesn't, create it + LET client == [ + height |-> clientHeight + ] IN + [ + clients |-> ICS02_SetClient(clients, clientIdCounter, client), + clientIdCounter |-> clientIdCounter + 1, + outcome |-> "ICS02CreateOK" + ] + +ICS02_UpdateClient(clients, clientId, clientHeight) == + \* check if the client exists + IF ICS02_ClientExists(clients, clientId) THEN + \* if the client exists, check its height + LET client == ICS02_GetClient(clients, clientId) IN + IF client.height < clientHeight THEN + \* if the client's height is lower than the one being updated to + \* then, update the client + LET updatedClient == [client EXCEPT + !.height = clientHeight + ] IN + [ + clients |-> ICS02_SetClient(clients, clientId, updatedClient), + outcome |-> "ICS02UpdateOK" + ] + ELSE + \* if the client's height is at least as high as the one being + \* updated to, then set an error outcome + [ + clients |-> clients, + outcome |-> "ICS02HeaderVerificationFailure" + ] + ELSE + \* if the client does not exist, then set an error outcome + [ + clients |-> clients, + outcome |-> "ICS02ClientNotFound" + ] + +============================================================================= \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla new file mode 100644 index 0000000000..73c370a042 --- /dev/null +++ b/modules/tests/support/model_based/ICS03.tla @@ -0,0 +1,52 @@ +------------------------- MODULE ICS03 -------------------------- + +EXTENDS Integers, FiniteSets, IBCDefinitions, ICS02 + +\* retrieves `connectionId`'s data +ICS03_GetConnection(connections, connectionId) == + connections[connectionId] + +\* check if `connectionId` exists +ICS03_ConnectionExists(connections, connectionId) == + ICS03_GetConnection(connections, connectionId).state /= "Uninit" + +\* update `connectionId`'s data +ICS03_SetConnection(connections, connectionId, connection) == + [connections EXCEPT ![connectionId] = connection] + +ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, counterpartyClientId) == + \* check if the client exists + IF ICS02_ClientExists(clients, clientId) THEN + \* if the client exists, + \* then check if the connection exists (it shouldn't) + IF ICS03_ConnectionExists(connections, connectionIdCounter) THEN + \* if the connection to be created already exists, + \* then there's an error in the model + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ModelError" + ] + ELSE + \* if it doesn't, create it + LET connection == [ + state |-> "Init", + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId, + connectionId |-> connectionIdCounter, + counterpartyConnectionId |-> NullConnectionId + ] IN + [ + connections |-> ICS03_SetConnection(connections, connectionIdCounter, connection), + connectionIdCounter |-> connectionIdCounter + 1, + outcome |-> "ICS03ConnectionOpenInitOK" + ] + ELSE + \* if the client does not exist, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03MissingClient" + ] + +============================================================================= \ No newline at end of file From 1f9881cbf5359f43cbb91445559e8473157cb1f8 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 12:02:39 +0100 Subject: [PATCH 023/104] TLA format convention --- modules/tests/support/model_based/IBC.tla | 65 +++++++++++-------- .../support/model_based/IBCDefinitions.tla | 4 +- .../tests/support/model_based/IBCTests.tla | 4 +- modules/tests/support/model_based/ICS02.tla | 6 +- modules/tests/support/model_based/ICS03.tla | 19 ++++-- 5 files changed, 61 insertions(+), 37 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index deb2b2011b..6ae053d9bd 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,4 +1,4 @@ ---------------------------- MODULE IBC ---------------------------- +--------------------------------- MODULE IBC ---------------------------------- EXTENDS Integers, FiniteSets, ICS02, ICS03 @@ -21,7 +21,7 @@ VARIABLE action \* string with the outcome of the last operation VARIABLE actionOutcome -(********************* TYPE ANNOTATIONS FOR APALACHE ***********************) +(********************** TYPE ANNOTATIONS FOR APALACHE ************************) \* operator for type annotations a <: b == a @@ -33,7 +33,7 @@ ActionType == [ counterpartyClientId |-> Int ] AsAction(a) == a <: ActionType -(****************** END OF TYPE ANNOTATIONS FOR APALACHE ********************) +(******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) \* set of possible client identifiers ClientIds == 0..(MaxClientsPerChain - 1) @@ -120,9 +120,7 @@ ActionOutcomes == { "ModelError" } -(*************************************************************************** - Specification - ***************************************************************************) +(***************************** Specification *********************************) CreateClient(chainId, clientHeight) == LET chain == chains[chainId] IN @@ -134,11 +132,13 @@ CreateClient(chainId, clientHeight) == !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN - \* update `chains`, set the action and its outcome + \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([type |-> "ICS02CreateClient", - chainId |-> chainId, - height |-> clientHeight]) + /\ action' = AsAction([ + type |-> "ICS02CreateClient", + chainId |-> chainId, + height |-> clientHeight + ]) /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, clientHeight) == @@ -149,12 +149,14 @@ UpdateClient(chainId, clientId, clientHeight) == LET updatedChain == [chain EXCEPT !.clients = result.clients ] IN - \* update `chains`, set the action and its outcome + \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([type |-> "ICS02UpdateClient", - chainId |-> chainId, - clientId |-> clientId, - height |-> clientHeight]) + /\ action' = AsAction([ + type |-> "ICS02UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + height |-> clientHeight + ]) /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == @@ -162,17 +164,26 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN - LET result == ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, counterpartyClientId) IN + LET result == ICS03_ConnectionOpenInit( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId + ) IN \* update the chain LET updatedChain == [chain EXCEPT !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN + \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([type |-> "ICS03ConnectionOpenInit", - chainId |-> chainId, - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId]) + /\ action' = AsAction([ + type |-> "ICS03ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId + ]) /\ actionOutcome' = result.outcome CreateClientAction == @@ -180,7 +191,8 @@ CreateClientAction == \E chainId \in ChainIds: \* select a height for the client to be created at \E clientHeight \in ClientHeights: - \* only create client if the model constant `MaxClientsPerChain` allows it + \* only create client if the model constant `MaxClientsPerChain` allows + \* it /\ chains[chainId].clientIdCounter \in ClientIds /\ CreateClient(chainId, clientHeight) @@ -200,12 +212,13 @@ ConnectionOpenInitAction == \E clientId \in ClientIds: \* select a couterparty client id \E counterpartyClientId \in ClientIds: - \* only create connection if the model constant `MaxConnectionsPerChain` allows it + \* only create connection if the model constant `MaxConnectionsPerChain` + \* allows it /\ chains[chainId].connectionIdCounter \in ConnectionIds /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) Init == - \* create an null client and a null connection + \* create a null client and a null connection LET nullClient == [ height |-> NullHeight ] IN @@ -233,9 +246,7 @@ Next == \/ ConnectionOpenInitAction \/ UNCHANGED <> -(*************************************************************************** - Invariants - ***************************************************************************) +(******************************** Invariants *********************************) TypeOK == /\ chains \in Chains @@ -246,4 +257,4 @@ TypeOK == ModelNeverErrors == actionOutcome /= "ModelError" -============================================================================= +=============================================================================== diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index e8ac537c08..045395cfb8 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -1,4 +1,4 @@ ---------------------------- MODULE IBCDefinitions ---------------------------- +--------------------------- MODULE IBCDefinitions ----------------------------- EXTENDS Integers, FiniteSets @@ -9,4 +9,4 @@ NullHeight == -1 \* if a connection identifier is undefined then it is -1 NullConnectionId == -1 -============================================================================= +=============================================================================== diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 660d9cd60d..5165bf50b9 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -1,4 +1,4 @@ -------------------------- MODULE IBCTests --------------------------- +------------------------------ MODULE IBCTests -------------------------------- EXTENDS IBC @@ -27,4 +27,4 @@ ICS02HeaderVerificationFailureTest == ~ICS02HeaderVerificationFailure ICS03ConnectionOpenInitOKTest == ~ICS03ConnectionOpenInitOK ICS03MissingClientTest == ~ICS03MissingClient -============================================================================= \ No newline at end of file +=============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 7fe4d7dc0c..ab930a382b 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -1,4 +1,4 @@ -------------------------- MODULE ICS02 -------------------------- +------------------------------- MODULE ICS02 ---------------------------------- EXTENDS Integers, FiniteSets, IBCDefinitions @@ -29,6 +29,7 @@ ICS02_CreateClient(clients, clientIdCounter, clientHeight) == LET client == [ height |-> clientHeight ] IN + \* return result with updated state [ clients |-> ICS02_SetClient(clients, clientIdCounter, client), clientIdCounter |-> clientIdCounter + 1, @@ -46,6 +47,7 @@ ICS02_UpdateClient(clients, clientId, clientHeight) == LET updatedClient == [client EXCEPT !.height = clientHeight ] IN + \* return result with updated state [ clients |-> ICS02_SetClient(clients, clientId, updatedClient), outcome |-> "ICS02UpdateOK" @@ -64,4 +66,4 @@ ICS02_UpdateClient(clients, clientId, clientHeight) == outcome |-> "ICS02ClientNotFound" ] -============================================================================= \ No newline at end of file +=============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 73c370a042..5eaabf52a7 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -1,4 +1,4 @@ -------------------------- MODULE ICS03 -------------------------- +------------------------------ MODULE ICS03 ----------------------------------- EXTENDS Integers, FiniteSets, IBCDefinitions, ICS02 @@ -14,7 +14,13 @@ ICS03_ConnectionExists(connections, connectionId) == ICS03_SetConnection(connections, connectionId, connection) == [connections EXCEPT ![connectionId] = connection] -ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, counterpartyClientId) == +ICS03_ConnectionOpenInit( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId +) == \* check if the client exists IF ICS02_ClientExists(clients, clientId) THEN \* if the client exists, @@ -36,8 +42,13 @@ ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, co connectionId |-> connectionIdCounter, counterpartyConnectionId |-> NullConnectionId ] IN + \* return result with updated state [ - connections |-> ICS03_SetConnection(connections, connectionIdCounter, connection), + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), connectionIdCounter |-> connectionIdCounter + 1, outcome |-> "ICS03ConnectionOpenInitOK" ] @@ -49,4 +60,4 @@ ICS03_ConnectionOpenInit(clients, connections, connectionIdCounter, clientId, co outcome |-> "ICS03MissingClient" ] -============================================================================= \ No newline at end of file +=============================================================================== \ No newline at end of file From e2605bb80a657a49ba78ac01f1a20b3b92c000d5 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 12:21:29 +0100 Subject: [PATCH 024/104] s/Null/None --- modules/tests/model_based.rs | 6 +-- modules/tests/step.rs | 4 +- modules/tests/support/model_based/IBC.tla | 53 +++++++++---------- .../support/model_based/IBCDefinitions.tla | 12 ++--- modules/tests/support/model_based/ICS02.tla | 2 +- .../ICS02HeaderVerificationFailureTest.json | 4 +- .../model_based/ICS02UpdateOKTest.json | 4 +- modules/tests/support/model_based/ICS03.tla | 2 +- .../ICS03ConnectionOpenInitOKTest.json | 4 +- .../model_based/ICS03MissingClientTest.json | 4 +- 10 files changed, 46 insertions(+), 49 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index f4213fffaa..d282a8b740 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -137,12 +137,12 @@ impl modelator::TestExecutor for ICS02TestExecutor { fn initial_step(&mut self, step: Step) -> bool { assert_eq!( step.action.action_type, - ActionType::Null, + ActionType::None, "unexpected action type" ); assert_eq!( step.action_outcome, - ActionOutcome::Null, + ActionOutcome::None, "unexpected action outcome" ); true @@ -150,7 +150,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { fn next_step(&mut self, step: Step) -> bool { match step.action.action_type { - ActionType::Null => panic!("unexpected action type"), + ActionType::None => panic!("unexpected action type"), ActionType::ICS02CreateClient => { // get action parameters let chain_id = step diff --git a/modules/tests/step.rs b/modules/tests/step.rs index a84e67bb33..70aa33108f 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -28,7 +28,7 @@ pub struct Action { #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionType { - Null, + None, ICS02CreateClient, ICS02UpdateClient, ICS03ConnectionOpenInit, @@ -36,7 +36,7 @@ pub enum ActionType { #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionOutcome { - Null, + None, ICS02CreateOK, ICS02UpdateOK, ICS02ClientNotFound, diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 6ae053d9bd..03afe415e2 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -51,7 +51,7 @@ ConnectionStates == { \* data kept per cliennt Client == [ - height: ClientHeights \union {NullHeight} + height: ClientHeights \union {HeightNone} ] \* mapping from client identifier to its height Clients == [ @@ -60,10 +60,10 @@ Clients == [ \* data kept per connection Connection == [ state: ConnectionStates, - clientId: ClientIds \union {NullClientId}, - counterpartyClientId: ClientIds \union {NullClientId}, - connectionId: ConnectionIds \union {NullConnectionId}, - counterpartyConnectionId: ConnectionIds \union {NullConnectionId} + clientId: ClientIds \union {ClientIdNone}, + counterpartyClientId: ClientIds \union {ClientIdNone}, + connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} ] \* mapping from connection identifier to its data Connections == [ @@ -82,8 +82,8 @@ Chains == [ ] \* set of possible actions -NullActions == [ - type: {"Null"} +NoneActions == [ + type: {"None"} ] <: {ActionType} CreateClientActions == [ type: {"ICS02CreateClient"}, @@ -103,14 +103,14 @@ ConnectionOpenInitActions == [ counterpartyClientId: ClientIds ] <: {ActionType} Actions == - NullActions \union + NoneActions \union CreateClientActions \union UpdateClientActions \union ConnectionOpenInitActions \* set of possible action outcomes ActionOutcomes == { - "Null", + "None", "ICS02CreateOK", "ICS02UpdateOK", "ICS02ClientNotFound", @@ -137,8 +137,7 @@ CreateClient(chainId, clientHeight) == /\ action' = AsAction([ type |-> "ICS02CreateClient", chainId |-> chainId, - height |-> clientHeight - ]) + height |-> clientHeight]) /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, clientHeight) == @@ -155,8 +154,7 @@ UpdateClient(chainId, clientId, clientHeight) == type |-> "ICS02UpdateClient", chainId |-> chainId, clientId |-> clientId, - height |-> clientHeight - ]) + height |-> clientHeight]) /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == @@ -182,8 +180,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == type |-> "ICS03ConnectionOpenInit", chainId |-> chainId, clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId - ]) + counterpartyClientId |-> counterpartyClientId]) /\ actionOutcome' = result.outcome CreateClientAction == @@ -210,7 +207,7 @@ ConnectionOpenInitAction == \E chainId \in ChainIds: \* select a client id \E clientId \in ClientIds: - \* select a couterparty client id + \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* only create connection if the model constant `MaxConnectionsPerChain` \* allows it @@ -218,27 +215,27 @@ ConnectionOpenInitAction == /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) Init == - \* create a null client and a null connection - LET nullClient == [ - height |-> NullHeight + \* create a client and a connection with none values + LET clientNone == [ + height |-> HeightNone ] IN - LET nullConnection == [ + LET connectionNone == [ state |-> "Uninit", - clientId |-> NullClientId, - counterpartyClientId |-> NullClientId, - connectionId |-> NullConnectionId, - counterpartyConnectionId |-> NullConnectionId + clientId |-> ClientIdNone, + counterpartyClientId |-> ClientIdNone, + connectionId |-> ConnectionIdNone, + counterpartyConnectionId |-> ConnectionIdNone ] IN \* create an empty chain LET emptyChain == [ - clients |-> [clientId \in ClientIds |-> nullClient], + clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, - connections |-> [connectionId \in ConnectionIds |-> nullConnection], + connections |-> [connectionId \in ConnectionIds |-> connectionNone], connectionIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] - /\ action = AsAction([type |-> "Null"]) - /\ actionOutcome = "Null" + /\ action = AsAction([type |-> "None"]) + /\ actionOutcome = "None" Next == \/ CreateClientAction diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index 045395cfb8..0d5e8e2385 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -2,11 +2,11 @@ EXTENDS Integers, FiniteSets -\* if a client identifier is undefined then it is -1 -NullClientId == -1 -\* if a client identifier is undefined then it is -1 -NullHeight == -1 -\* if a connection identifier is undefined then it is -1 -NullConnectionId == -1 +\* if a client identifier is not set then it is -1 +ClientIdNone == -1 +\* if a client identifier is not set then it is -1 +HeightNone == -1 +\* if a connection identifier is not set then it is -1 +ConnectionIdNone == -1 =============================================================================== diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index ab930a382b..82d788d89e 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -8,7 +8,7 @@ ICS02_GetClient(clients, clientId) == \* check if `clientId` exists ICS02_ClientExists(clients, clientId) == - ICS02_GetClient(clients, clientId).height /= NullHeight + ICS02_GetClient(clients, clientId).height /= HeightNone \* update `clientId`'s data ICS02_SetClient(clients, clientId, client) == diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index cde46f8d20..ab10c480d5 100644 --- a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -1,9 +1,9 @@ [ { "action": { - "type": "Null" + "type": "None" }, - "actionOutcome": "Null" + "actionOutcome": "None" }, { "action": { diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json index 8a78fa3bfa..fe417e1d5c 100644 --- a/modules/tests/support/model_based/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -1,9 +1,9 @@ [ { "action": { - "type": "Null" + "type": "None" }, - "actionOutcome": "Null" + "actionOutcome": "None" }, { "action": { diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 5eaabf52a7..5228fa7242 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -40,7 +40,7 @@ ICS03_ConnectionOpenInit( clientId |-> clientId, counterpartyClientId |-> counterpartyClientId, connectionId |-> connectionIdCounter, - counterpartyConnectionId |-> NullConnectionId + counterpartyConnectionId |-> ConnectionIdNone ] IN \* return result with updated state [ diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json index 5ef27e6744..e23a2021d7 100644 --- a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json @@ -1,9 +1,9 @@ [ { "action": { - "type": "Null" + "type": "None" }, - "actionOutcome": "Null" + "actionOutcome": "None" }, { "action": { diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json index 4f180b696b..3bdd7799a5 100644 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -1,9 +1,9 @@ [ { "action": { - "type": "Null" + "type": "None" }, - "actionOutcome": "Null" + "actionOutcome": "None" }, { "action": { From 5b98a7ef7aa52217fb9b1fe6a26dd5ab14ab62ec Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 14:30:26 +0100 Subject: [PATCH 025/104] Sketch conn open try; Model chain's height --- modules/tests/support/model_based/IBC.tla | 74 +++++++++++++++++-- .../tests/support/model_based/IBCTests.cfg | 4 +- .../ICS02HeaderVerificationFailureTest.json | 30 +++++++- .../model_based/ICS02UpdateOKTest.json | 70 ++++++++++++++++-- modules/tests/support/model_based/ICS03.tla | 10 +++ .../ICS03ConnectionOpenInitOKTest.json | 34 +++++++-- .../model_based/ICS03MissingClientTest.json | 46 +++++++++++- 7 files changed, 240 insertions(+), 28 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 03afe415e2..37ec3277cc 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -6,13 +6,13 @@ EXTENDS Integers, FiniteSets, ICS02, ICS03 CONSTANT ChainIds \* max number of client to be created per chain CONSTANT MaxClientsPerChain -ASSUME MaxClientsPerChain > 0 +ASSUME MaxClientsPerChain >= 0 \* max height which clients can reach CONSTANT MaxClientHeight -ASSUME MaxClientHeight > 0 +ASSUME MaxClientHeight >= 0 \* max number of connections to be created per chain CONSTANT MaxConnectionsPerChain -ASSUME MaxConnectionsPerChain > 0 +ASSUME MaxConnectionsPerChain >= 0 \* mapping from chain id to its data VARIABLE chains @@ -20,6 +20,7 @@ VARIABLE chains VARIABLE action \* string with the outcome of the last operation VARIABLE actionOutcome +vars == <> (********************** TYPE ANNOTATIONS FOR APALACHE ************************) \* operator for type annotations @@ -35,6 +36,8 @@ ActionType == [ AsAction(a) == a <: ActionType (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) +\* set of possible chain heights +ChainHeights == Int \* set of possible client identifiers ClientIds == 0..(MaxClientsPerChain - 1) \* set of possible client heights @@ -71,6 +74,7 @@ Connections == [ ] \* data kept per chain Chain == [ + height: ChainHeights, clients: Clients, clientIdCounter: 0..MaxClientsPerChain, connections: Connections, @@ -129,6 +133,7 @@ CreateClient(chainId, clientHeight) == LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT + !.height = @ + 1, !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN @@ -146,6 +151,7 @@ UpdateClient(chainId, clientId, clientHeight) == LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT + !.height = @ + 1, !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` @@ -171,6 +177,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ) IN \* update the chain LET updatedChain == [chain EXCEPT + !.height = @ + 1, !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN @@ -183,6 +190,21 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == counterpartyClientId |-> counterpartyClientId]) /\ actionOutcome' = result.outcome +ConnectionOpenTry(chainId, clientId, counterpartyClientId, connectionId) == + LET chain == chains[chainId] IN + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN + LET result == ICS03_ConnectionOpenTry( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId, + connectionId + ) IN + UNCHANGED vars + CreateClientAction == \* select a chain id \E chainId \in ChainIds: @@ -190,8 +212,10 @@ CreateClientAction == \E clientHeight \in ClientHeights: \* only create client if the model constant `MaxClientsPerChain` allows \* it - /\ chains[chainId].clientIdCounter \in ClientIds - /\ CreateClient(chainId, clientHeight) + IF chains[chainId].clientIdCounter \in ClientIds THEN + CreateClient(chainId, clientHeight) + ELSE + UNCHANGED vars UpdateClientAction == \* select a chain id @@ -211,8 +235,40 @@ ConnectionOpenInitAction == \E counterpartyClientId \in ClientIds: \* only create connection if the model constant `MaxConnectionsPerChain` \* allows it - /\ chains[chainId].connectionIdCounter \in ConnectionIds - /\ ConnectionOpenInit(chainId, clientId, counterpartyClientId) + IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + ConnectionOpenInit(chainId, clientId, counterpartyClientId) + ELSE + UNCHANGED vars + +ConnectionOpenTryAction == + \* select a chain id + \E chainId \in ChainIds: + \* select a client id + \E clientId \in ClientIds: + \* select a counterparty client id + \E counterpartyClientId \in ClientIds: + \* select a connection id (which can be none) + \E connectionId \in ConnectionIds \union {ConnectionIdNone}: + IF connectionId = ConnectionIdNone THEN + \* in this case we're trying to create a new connection; only create + \* connection if the model constant `MaxConnectionsPerChain` allows + \* it + IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + ConnectionOpenTry( + chainId, + clientId, + counterpartyClientId, + connectionId + ) + ELSE + UNCHANGED vars + ELSE + ConnectionOpenTry( + chainId, + clientId, + counterpartyClientId, + connectionId + ) Init == \* create a client and a connection with none values @@ -228,6 +284,7 @@ Init == ] IN \* create an empty chain LET emptyChain == [ + height |-> 0, clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, connections |-> [connectionId \in ConnectionIds |-> connectionNone], @@ -241,7 +298,8 @@ Next == \/ CreateClientAction \/ UpdateClientAction \/ ConnectionOpenInitAction - \/ UNCHANGED <> + \/ ConnectionOpenTryAction + \/ UNCHANGED vars (******************************** Invariants *********************************) diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 79005a26bc..f87ef29091 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -11,6 +11,6 @@ INVARIANTS \* ICS02CreateOKTest \* ICS02UpdateOKTest \* ICS02ClientNotFoundTest - \* ICS02HeaderVerificationFailureTest - ICS03ConnectionOpenInitOKTest + ICS02HeaderVerificationFailureTest + \* ICS03ConnectionOpenInitOKTest \* ICS03MissingClientTest \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index ab10c480d5..83857d684d 100644 --- a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -3,7 +3,15 @@ "action": { "type": "None" }, - "actionOutcome": "None" + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -11,7 +19,15 @@ "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } }, { "action": { @@ -20,6 +36,14 @@ "height": 1, "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02HeaderVerificationFailure" + "actionOutcome": "ICS02HeaderVerificationFailure", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 2 + } + } } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json index fe417e1d5c..0cf02fc9c6 100644 --- a/modules/tests/support/model_based/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -3,7 +3,15 @@ "action": { "type": "None" }, - "actionOutcome": "None" + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -11,7 +19,15 @@ "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -20,7 +36,15 @@ "height": 2, "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02UpdateOK" + "actionOutcome": "ICS02UpdateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -28,7 +52,15 @@ "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -37,7 +69,15 @@ "height": 2, "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02UpdateOK" + "actionOutcome": "ICS02UpdateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -45,7 +85,15 @@ "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -54,6 +102,14 @@ "height": 2, "type": "ICS02UpdateClient" }, - "actionOutcome": "ICS02UpdateOK" + "actionOutcome": "ICS02UpdateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 5228fa7242..f8e5e6632c 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -60,4 +60,14 @@ ICS03_ConnectionOpenInit( outcome |-> "ICS03MissingClient" ] +ICS03_ConnectionOpenTry( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId, + connectionId +) == + TRUE + =============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json index e23a2021d7..9a71e469e2 100644 --- a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json @@ -3,23 +3,47 @@ "action": { "type": "None" }, - "actionOutcome": "None" + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { - "chainId": "chain-A", + "chainId": "chain-B", "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } }, { "action": { - "chainId": "chain-A", + "chainId": "chain-B", "clientId": 0, "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, - "actionOutcome": "ICS03ConnectionOpenInitOK" + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 2 + } + } } ] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json index 3bdd7799a5..c6948d035f 100644 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -3,7 +3,15 @@ "action": { "type": "None" }, - "actionOutcome": "None" + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -11,7 +19,31 @@ "height": 1, "type": "ICS02CreateClient" }, - "actionOutcome": "ICS02CreateOK" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 1 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-A", + "height": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 2 + }, + "chain-B": { + "height": 0 + } + } }, { "action": { @@ -20,6 +52,14 @@ "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, - "actionOutcome": "ICS03MissingClient" + "actionOutcome": "ICS03MissingClient", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } } ] \ No newline at end of file From 244efa6c7d372bda3d2eaad5afcf6ea4e777a486 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 14:33:35 +0100 Subject: [PATCH 026/104] Bound model space --- modules/tests/support/model_based/IBC.tla | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 37ec3277cc..26d257fb2a 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -74,7 +74,7 @@ Connections == [ ] \* data kept per chain Chain == [ - height: ChainHeights, + \* height: ChainHeights, clients: Clients, clientIdCounter: 0..MaxClientsPerChain, connections: Connections, @@ -133,7 +133,7 @@ CreateClient(chainId, clientHeight) == LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = @ + 1, + \* !.height = @ + 1, !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN @@ -151,7 +151,7 @@ UpdateClient(chainId, clientId, clientHeight) == LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = @ + 1, + \* !.height = @ + 1, !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` @@ -177,7 +177,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = @ + 1, + \* !.height = @ + 1, !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN @@ -284,7 +284,7 @@ Init == ] IN \* create an empty chain LET emptyChain == [ - height |-> 0, + \* height |-> 0, clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, connections |-> [connectionId \in ConnectionIds |-> connectionNone], From 7d9202a8331c00ea571688f89826f755619e9a58 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 15:35:55 +0100 Subject: [PATCH 027/104] Only update chain height upon success --- modules/tests/support/model_based/IBC.cfg | 1 + modules/tests/support/model_based/IBC.tla | 14 ++++++++----- .../tests/support/model_based/IBCTests.cfg | 1 + .../model_based/ICS02UpdateOKTest.json | 20 +++++++++---------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 75f117802a..0f1dcc1985 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,5 +1,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} + MaxChainHeight = 4 MaxClientsPerChain = 2 MaxClientHeight = 2 MaxConnectionsPerChain = 2 diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 26d257fb2a..49c6ae925f 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -74,7 +74,7 @@ Connections == [ ] \* data kept per chain Chain == [ - \* height: ChainHeights, + height: ChainHeights, clients: Clients, clientIdCounter: 0..MaxClientsPerChain, connections: Connections, @@ -126,6 +126,10 @@ ActionOutcomes == { (***************************** Specification *********************************) +\* update chain height if outcome was ok +UpdateHeight(height, outcome, okOutcome) == + IF outcome = okOutcome THEN height + 1 ELSE height + CreateClient(chainId, clientHeight) == LET chain == chains[chainId] IN LET clients == chain.clients IN @@ -133,7 +137,7 @@ CreateClient(chainId, clientHeight) == LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - \* !.height = @ + 1, + !.height = UpdateHeight(@, result.outcome, "ICS02CreateOK"), !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN @@ -151,7 +155,7 @@ UpdateClient(chainId, clientId, clientHeight) == LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - \* !.height = @ + 1, + !.height = UpdateHeight(@, result.outcome, "ICS03CreateOK"), !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` @@ -177,7 +181,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ) IN \* update the chain LET updatedChain == [chain EXCEPT - \* !.height = @ + 1, + !.height = UpdateHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN @@ -284,7 +288,7 @@ Init == ] IN \* create an empty chain LET emptyChain == [ - \* height |-> 0, + height |-> 0, clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, connections |-> [connectionId \in ConnectionIds |-> connectionNone], diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index f87ef29091..d5e07381b5 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,5 +1,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} + MaxChainHeight = 4 MaxClientsPerChain = 2 MaxClientHeight = 2 MaxConnectionsPerChain = 2 diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json index 0cf02fc9c6..4fbcd5ec30 100644 --- a/modules/tests/support/model_based/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -25,7 +25,7 @@ "height": 0 }, "chain-B": { - "height": 0 + "height": 1 } } }, @@ -42,7 +42,7 @@ "height": 0 }, "chain-B": { - "height": 0 + "height": 2 } } }, @@ -55,10 +55,10 @@ "actionOutcome": "ICS02CreateOK", "chains": { "chain-A": { - "height": 0 + "height": 1 }, "chain-B": { - "height": 0 + "height": 2 } } }, @@ -72,10 +72,10 @@ "actionOutcome": "ICS02UpdateOK", "chains": { "chain-A": { - "height": 0 + "height": 2 }, "chain-B": { - "height": 0 + "height": 2 } } }, @@ -88,10 +88,10 @@ "actionOutcome": "ICS02CreateOK", "chains": { "chain-A": { - "height": 0 + "height": 3 }, "chain-B": { - "height": 0 + "height": 2 } } }, @@ -105,10 +105,10 @@ "actionOutcome": "ICS02UpdateOK", "chains": { "chain-A": { - "height": 0 + "height": 4 }, "chain-B": { - "height": 0 + "height": 2 } } } From 28879f0efda68a550691f82a779860a2b9618825 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 15:44:39 +0100 Subject: [PATCH 028/104] Check that chain heights match the ones in the model --- modules/tests/model_based.rs | 74 +++++++++++++------ modules/tests/modelator.rs | 32 ++++---- modules/tests/step.rs | 8 ++ .../ICS02HeaderVerificationFailureTest.json | 2 +- .../model_based/ICS03MissingClientTest.json | 4 +- 5 files changed, 79 insertions(+), 41 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index d282a8b740..53e8622898 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -1,7 +1,6 @@ mod modelator; mod step; -use ibc::ics02_client::client_def::AnyHeader; use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use ibc::ics02_client::client_type::ClientType; use ibc::ics02_client::error::Kind as ICS02ErrorKind; @@ -24,10 +23,11 @@ use ibc::mock::context::MockContext; use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; use ibc::Height; +use ibc::{ics02_client::client_def::AnyHeader, ics18_relayer::context::ICS18Context}; use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; -use step::{ActionOutcome, ActionType, Step}; +use step::{ActionOutcome, ActionType, Chain, Step}; use tendermint::account::Id as AccountId; #[derive(Debug)] @@ -43,19 +43,33 @@ impl ICS02TestExecutor { } } - /// Find the `MockContext` of a given `chain_id`. - /// If no context is found, a new one is created. - fn get_chain_context_or_init(&mut self, chain_id: String) -> &mut MockContext { - self.contexts.entry(chain_id.clone()).or_insert_with(|| { - let max_history_size = 1; - let initial_height = 0; - MockContext::new( - ChainId::new(chain_id, Self::epoch()), - HostType::Mock, - max_history_size, - Height::new(Self::epoch(), initial_height), - ) - }) + /// Create a `MockContext` for a given `chain_id`. + /// Panic if a context for `chain_id` already exists. + fn init_chain_context(&mut self, chain_id: String, initial_height: u64) { + let max_history_size = 1; + let ctx = MockContext::new( + ChainId::new(chain_id.clone(), Self::epoch()), + HostType::Mock, + max_history_size, + Height::new(Self::epoch(), initial_height), + ); + assert!(self.contexts.insert(chain_id, ctx).is_none()); + } + + /// Returns a reference to the `MockContext` of a given `chain_id`. + /// Panic if the context for `chain_id` is not found. + fn chain_context(&self, chain_id: &String) -> &MockContext { + self.contexts + .get(chain_id) + .expect("chain context should have been initialized") + } + + /// Returns a mutable reference to the `MockContext` of a given `chain_id`. + /// Panic if the context for `chain_id` is not found. + fn chain_context_mut(&mut self, chain_id: &String) -> &mut MockContext { + self.contexts + .get_mut(chain_id) + .expect("chain context should have been initialized") } fn extract_handler_error_kind(result: Result<(), ICS18Error>) -> K @@ -100,8 +114,12 @@ impl ICS02TestExecutor { .expect("it should be possible to create the client identifier") } + fn height(height: u64) -> Height { + Height::new(Self::epoch(), height) + } + fn mock_header(height: u64) -> MockHeader { - MockHeader(Height::new(Self::epoch(), height)) + MockHeader(Self::height(height)) } fn header(height: u64) -> AnyHeader { @@ -131,6 +149,14 @@ impl ICS02TestExecutor { fn delay_period() -> u64 { 0 } + + // Check that chain heights match the ones in the model. + fn check_chain_heights(&self, chains: HashMap) -> bool { + chains.into_iter().all(|(chain_id, chain)| { + let ctx = self.chain_context(&chain_id); + ctx.query_latest_height() == Self::height(chain.height) + }) + } } impl modelator::TestExecutor for ICS02TestExecutor { @@ -145,11 +171,15 @@ impl modelator::TestExecutor for ICS02TestExecutor { ActionOutcome::None, "unexpected action outcome" ); + // initiliaze all chains + for (chain_id, chain) in step.chains { + self.init_chain_context(chain_id, chain.height); + } true } fn next_step(&mut self, step: Step) -> bool { - match step.action.action_type { + let outcome_matches = match step.action.action_type { ActionType::None => panic!("unexpected action type"), ActionType::ICS02CreateClient => { // get action parameters @@ -163,7 +193,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { .expect("create client action should have a height"); // get chain's context - let ctx = self.get_chain_context_or_init(chain_id); + let ctx = self.chain_context_mut(&chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { @@ -198,7 +228,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { .expect("update client action should have a height"); // get chain's context - let ctx = self.get_chain_context_or_init(chain_id); + let ctx = self.chain_context_mut(&chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { @@ -249,7 +279,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { ); // get chain's context - let ctx = self.get_chain_context_or_init(chain_id); + let ctx = self.chain_context_mut(&chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenInit( @@ -282,7 +312,9 @@ impl modelator::TestExecutor for ICS02TestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - } + }; + // also check that chain heights match + outcome_matches && self.check_chain_heights(step.chains) } } diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index 91d60d6800..6f0f9b7b22 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -18,30 +18,28 @@ where { // open test file let file = File::open(path.as_ref()) - .wrap_err_with(|| format!("test file {:?} not found.", path.as_ref()))?; + .wrap_err_with(|| format!("test {:?} not found.", path.as_ref()))?; let reader = BufReader::new(file); // parse test file let steps: Vec = serde_json::de::from_reader(reader) - .wrap_err_with(|| format!("test file {:?} could not be deserialized", path.as_ref()))?; + .wrap_err_with(|| format!("test {:?} could not be deserialized", path.as_ref()))?; + let step_count = steps.len(); - let mut steps = steps.into_iter(); + for (i, step) in steps.into_iter().enumerate() { + // check the step + let ok = if i == 0 { + executor.initial_step(step.clone()) + } else { + executor.next_step(step.clone()) + }; - // check the initial step - if let Some(step) = steps.next() { - if !executor.initial_step(step.clone()) { - return Err(eyre!("check failed on initial step:\n{:#?}", step)); - } - } else { - println!("WARNING: test file {:?} had 0 steps", path.as_ref()); - return Ok(()); - } - - // check the remaining steps - for step in steps { - if !executor.next_step(step.clone()) { + if !ok { return Err(eyre!( - "check failed on step:\n{:#?}\n\nexecutor:\n{:#?}", + "test {:?} failed on step {}/{}:\n{:#?}\n\nexecutor:\n{:#?}", + path.as_ref(), + i + 1, + step_count, step, executor )); diff --git a/modules/tests/step.rs b/modules/tests/step.rs index 70aa33108f..eabf76d08f 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -1,4 +1,5 @@ use serde::Deserialize; +use std::collections::HashMap; use std::fmt::Debug; #[derive(Debug, Clone, Deserialize)] @@ -7,6 +8,8 @@ pub struct Step { #[serde(alias = "actionOutcome")] pub action_outcome: ActionOutcome, + + pub chains: HashMap, } #[derive(Debug, Clone, Deserialize)] @@ -44,3 +47,8 @@ pub enum ActionOutcome { ICS03ConnectionOpenInitOK, ICS03MissingClient, } + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct Chain { + pub height: u64, +} diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index 83857d684d..2fb55f7080 100644 --- a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -42,7 +42,7 @@ "height": 0 }, "chain-B": { - "height": 2 + "height": 1 } } } diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json index c6948d035f..86e67b14d0 100644 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -55,10 +55,10 @@ "actionOutcome": "ICS03MissingClient", "chains": { "chain-A": { - "height": 0 + "height": 2 }, "chain-B": { - "height": 1 + "height": 0 } } } From a870537360e16fb5046c799e1cc6e86f01166bd1 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 16:17:41 +0100 Subject: [PATCH 029/104] Sketch conn open try --- modules/tests/model_based.rs | 8 +-- modules/tests/support/model_based/IBC.tla | 72 +++++++++++++++++---- modules/tests/support/model_based/ICS03.tla | 17 ++++- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 53e8622898..3622e61599 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -72,11 +72,11 @@ impl ICS02TestExecutor { .expect("chain context should have been initialized") } - fn extract_handler_error_kind(result: Result<(), ICS18Error>) -> K + fn extract_handler_error_kind(ics18_result: Result<(), ICS18Error>) -> K where K: Clone + Debug + Display + Into + 'static, { - let ics18_error = result.expect_err("ICS18 error expected"); + let ics18_error = ics18_result.expect_err("ICS18 error expected"); assert!(matches!( ics18_error.kind(), ICS18ErrorKind::TransactionFailed @@ -94,7 +94,7 @@ impl ICS02TestExecutor { .source() .expect("expected source in ICS26 error") .downcast_ref::>() - .expect("ICS26 source should be an error") + .expect("ICS26 source should be an handler error") .kind() .clone() } @@ -150,7 +150,7 @@ impl ICS02TestExecutor { 0 } - // Check that chain heights match the ones in the model. + /// Check that chain heights match the ones in the model. fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { let ctx = self.chain_context(&chain_id); diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 49c6ae925f..dcc21256fb 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -29,9 +29,10 @@ a <: b == a ActionType == [ type |-> STRING, chainId |-> STRING, - height |-> Int, + clientHeight |-> Int, clientId |-> Int, - counterpartyClientId |-> Int + counterpartyClientId |-> Int, + connectionId |-> Int ] AsAction(a) == a <: ActionType (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) @@ -92,13 +93,13 @@ NoneActions == [ CreateClientActions == [ type: {"ICS02CreateClient"}, chainId: ChainIds, - height: ClientHeights + clientHeight: ClientHeights ] <: {ActionType} UpdateClientActions == [ type: {"ICS02UpdateClient"}, chainId: ChainIds, clientId: ClientIds, - height: ClientHeights + clientHeight: ClientHeights ] <: {ActionType} ConnectionOpenInitActions == [ type: {"ICS03ConnectionOpenInit"}, @@ -106,28 +107,43 @@ ConnectionOpenInitActions == [ clientId: ClientIds, counterpartyClientId: ClientIds ] <: {ActionType} +ConnectionOpenTryActions == [ + type: {"ICS03ConnectionOpenTry"}, + chainId: ChainIds, + clientId: ClientIds, + clientHeight: ClientHeights, + counterpartyClientId: ClientIds, + connectionId: ConnectionIds \union {ConnectionIdNone} +] <: {ActionType} Actions == NoneActions \union CreateClientActions \union UpdateClientActions \union - ConnectionOpenInitActions + ConnectionOpenInitActions \union + ConnectionOpenTryActions \* set of possible action outcomes ActionOutcomes == { "None", + "ModelError", + \* ICS02_CreateClient outcomes: "ICS02CreateOK", + \* ICS02_UpdateClient outcomes: "ICS02UpdateOK", "ICS02ClientNotFound", "ICS02HeaderVerificationFailure", + \* ICS03_ConnectionOpenInit outcomes: "ICS03ConnectionOpenInitOK", "ICS03MissingClient", - "ModelError" + \* ICS03_ConnectionOpenTry outcomes: + "ICS03ConnectionOpenTryOK", + "ICS03InvalidConsensusHeight" } (***************************** Specification *********************************) \* update chain height if outcome was ok -UpdateHeight(height, outcome, okOutcome) == +UpdateChainHeight(height, outcome, okOutcome) == IF outcome = okOutcome THEN height + 1 ELSE height CreateClient(chainId, clientHeight) == @@ -137,7 +153,7 @@ CreateClient(chainId, clientHeight) == LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateHeight(@, result.outcome, "ICS02CreateOK"), + !.height = UpdateChainHeight(@, result.outcome, "ICS02CreateOK"), !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN @@ -146,7 +162,7 @@ CreateClient(chainId, clientHeight) == /\ action' = AsAction([ type |-> "ICS02CreateClient", chainId |-> chainId, - height |-> clientHeight]) + clientHeight |-> clientHeight]) /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, clientHeight) == @@ -155,7 +171,7 @@ UpdateClient(chainId, clientId, clientHeight) == LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateHeight(@, result.outcome, "ICS03CreateOK"), + !.height = UpdateChainHeight(@, result.outcome, "ICS03CreateOK"), !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` @@ -164,7 +180,7 @@ UpdateClient(chainId, clientId, clientHeight) == type |-> "ICS02UpdateClient", chainId |-> chainId, clientId |-> clientId, - height |-> clientHeight]) + clientHeight |-> clientHeight]) /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == @@ -181,7 +197,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), + !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN @@ -194,20 +210,44 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == counterpartyClientId |-> counterpartyClientId]) /\ actionOutcome' = result.outcome -ConnectionOpenTry(chainId, clientId, counterpartyClientId, connectionId) == +ConnectionOpenTry( + chainId, + clientId, + clientHeight, + counterpartyClientId, + connectionId +) == LET chain == chains[chainId] IN + LET height == chain.height IN LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN LET result == ICS03_ConnectionOpenTry( + height, clients, connections, connectionIdCounter, clientId, + clientHeight, counterpartyClientId, connectionId ) IN - UNCHANGED vars + \* update the chain + LET updatedChain == [chain EXCEPT + !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), + !.connections = result.connections, + !.connectionIdCounter = result.connectionIdCounter + ] IN + \* update `chains`, set the `action` and its `actionOutcome` + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([ + type |-> "ICS03ConnectionOpenTry", + chainId |-> chainId, + clientId |-> clientId, + clientHeight |-> clientHeight, + counterpartyClientId |-> counterpartyClientId, + connectionId |-> connectionId]) + /\ actionOutcome' = result.outcome CreateClientAction == \* select a chain id @@ -249,6 +289,8 @@ ConnectionOpenTryAction == \E chainId \in ChainIds: \* select a client id \E clientId \in ClientIds: + \* select a claimed height for the client + \E clientHeight \in ClientHeights: \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* select a connection id (which can be none) @@ -261,6 +303,7 @@ ConnectionOpenTryAction == ConnectionOpenTry( chainId, clientId, + clientHeight, counterpartyClientId, connectionId ) @@ -270,6 +313,7 @@ ConnectionOpenTryAction == ConnectionOpenTry( chainId, clientId, + clientHeight, counterpartyClientId, connectionId ) diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index f8e5e6632c..c3d1d675bb 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -61,13 +61,28 @@ ICS03_ConnectionOpenInit( ] ICS03_ConnectionOpenTry( + height, clients, connections, connectionIdCounter, clientId, + clientHeight, counterpartyClientId, connectionId ) == - TRUE + \* check if client's claimed height + IF clientHeight > height THEN + \* if client's height is too advanced, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03InvalidConsensusHeight" + ] + ELSE + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionOpenTryOK" + ] =============================================================================== \ No newline at end of file From a533def051d856b4902debd0e8c6166a18349486 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 19:00:51 +0100 Subject: [PATCH 030/104] Sketch conn open try --- modules/src/ics24_host/identifier.rs | 14 ++ modules/src/mock/context.rs | 16 +- modules/tests/model_based.rs | 138 +++++++++++++++--- modules/tests/step.rs | 28 +++- modules/tests/support/model_based/IBC.cfg | 1 - .../tests/support/model_based/IBCTests.cfg | 7 +- .../tests/support/model_based/IBCTests.tla | 8 + .../ICS02HeaderVerificationFailureTest.json | 4 +- .../model_based/ICS02UpdateOKTest.json | 12 +- .../ICS03ConnectionOpenInitOKTest.json | 2 +- .../ICS03InvalidConsensusHeightTest.json | 35 +++++ .../model_based/ICS03MissingClientTest.json | 4 +- 12 files changed, 222 insertions(+), 47 deletions(-) create mode 100644 modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index e76c9f7d60..965d04038b 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -197,6 +197,13 @@ impl PartialEq for ClientId { pub struct ConnectionId(String); impl ConnectionId { + /// Builds a new connection identifier. + pub fn new(counter: u64) -> Result { + let prefix = "connection"; + let id = format!("{}-{}", prefix, counter); + Self::from_str(id.as_str()) + } + /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 @@ -283,6 +290,13 @@ impl Default for PortId { pub struct ChannelId(String); impl ChannelId { + /// Builds a new channel identifier. + pub fn new(counter: u64) -> Result { + let prefix = "channel"; + let id = format!("{}-{}", prefix, counter); + Self::from_str(id.as_str()) + } + /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index c656363513..6bb829924e 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -88,10 +88,10 @@ pub struct MockContext { port_capabilities: HashMap, /// Counter for connection identifiers (see `next_connection_id`). - connection_ids_counter: u32, + connection_ids_counter: u64, /// Counter for channel identifiers (see `next_channel_id`). - channel_ids_counter: u32, + channel_ids_counter: u64, } /// Returns a MockContext with bare minimum initialization: no clients, no connections and no channels are @@ -392,11 +392,9 @@ impl ChannelReader for MockContext { impl ChannelKeeper for MockContext { fn next_channel_id(&mut self) -> ChannelId { - let prefix = ChannelId::default().to_string(); - let suffix = self.channel_ids_counter; + let counter = self.channel_ids_counter; self.channel_ids_counter += 1; - - ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() + ChannelId::new(counter).unwrap() } fn store_channel( @@ -497,11 +495,9 @@ impl ConnectionReader for MockContext { impl ConnectionKeeper for MockContext { fn next_connection_id(&mut self) -> ConnectionId { - let prefix = ConnectionId::default().to_string(); - let suffix = self.connection_ids_counter; + let counter = self.connection_ids_counter; self.connection_ids_counter += 1; - - ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() + ConnectionId::new(counter).unwrap() } fn store_connection( diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 3622e61599..7740f7d50d 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -10,23 +10,25 @@ use ibc::ics02_client::msgs::ClientMsg; use ibc::ics03_connection::connection::Counterparty; use ibc::ics03_connection::error::Kind as ICS03ErrorKind; use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use ibc::ics03_connection::msgs::ConnectionMsg; use ibc::ics03_connection::version::Version; use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; use ibc::ics23_commitment::commitment::CommitmentPrefix; -use ibc::ics24_host::identifier::ChainId; -use ibc::ics24_host::identifier::ClientId; +use ibc::ics23_commitment::commitment::CommitmentProofBytes; +use ibc::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; use ibc::ics26_routing::msgs::ICS26Envelope; use ibc::mock::client_state::{MockClientState, MockConsensusState}; use ibc::mock::context::MockContext; use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; +use ibc::proofs::{ConsensusProof, Proofs}; use ibc::Height; use ibc::{ics02_client::client_def::AnyHeader, ics18_relayer::context::ICS18Context}; -use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; +use std::{collections::HashMap, vec}; use step::{ActionOutcome, ActionType, Chain, Step}; use tendermint::account::Id as AccountId; @@ -109,11 +111,20 @@ impl ICS02TestExecutor { Version::default() } + fn versions() -> Vec { + vec![Self::version()] + } + fn client_id(client_id: u64) -> ClientId { ClientId::new(ClientType::Mock, client_id) .expect("it should be possible to create the client identifier") } + fn connection_id(connection_id: u64) -> ConnectionId { + ConnectionId::new(connection_id) + .expect("it should be possible to create the connection identifier") + } + fn height(height: u64) -> Height { Height::new(Self::epoch(), height) } @@ -139,17 +150,47 @@ impl ICS02TestExecutor { } fn counterparty(counterparty_client_id: u64) -> Counterparty { - Counterparty::new( - Self::client_id(counterparty_client_id), - None, - CommitmentPrefix(Vec::new()), - ) + let client_id = Self::client_id(counterparty_client_id); + let connection_id = None; + let prefix = Self::commitment_prefix(); + Counterparty::new(client_id, connection_id, prefix) } fn delay_period() -> u64 { 0 } + fn commitment_prefix() -> CommitmentPrefix { + CommitmentPrefix(Vec::new()) + } + + fn commitment_proof_bytes() -> CommitmentProofBytes { + vec![0].into() + } + + fn consensus_proof(height: u64) -> ConsensusProof { + let consensus_proof = Self::commitment_proof_bytes(); + let consensus_height = Self::height(height); + ConsensusProof::new(consensus_proof, consensus_height) + .expect("it should be possible to create the consensus proof") + } + + fn proofs(height: u64) -> Proofs { + let object_proof = Self::commitment_proof_bytes(); + let client_proof = None; + let consensus_proof = Some(Self::consensus_proof(height)); + let other_proof = None; + let height = Self::height(height); + Proofs::new( + object_proof, + client_proof, + consensus_proof, + other_proof, + height, + ) + .expect("it should be possible to create the proofs") + } + /// Check that chain heights match the ones in the model. fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { @@ -179,6 +220,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { } fn next_step(&mut self, step: Step) -> bool { + println!("{:?}", step); let outcome_matches = match step.action.action_type { ActionType::None => panic!("unexpected action type"), ActionType::ICS02CreateClient => { @@ -187,18 +229,18 @@ impl modelator::TestExecutor for ICS02TestExecutor { .action .chain_id .expect("create client action should have a chain identifier"); - let height = step + let client_height = step .action - .height - .expect("create client action should have a height"); + .client_height + .expect("create client action should have a client height"); // get chain's context let ctx = self.chain_context_mut(&chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { - client_state: Self::client_state(height), - consensus_state: Self::consensus_state(height), + client_state: Self::client_state(client_height), + consensus_state: Self::consensus_state(client_height), signer: Self::signer(), })); let result = ctx.deliver(msg); @@ -222,10 +264,10 @@ impl modelator::TestExecutor for ICS02TestExecutor { .action .client_id .expect("update client action should have a client identifier"); - let height = step + let client_height = step .action - .height - .expect("update client action should have a height"); + .client_height + .expect("update client action should have a client height"); // get chain's context let ctx = self.chain_context_mut(&chain_id); @@ -233,7 +275,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { client_id: Self::client_id(client_id), - header: Self::header(height), + header: Self::header(client_height), signer: Self::signer(), })); let result = ctx.deliver(msg); @@ -251,7 +293,8 @@ impl modelator::TestExecutor for ICS02TestExecutor { // error matching the expected outcome matches!( handler_error_kind, - ICS02ErrorKind::ClientNotFound(id) if id == Self::client_id(client_id) + ICS02ErrorKind::ClientNotFound(error_client_id) + if error_client_id == Self::client_id(client_id) ) } ActionOutcome::ICS02HeaderVerificationFailure => { @@ -306,9 +349,64 @@ impl modelator::TestExecutor for ICS02TestExecutor { // error matching the expected outcome matches!( handler_error_kind, - ICS03ErrorKind::MissingClient(id) if id == Self::client_id(client_id) + ICS03ErrorKind::MissingClient(error_client_id) + if error_client_id == Self::client_id(client_id) + ) + } + action => panic!("unexpected action outcome {:?}", action), + } + } + ActionType::ICS03ConnectionOpenTry => { + // get action parameters + let chain_id = step + .action + .chain_id + .expect("connection open init action should have a chain identifier"); + let client_id = step + .action + .client_id + .expect("connection open init action should have a client identifier"); + let client_height = step + .action + .client_height + .expect("connection open try action should have a client height"); + let counterparty_client_id = step.action.counterparty_client_id.expect( + "connection open init action should have a counterparty client identifier", + ); + let connection_id = step.action.connection_id; + + // get chain's context + let ctx = self.chain_context_mut(&chain_id); + + // create ICS26 message and deliver it + let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( + MsgConnectionOpenTry { + previous_connection_id: connection_id.map(Self::connection_id), + client_id: Self::client_id(client_id), + client_state: None, + counterparty: Self::counterparty(counterparty_client_id), + counterparty_versions: Self::versions(), + proofs: Self::proofs(client_height), + delay_period: Self::delay_period(), + signer: Self::signer(), + }, + ))); + let result = ctx.deliver(msg); + + // check the expected outcome + match step.action_outcome { + ActionOutcome::ICS03InvalidConsensusHeight => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + matches!( + handler_error_kind, + ICS03ErrorKind::InvalidConsensusHeight(error_consensus_height, _) + if error_consensus_height == Self::height(client_height) ) } + action => panic!("unexpected action outcome {:?}", action), } } @@ -327,6 +425,8 @@ fn main() { "ICS02HeaderVerificationFailureTest", "ICS03ConnectionOpenInitOKTest", "ICS03MissingClientTest", + "ICS03MissingClientTest", + "ICS03InvalidConsensusHeightTest", ]; for test in tests { diff --git a/modules/tests/step.rs b/modules/tests/step.rs index eabf76d08f..85935ab09e 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -1,4 +1,4 @@ -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; use std::collections::HashMap; use std::fmt::Debug; @@ -20,13 +20,33 @@ pub struct Action { #[serde(alias = "chainId")] pub chain_id: Option, - pub height: Option, - #[serde(alias = "clientId")] pub client_id: Option, + #[serde(alias = "clientHeight")] + pub client_height: Option, + #[serde(alias = "counterpartyClientId")] pub counterparty_client_id: Option, + + #[serde(alias = "connectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + pub connection_id: Option, +} + +/// On the model, a non-existing `connection_id` is represented with -1. +/// For this reason, this function maps a `Some(-1)` to a `None`. +fn deserialize_connection_id<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let connection_id: Option = Deserialize::deserialize(deserializer)?; + let connection_id = if connection_id == Some(-1) { + None + } else { + connection_id.map(|connection_id| connection_id as u64) + }; + Ok(connection_id) } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -35,6 +55,7 @@ pub enum ActionType { ICS02CreateClient, ICS02UpdateClient, ICS03ConnectionOpenInit, + ICS03ConnectionOpenTry, } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -46,6 +67,7 @@ pub enum ActionOutcome { ICS02HeaderVerificationFailure, ICS03ConnectionOpenInitOK, ICS03MissingClient, + ICS03InvalidConsensusHeight, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 0f1dcc1985..75f117802a 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,6 +1,5 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxChainHeight = 4 MaxClientsPerChain = 2 MaxClientHeight = 2 MaxConnectionsPerChain = 2 diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index d5e07381b5..93d056dc99 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,6 +1,5 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxChainHeight = 4 MaxClientsPerChain = 2 MaxClientHeight = 2 MaxConnectionsPerChain = 2 @@ -12,6 +11,8 @@ INVARIANTS \* ICS02CreateOKTest \* ICS02UpdateOKTest \* ICS02ClientNotFoundTest - ICS02HeaderVerificationFailureTest + \* ICS02HeaderVerificationFailureTest \* ICS03ConnectionOpenInitOKTest - \* ICS03MissingClientTest \ No newline at end of file + \* ICS03MissingClientTest + \* ICS03ConnectionOpenTryOKTest + ICS03InvalidConsensusHeightTest \ No newline at end of file diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 5165bf50b9..12ba4da0f2 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -20,11 +20,19 @@ ICS03ConnectionOpenInitOK == ICS03MissingClient == /\ actionOutcome = "ICS03MissingClient" +ICS03ConnectionOpenTryOK == + /\ actionOutcome = "ICS03ConnectionOpenTryOK" + +ICS03InvalidConsensusHeight == + /\ actionOutcome = "ICS03InvalidConsensusHeight" + ICS02CreateOKTest == ~ICS02CreateOK ICS02UpdateOKTest == ~ICS02UpdateOK ICS02ClientNotFoundTest == ~ICS02ClientNotFound ICS02HeaderVerificationFailureTest == ~ICS02HeaderVerificationFailure ICS03ConnectionOpenInitOKTest == ~ICS03ConnectionOpenInitOK ICS03MissingClientTest == ~ICS03MissingClient +ICS03ConnectionOpenTryOKTest == ~ICS03ConnectionOpenTryOK +ICS03InvalidConsensusHeightTest == ~ICS03InvalidConsensusHeight =============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index 2fb55f7080..9947b27078 100644 --- a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -16,7 +16,7 @@ { "action": { "chainId": "chain-B", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -33,7 +33,7 @@ "action": { "chainId": "chain-B", "clientId": 0, - "height": 1, + "clientHeight": 1, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02HeaderVerificationFailure", diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json index 4fbcd5ec30..33e67f0967 100644 --- a/modules/tests/support/model_based/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -16,7 +16,7 @@ { "action": { "chainId": "chain-B", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -33,7 +33,7 @@ "action": { "chainId": "chain-B", "clientId": 0, - "height": 2, + "clientHeight": 2, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", @@ -49,7 +49,7 @@ { "action": { "chainId": "chain-A", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -66,7 +66,7 @@ "action": { "chainId": "chain-A", "clientId": 0, - "height": 2, + "clientHeight": 2, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", @@ -82,7 +82,7 @@ { "action": { "chainId": "chain-A", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -99,7 +99,7 @@ "action": { "chainId": "chain-A", "clientId": 1, - "height": 2, + "clientHeight": 2, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json index 9a71e469e2..14fe580531 100644 --- a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json @@ -16,7 +16,7 @@ { "action": { "chainId": "chain-B", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", diff --git a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json new file mode 100644 index 0000000000..8e4a6553fb --- /dev/null +++ b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json @@ -0,0 +1,35 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-A", + "clientId": 0, + "clientHeight": 1, + "connectionId": -1, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03InvalidConsensusHeight", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json index 86e67b14d0..bfec803cd7 100644 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -16,7 +16,7 @@ { "action": { "chainId": "chain-A", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -32,7 +32,7 @@ { "action": { "chainId": "chain-A", - "height": 1, + "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", From 1cdb02a242ade2ed70537f65b17cdd9b8a969824 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 19:51:10 +0100 Subject: [PATCH 031/104] Model missing connections and connection mismatches in conn open try --- modules/tests/model_based.rs | 27 ++++- modules/tests/step.rs | 2 + modules/tests/support/model_based/IBC.tla | 4 +- .../tests/support/model_based/IBCTests.cfg | 4 +- .../tests/support/model_based/IBCTests.tla | 8 ++ modules/tests/support/model_based/ICS03.tla | 106 ++++++++++++++++-- .../ICS03ConnectionMismatchTest.json | 68 +++++++++++ .../ICS03ConnectionNotFoundTest.json | 51 +++++++++ 8 files changed, 257 insertions(+), 13 deletions(-) create mode 100644 modules/tests/support/model_based/ICS03ConnectionMismatchTest.json create mode 100644 modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 7740f7d50d..368fae334c 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -406,7 +406,30 @@ impl modelator::TestExecutor for ICS02TestExecutor { if error_consensus_height == Self::height(client_height) ) } - + ActionOutcome::ICS03ConnectionNotFound => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + connection_id.is_some() + && matches!( + handler_error_kind, + ICS03ErrorKind::ConnectionNotFound(error_connection_id) + if error_connection_id == Self::connection_id(connection_id.unwrap()) + ) + } + ActionOutcome::ICS03ConnectionMismatch => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + connection_id.is_some() + && matches!( + handler_error_kind, + ICS03ErrorKind::ConnectionMismatch(error_connection_id) + if error_connection_id == Self::connection_id(connection_id.unwrap()) + ) + } action => panic!("unexpected action outcome {:?}", action), } } @@ -427,6 +450,8 @@ fn main() { "ICS03MissingClientTest", "ICS03MissingClientTest", "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", ]; for test in tests { diff --git a/modules/tests/step.rs b/modules/tests/step.rs index 85935ab09e..2b54c109e0 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -68,6 +68,8 @@ pub enum ActionOutcome { ICS03ConnectionOpenInitOK, ICS03MissingClient, ICS03InvalidConsensusHeight, + ICS03ConnectionNotFound, + ICS03ConnectionMismatch, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index dcc21256fb..0f6676e8a1 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -137,7 +137,9 @@ ActionOutcomes == { "ICS03MissingClient", \* ICS03_ConnectionOpenTry outcomes: "ICS03ConnectionOpenTryOK", - "ICS03InvalidConsensusHeight" + "ICS03InvalidConsensusHeight", + "ICS03ConnectionNotFound", + "ICS03ConnectionMismatch" } (***************************** Specification *********************************) diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 93d056dc99..9f501b448a 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -15,4 +15,6 @@ INVARIANTS \* ICS03ConnectionOpenInitOKTest \* ICS03MissingClientTest \* ICS03ConnectionOpenTryOKTest - ICS03InvalidConsensusHeightTest \ No newline at end of file + \* ICS03InvalidConsensusHeightTest + \* ICS03ConnectionNotFoundTest + ICS03ConnectionMismatchTest \ No newline at end of file diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 12ba4da0f2..0d7e352217 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -26,6 +26,12 @@ ICS03ConnectionOpenTryOK == ICS03InvalidConsensusHeight == /\ actionOutcome = "ICS03InvalidConsensusHeight" +ICS03ConnectionNotFound == + /\ actionOutcome = "ICS03ConnectionNotFound" + +ICS03ConnectionMismatch == + /\ actionOutcome = "ICS03ConnectionMismatch" + ICS02CreateOKTest == ~ICS02CreateOK ICS02UpdateOKTest == ~ICS02UpdateOK ICS02ClientNotFoundTest == ~ICS02ClientNotFound @@ -34,5 +40,7 @@ ICS03ConnectionOpenInitOKTest == ~ICS03ConnectionOpenInitOK ICS03MissingClientTest == ~ICS03MissingClient ICS03ConnectionOpenTryOKTest == ~ICS03ConnectionOpenTryOK ICS03InvalidConsensusHeightTest == ~ICS03InvalidConsensusHeight +ICS03ConnectionNotFoundTest == ~ICS03ConnectionNotFound +ICS03ConnectionMismatchTest == ~ICS03ConnectionMismatch =============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index c3d1d675bb..04fd29863b 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -60,29 +60,115 @@ ICS03_ConnectionOpenInit( outcome |-> "ICS03MissingClient" ] -ICS03_ConnectionOpenTry( - height, +ICS03_ConnectionOpenTry_1( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + counterpartyClientId, + connectionId +) == + \* TODO check that all parameters are still needed + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionOpenTryOK" + ] + +ICS03_ConnectionOpenTry_0( + chainHeight, clients, connections, connectionIdCounter, clientId, - clientHeight, + clientClaimedHeight, counterpartyClientId, connectionId ) == - \* check if client's claimed height - IF clientHeight > height THEN + \* check if client's claimed height is higher than the chain's height + IF clientClaimedHeight > chainHeight THEN \* if client's height is too advanced, then set an error outcome [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, outcome |-> "ICS03InvalidConsensusHeight" ] + \* TODO: add `chain_max_history_size` to the model to be able to also + \* return a `ICS03StaleConsensusHeight` error outcome ELSE - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03ConnectionOpenTryOK" - ] + \* check if a `connectionId` was set + IF connectionId /= ConnectionIdNone THEN + \* if so, check if the connection exists + IF ICS03_ConnectionExists(connections, connectionId) THEN + \* if the connection exists, verify that is matches the + \* the parameters provided + LET connection == ICS03_GetConnection( + connections, + connectionId + ) IN + IF /\ connection.state = "Init" + /\ connection.clientId = clientId + /\ connection.counterpartyClientId = counterpartyClientId + THEN + \* initial verification passed; move to step 1 + ICS03_ConnectionOpenTry_1( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + counterpartyClientId, + connectionId + ) + ELSE + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionMismatch" + ] + ELSE + \* if the connection does not exist, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionNotFound" + ] + ELSE + \* initial verification passed; move to step 1 + ICS03_ConnectionOpenTry_1( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + counterpartyClientId, + connectionId + ) + +ICS03_ConnectionOpenTry( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + counterpartyClientId, + connectionId +) == + \* start step 0 + ICS03_ConnectionOpenTry_0( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + counterpartyClientId, + connectionId + ) =============================================================================== \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json new file mode 100644 index 0000000000..41a6394b0a --- /dev/null +++ b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json @@ -0,0 +1,68 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-B", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } + }, + { + "action": { + "chainId": "chain-B", + "clientId": 0, + "counterpartyClientId": 1, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 2 + } + } + }, + { + "action": { + "chainId": "chain-B", + "clientId": 1, + "clientHeight": 2, + "connectionId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionMismatch", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 2 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json new file mode 100644 index 0000000000..7d8ea34d92 --- /dev/null +++ b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json @@ -0,0 +1,51 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-B", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } + }, + { + "action": { + "chainId": "chain-B", + "clientId": 0, + "clientHeight": 1, + "connectionId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionNotFound", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 1 + } + } + } +] \ No newline at end of file From 0186a1c2da296f5cc2f01983b5a0469c00f34e38 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 22:01:48 +0100 Subject: [PATCH 032/104] Trigger bug in conn open try --- modules/tests/TODO | 3 + modules/tests/model_based.rs | 41 ++++--- modules/tests/step.rs | 5 + modules/tests/support/model_based/IBC.cfg | 2 +- modules/tests/support/model_based/IBC.tla | 33 ++++-- .../tests/support/model_based/IBCTests.cfg | 6 +- .../tests/support/model_based/IBCTests.tla | 2 +- modules/tests/support/model_based/ICS02.tla | 4 +- .../ICS02HeaderVerificationFailureTest.json | 2 +- .../model_based/ICS02UpdateOKTest.json | 6 +- modules/tests/support/model_based/ICS03.tla | 112 ++++++++---------- .../ICS03ConnectionMismatchTest.json | 4 +- .../ICS03ConnectionNotFoundTest.json | 4 +- .../ICS03ConnectionOpenInitOKTest.json | 2 +- .../ICS03ConnectionOpenTryOKTest.json | 52 ++++++++ .../ICS03InvalidConsensusHeightTest.json | 2 +- .../model_based/ICS03MissingClientTest.json | 2 +- 17 files changed, 173 insertions(+), 109 deletions(-) create mode 100644 modules/tests/TODO create mode 100644 modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json diff --git a/modules/tests/TODO b/modules/tests/TODO new file mode 100644 index 0000000000..b86a736905 --- /dev/null +++ b/modules/tests/TODO @@ -0,0 +1,3 @@ +- conn open try does not increment the connection id counter; looks like a bug +- the model allows a conn open try to succeed without a conn open try (likely because we don't have proofs) +- TLC doesn't finish with `MaxClientsPerChain = 2` diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 368fae334c..9d2566345c 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -1,7 +1,7 @@ mod modelator; mod step; -use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; +use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState, AnyHeader}; use ibc::ics02_client::client_type::ClientType; use ibc::ics02_client::error::Kind as ICS02ErrorKind; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; @@ -13,9 +13,9 @@ use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use ibc::ics03_connection::msgs::ConnectionMsg; use ibc::ics03_connection::version::Version; +use ibc::ics18_relayer::context::ICS18Context; use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; -use ibc::ics23_commitment::commitment::CommitmentPrefix; -use ibc::ics23_commitment::commitment::CommitmentProofBytes; +use ibc::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes}; use ibc::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; use ibc::ics26_routing::msgs::ICS26Envelope; @@ -25,10 +25,9 @@ use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; use ibc::proofs::{ConsensusProof, Proofs}; use ibc::Height; -use ibc::{ics02_client::client_def::AnyHeader, ics18_relayer::context::ICS18Context}; +use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; -use std::{collections::HashMap, vec}; use step::{ActionOutcome, ActionType, Chain, Step}; use tendermint::account::Id as AccountId; @@ -149,9 +148,9 @@ impl ICS02TestExecutor { AccountId::new([0; 20]) } - fn counterparty(counterparty_client_id: u64) -> Counterparty { - let client_id = Self::client_id(counterparty_client_id); - let connection_id = None; + fn counterparty(client_id: u64, connection_id: Option) -> Counterparty { + let client_id = Self::client_id(client_id); + let connection_id = connection_id.map(|connection_id| Self::connection_id(connection_id)); let prefix = Self::commitment_prefix(); Counterparty::new(client_id, connection_id, prefix) } @@ -161,7 +160,7 @@ impl ICS02TestExecutor { } fn commitment_prefix() -> CommitmentPrefix { - CommitmentPrefix(Vec::new()) + vec![0].into() } fn commitment_proof_bytes() -> CommitmentProofBytes { @@ -328,7 +327,7 @@ impl modelator::TestExecutor for ICS02TestExecutor { let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenInit( MsgConnectionOpenInit { client_id: Self::client_id(client_id), - counterparty: Self::counterparty(counterparty_client_id), + counterparty: Self::counterparty(counterparty_client_id, None), version: Self::version(), delay_period: Self::delay_period(), signer: Self::signer(), @@ -361,19 +360,22 @@ impl modelator::TestExecutor for ICS02TestExecutor { let chain_id = step .action .chain_id - .expect("connection open init action should have a chain identifier"); + .expect("connection open try action should have a chain identifier"); let client_id = step .action .client_id - .expect("connection open init action should have a client identifier"); + .expect("connection open try action should have a client identifier"); let client_height = step .action .client_height .expect("connection open try action should have a client height"); let counterparty_client_id = step.action.counterparty_client_id.expect( - "connection open init action should have a counterparty client identifier", + "connection open try action should have a counterparty client identifier", ); let connection_id = step.action.connection_id; + let counterparty_connection_id = step.action.counterparty_connection_id.expect( + "connection open try action should have a counterparty connection identifier", + ); // get chain's context let ctx = self.chain_context_mut(&chain_id); @@ -384,17 +386,24 @@ impl modelator::TestExecutor for ICS02TestExecutor { previous_connection_id: connection_id.map(Self::connection_id), client_id: Self::client_id(client_id), client_state: None, - counterparty: Self::counterparty(counterparty_client_id), + counterparty: Self::counterparty( + counterparty_client_id, + Some(counterparty_connection_id), + ), counterparty_versions: Self::versions(), proofs: Self::proofs(client_height), delay_period: Self::delay_period(), signer: Self::signer(), }, ))); - let result = ctx.deliver(msg); + let result = dbg!(ctx.deliver(msg)); // check the expected outcome match step.action_outcome { + ActionOutcome::ICS03ConnectionOpenTryOK => { + // the implementaion matches the model if no error occurs + result.is_ok() + } ActionOutcome::ICS03InvalidConsensusHeight => { let handler_error_kind = Self::extract_handler_error_kind::(result); @@ -448,7 +457,7 @@ fn main() { "ICS02HeaderVerificationFailureTest", "ICS03ConnectionOpenInitOKTest", "ICS03MissingClientTest", - "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", diff --git a/modules/tests/step.rs b/modules/tests/step.rs index 2b54c109e0..67f97882bc 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -32,6 +32,10 @@ pub struct Action { #[serde(alias = "connectionId")] #[serde(default, deserialize_with = "deserialize_connection_id")] pub connection_id: Option, + + #[serde(alias = "counterpartyConnectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + pub counterparty_connection_id: Option, } /// On the model, a non-existing `connection_id` is represented with -1. @@ -67,6 +71,7 @@ pub enum ActionOutcome { ICS02HeaderVerificationFailure, ICS03ConnectionOpenInitOK, ICS03MissingClient, + ICS03ConnectionOpenTryOK, ICS03InvalidConsensusHeight, ICS03ConnectionNotFound, ICS03ConnectionMismatch, diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 75f117802a..25f40c9106 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxClientsPerChain = 2 + MaxClientsPerChain = 1 MaxClientHeight = 2 MaxConnectionsPerChain = 2 diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 0f6676e8a1..89ddfe6de2 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -31,8 +31,9 @@ ActionType == [ chainId |-> STRING, clientHeight |-> Int, clientId |-> Int, + connectionId |-> Int, counterpartyClientId |-> Int, - connectionId |-> Int + counterpartyConnectionId |-> Int ] AsAction(a) == a <: ActionType (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) @@ -98,8 +99,8 @@ CreateClientActions == [ UpdateClientActions == [ type: {"ICS02UpdateClient"}, chainId: ChainIds, - clientId: ClientIds, - clientHeight: ClientHeights + clientHeight: ClientHeights, + clientId: ClientIds ] <: {ActionType} ConnectionOpenInitActions == [ type: {"ICS03ConnectionOpenInit"}, @@ -110,10 +111,11 @@ ConnectionOpenInitActions == [ ConnectionOpenTryActions == [ type: {"ICS03ConnectionOpenTry"}, chainId: ChainIds, - clientId: ClientIds, clientHeight: ClientHeights, + clientId: ClientIds, counterpartyClientId: ClientIds, - connectionId: ConnectionIds \union {ConnectionIdNone} + connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyConnectionId: ConnectionIds ] <: {ActionType} Actions == NoneActions \union @@ -216,8 +218,9 @@ ConnectionOpenTry( chainId, clientId, clientHeight, + connectionId, counterpartyClientId, - connectionId + counterpartyConnectionId ) == LET chain == chains[chainId] IN LET height == chain.height IN @@ -231,8 +234,9 @@ ConnectionOpenTry( connectionIdCounter, clientId, clientHeight, + connectionId, counterpartyClientId, - connectionId + counterpartyConnectionId ) IN \* update the chain LET updatedChain == [chain EXCEPT @@ -247,8 +251,9 @@ ConnectionOpenTry( chainId |-> chainId, clientId |-> clientId, clientHeight |-> clientHeight, + connectionId |-> connectionId, counterpartyClientId |-> counterpartyClientId, - connectionId |-> connectionId]) + counterpartyConnectionId |-> counterpartyConnectionId]) /\ actionOutcome' = result.outcome CreateClientAction == @@ -293,10 +298,12 @@ ConnectionOpenTryAction == \E clientId \in ClientIds: \* select a claimed height for the client \E clientHeight \in ClientHeights: - \* select a counterparty client id - \E counterpartyClientId \in ClientIds: \* select a connection id (which can be none) \E connectionId \in ConnectionIds \union {ConnectionIdNone}: + \* select a counterparty client id + \E counterpartyClientId \in ClientIds: + \* select a counterparty connection id + \E counterpartyConnectionId \in ConnectionIds: IF connectionId = ConnectionIdNone THEN \* in this case we're trying to create a new connection; only create \* connection if the model constant `MaxConnectionsPerChain` allows @@ -306,8 +313,9 @@ ConnectionOpenTryAction == chainId, clientId, clientHeight, + connectionId, counterpartyClientId, - connectionId + counterpartyConnectionId ) ELSE UNCHANGED vars @@ -316,8 +324,9 @@ ConnectionOpenTryAction == chainId, clientId, clientHeight, + connectionId, counterpartyClientId, - connectionId + counterpartyConnectionId ) Init == diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 9f501b448a..4090d7a7f4 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} - MaxClientsPerChain = 2 + MaxClientsPerChain = 1 MaxClientHeight = 2 MaxConnectionsPerChain = 2 @@ -14,7 +14,7 @@ INVARIANTS \* ICS02HeaderVerificationFailureTest \* ICS03ConnectionOpenInitOKTest \* ICS03MissingClientTest - \* ICS03ConnectionOpenTryOKTest + ICS03ConnectionOpenTryOKTest \* ICS03InvalidConsensusHeightTest \* ICS03ConnectionNotFoundTest - ICS03ConnectionMismatchTest \ No newline at end of file + \* ICS03ConnectionMismatchTest diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 0d7e352217..35127df6ae 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -43,4 +43,4 @@ ICS03InvalidConsensusHeightTest == ~ICS03InvalidConsensusHeight ICS03ConnectionNotFoundTest == ~ICS03ConnectionNotFound ICS03ConnectionMismatchTest == ~ICS03ConnectionMismatch -=============================================================================== \ No newline at end of file +=============================================================================== diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 82d788d89e..84fa0c4727 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -65,5 +65,7 @@ ICS02_UpdateClient(clients, clientId, clientHeight) == clients |-> clients, outcome |-> "ICS02ClientNotFound" ] + \* TODO: distinguish between client state and consensus state to also be + \* able to return a `ConsensusStateNotFound` error outcome -=============================================================================== \ No newline at end of file +=============================================================================== diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json index 9947b27078..dbad8fc3ba 100644 --- a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json @@ -32,8 +32,8 @@ { "action": { "chainId": "chain-B", - "clientId": 0, "clientHeight": 1, + "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02HeaderVerificationFailure", diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/ICS02UpdateOKTest.json index 33e67f0967..309d6aa953 100644 --- a/modules/tests/support/model_based/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/ICS02UpdateOKTest.json @@ -32,8 +32,8 @@ { "action": { "chainId": "chain-B", - "clientId": 0, "clientHeight": 2, + "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", @@ -65,8 +65,8 @@ { "action": { "chainId": "chain-A", - "clientId": 0, "clientHeight": 2, + "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", @@ -98,8 +98,8 @@ { "action": { "chainId": "chain-A", - "clientId": 1, "clientHeight": 2, + "clientId": 1, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 04fd29863b..e9b3096a7f 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -60,32 +60,18 @@ ICS03_ConnectionOpenInit( outcome |-> "ICS03MissingClient" ] -ICS03_ConnectionOpenTry_1( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - counterpartyClientId, - connectionId -) == - \* TODO check that all parameters are still needed - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03ConnectionOpenTryOK" - ] - -ICS03_ConnectionOpenTry_0( +\* TODO: errors generated when verifying proofs are never an outcome of this +\* model +ICS03_ConnectionOpenTry( chainHeight, clients, connections, connectionIdCounter, clientId, clientClaimedHeight, + connectionId, counterpartyClientId, - connectionId + counterpartyConnectionId ) == \* check if client's claimed height is higher than the chain's height IF clientClaimedHeight > chainHeight THEN @@ -112,17 +98,27 @@ ICS03_ConnectionOpenTry_0( /\ connection.clientId = clientId /\ connection.counterpartyClientId = counterpartyClientId THEN - \* initial verification passed; move to step 1 - ICS03_ConnectionOpenTry_1( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - counterpartyClientId, - connectionId - ) + \* verification passed; update connection + LET updatedConnection == [ + state |-> "TryOpen", + clientId |-> clientId, + connectionId |-> connectionId, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionId, + updatedConnection + ), + \* as the connection identifier has already been + \* created, here we do not update the + \* `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionOpenTryOK" + ] ELSE [ connections |-> connections, @@ -137,38 +133,26 @@ ICS03_ConnectionOpenTry_0( outcome |-> "ICS03ConnectionNotFound" ] ELSE - \* initial verification passed; move to step 1 - ICS03_ConnectionOpenTry_1( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - counterpartyClientId, - connectionId - ) - -ICS03_ConnectionOpenTry( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - counterpartyClientId, - connectionId -) == - \* start step 0 - ICS03_ConnectionOpenTry_0( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - counterpartyClientId, - connectionId - ) + \* verification passed; create connection + LET connection == [ + state |-> "TryOpen", + clientId |-> clientId, + \* generate a new connection identifier + connectionId |-> connectionIdCounter, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), + \* since a new connection identifier has been created, here we + \* update the `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter + 1, + outcome |-> "ICS03ConnectionOpenTryOK" + ] -=============================================================================== \ No newline at end of file +=============================================================================== diff --git a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json index 41a6394b0a..6bed88ced0 100644 --- a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json @@ -49,8 +49,8 @@ { "action": { "chainId": "chain-B", - "clientId": 1, "clientHeight": 2, + "clientId": 1, "connectionId": 0, "counterpartyClientId": 0, "type": "ICS03ConnectionOpenTry" @@ -65,4 +65,4 @@ } } } -] \ No newline at end of file +] diff --git a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json index 7d8ea34d92..4f1da1bc44 100644 --- a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json @@ -32,8 +32,8 @@ { "action": { "chainId": "chain-B", - "clientId": 0, "clientHeight": 1, + "clientId": 0, "connectionId": 0, "counterpartyClientId": 0, "type": "ICS03ConnectionOpenTry" @@ -48,4 +48,4 @@ } } } -] \ No newline at end of file +] diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json index 14fe580531..6e3d67ed6b 100644 --- a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json @@ -46,4 +46,4 @@ } } } -] \ No newline at end of file +] diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json new file mode 100644 index 0000000000..2c2655da7b --- /dev/null +++ b/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json @@ -0,0 +1,52 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chain-A": { + "height": 0 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-A", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chain-A": { + "height": 1 + }, + "chain-B": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chain-A", + "clientHeight": 1, + "clientId": 0, + "connectionId": -1, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionOpenTryOK", + "chains": { + "chain-A": { + "height": 2 + }, + "chain-B": { + "height": 0 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json index 8e4a6553fb..b87a592328 100644 --- a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json @@ -32,4 +32,4 @@ } } } -] \ No newline at end of file +] diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json index bfec803cd7..9200e16399 100644 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/ICS03MissingClientTest.json @@ -62,4 +62,4 @@ } } } -] \ No newline at end of file +] From 6b6cd43f92a3fc521dc1eb5e5ded4f41b3552a13 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 22:33:57 +0100 Subject: [PATCH 033/104] Go back to previous way of generating connection and channel ids --- modules/src/ics24_host/identifier.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index 965d04038b..293461bda1 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -199,7 +199,7 @@ pub struct ConnectionId(String); impl ConnectionId { /// Builds a new connection identifier. pub fn new(counter: u64) -> Result { - let prefix = "connection"; + let prefix = ConnectionId::default().to_string(); let id = format!("{}-{}", prefix, counter); Self::from_str(id.as_str()) } @@ -292,7 +292,7 @@ pub struct ChannelId(String); impl ChannelId { /// Builds a new channel identifier. pub fn new(counter: u64) -> Result { - let prefix = "channel"; + let prefix = ConnectionId::default().to_string(); let id = format!("{}-{}", prefix, counter); Self::from_str(id.as_str()) } From 6186bec661df3f6acac78ec6339da50620a3fdd4 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 4 Feb 2021 22:40:54 +0100 Subject: [PATCH 034/104] Disable failing MBT test --- modules/tests/model_based.rs | 2 +- .../tests/support/model_based/ICS03ConnectionMismatchTest.json | 3 ++- .../tests/support/model_based/ICS03ConnectionNotFoundTest.json | 3 ++- .../support/model_based/ICS03InvalidConsensusHeightTest.json | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 9d2566345c..b2c6061982 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -457,7 +457,7 @@ fn main() { "ICS02HeaderVerificationFailureTest", "ICS03ConnectionOpenInitOKTest", "ICS03MissingClientTest", - "ICS03ConnectionOpenTryOKTest", + // "ICS03ConnectionOpenTryOKTest", "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", diff --git a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json index 6bed88ced0..6e579d841b 100644 --- a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json @@ -53,6 +53,7 @@ "clientId": 1, "connectionId": 0, "counterpartyClientId": 0, + "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03ConnectionMismatch", @@ -65,4 +66,4 @@ } } } -] +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json index 4f1da1bc44..84666a043a 100644 --- a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json @@ -36,6 +36,7 @@ "clientId": 0, "connectionId": 0, "counterpartyClientId": 0, + "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03ConnectionNotFound", @@ -48,4 +49,4 @@ } } } -] +] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json index b87a592328..7c04490b6b 100644 --- a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json @@ -16,10 +16,11 @@ { "action": { "chainId": "chain-A", - "clientId": 0, "clientHeight": 1, + "clientId": 0, "connectionId": -1, "counterpartyClientId": 0, + "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03InvalidConsensusHeight", From a7b50d772aba468189e4dcdf9714bfa2a26c6dc5 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 5 Feb 2021 10:23:39 +0100 Subject: [PATCH 035/104] Fix panic in conn open try when no connection id is provided --- modules/src/ics03_connection/context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/src/ics03_connection/context.rs b/modules/src/ics03_connection/context.rs index a0b9bc6140..718101a842 100644 --- a/modules/src/ics03_connection/context.rs +++ b/modules/src/ics03_connection/context.rs @@ -72,14 +72,14 @@ pub trait ConnectionKeeper { )?; } State::TryOpen => { - self.store_connection( - &result.connection_id.clone().unwrap(), - &result.connection_end, - )?; + let connection_id = result + .connection_id + .unwrap_or_else(|| self.next_connection_id()); + self.store_connection(&connection_id, &result.connection_end)?; // If this is the first time the handler processed this connection, associate the // connection end to its client identifier. self.store_connection_to_client( - &result.connection_id.clone().unwrap(), + &connection_id, &result.connection_end.client_id(), )?; } From 5b66aac5c89d3efed06c0a6a348361df6ad757c4 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 5 Feb 2021 19:22:38 +0100 Subject: [PATCH 036/104] ICS02TestExecutor -> IBCTestExecutor --- modules/tests/model_based.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index b2c6061982..dd9507af95 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -32,12 +32,12 @@ use step::{ActionOutcome, ActionType, Chain, Step}; use tendermint::account::Id as AccountId; #[derive(Debug)] -struct ICS02TestExecutor { +struct IBCTestExecutor { // mapping from chain identifier to its context contexts: HashMap, } -impl ICS02TestExecutor { +impl IBCTestExecutor { fn new() -> Self { Self { contexts: Default::default(), @@ -199,7 +199,7 @@ impl ICS02TestExecutor { } } -impl modelator::TestExecutor for ICS02TestExecutor { +impl modelator::TestExecutor for IBCTestExecutor { fn initial_step(&mut self, step: Step) -> bool { assert_eq!( step.action.action_type, @@ -465,7 +465,7 @@ fn main() { for test in tests { let path = format!("{}/{}.json", TESTS_DIR, test); - let executor = ICS02TestExecutor::new(); + let executor = IBCTestExecutor::new(); // we should be able to just return the `Result` once the following issue // is fixed: https://github.com/rust-lang/rust/issues/43301 if let Err(e) = modelator::test_driver(executor, path) { From f2194cf1521ec82887c246b552a5e6c9c196fc89 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 5 Feb 2021 19:52:44 +0100 Subject: [PATCH 037/104] Failing MBT test now passes with #615 --- modules/tests/model_based.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index dd9507af95..d5baf8cee7 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -457,7 +457,7 @@ fn main() { "ICS02HeaderVerificationFailureTest", "ICS03ConnectionOpenInitOKTest", "ICS03MissingClientTest", - // "ICS03ConnectionOpenTryOKTest", + "ICS03ConnectionOpenTryOKTest", "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", From 7bdd3b6a19d49c65e44cb9c8f00aab41b64686a0 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 8 Feb 2021 11:25:31 +0100 Subject: [PATCH 038/104] Add notes on MBT --- modules/tests/README.md | 46 +++++++++++++++++++++++++++++++++++++++++ modules/tests/TODO | 1 + 2 files changed, 47 insertions(+) create mode 100644 modules/tests/README.md diff --git a/modules/tests/README.md b/modules/tests/README.md new file mode 100644 index 0000000000..3e4b1fb7cc --- /dev/null +++ b/modules/tests/README.md @@ -0,0 +1,46 @@ +### Model-based testing + +Let's say we want to test a system where: +- users can be created and deleted +- users have an id (say `u`) +- existing users have different ids + +#### i. Testing +- sequence of actions and expected outcomes + - `Test :: Vec<(Action, ActionOutcome)>` + - __test a)__: + - if I create user `u` (`action_1`), the operation should _succeed_ (`action_outcome_1`) + - if then I delete user `u` (`action_2`), the operation should _succeed_ (`action_outcome_2`) + - `Test = [(action_1, action_outcome_1), (action_2, action_outcome_2)]` + - __test b)__: + - if I create a user `u` (`action_1`), the operation should _succeed_ (`action_outcome_1`) + - if I then I create user `u` (`action_2`), the operation should _fail_ with an `ExistingUser` error (`action_outcome_2`) +- let's say that an action + its expected outcome is a `Step` + - `Step :: (Action, ActionOutcome)` + - `Test :: Vec` + + +#### ii. Model + +- what's a model? + - it's description of a system + - in our case, it's a __description of the system under test__ +- how do we write a model? + - in a language called `TLA+` +- what do we do with a model? + - e.g. prove invariants about it using a model checker + - example of an invariant: "existing users have different ids" + - model checkers for `TLA+`: `TLC` and `Apalache` + +#### How do we join i. and ii.? + +1. use the model to generate tests + - let's say we want a test where some user is deleted successfully + - define an invariant __negating the test__: + - "it's not possible that a user is deleted successfully" + - then we ask `Apalache` to prove it + - because the invariant is false, `Apalache` will find a counter example that shows it + - for example, it can find __test a)__ +2. monitor the model + - track each model action and its outcome + - define two `TLA+` variables: `action` and `actionOutcome` \ No newline at end of file diff --git a/modules/tests/TODO b/modules/tests/TODO index b86a736905..062411140c 100644 --- a/modules/tests/TODO +++ b/modules/tests/TODO @@ -1,3 +1,4 @@ - conn open try does not increment the connection id counter; looks like a bug - the model allows a conn open try to succeed without a conn open try (likely because we don't have proofs) + - one possible solution is the following; let A be the chain where a conn open init occurs and B the counterparty chain; when processing the conn open init, A should write a proof of it to B's set of proofs; a coon open try at B should then only succeed if B's set of proofs contains a proof of the corresponding conn open init - TLC doesn't finish with `MaxClientsPerChain = 2` From 9ee48bd2a7c337277de3889df06d963b0fd005bf Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 8 Feb 2021 20:20:23 +0100 Subject: [PATCH 039/104] Remove ICS02 --- modules/src/ics24_host/identifier.rs | 14 -- modules/src/mock/context.rs | 16 +- modules/tests/Makefile | 2 - modules/tests/TODO | 4 - modules/tests/model_based.rs | 217 +----------------- modules/tests/step.rs | 36 +-- modules/tests/support/model_based/IBC.tla | 200 +--------------- .../tests/support/model_based/IBCTests.cfg | 8 +- .../tests/support/model_based/IBCTests.tla | 24 -- modules/tests/support/model_based/ICS03.tla | 158 ------------- .../ICS03ConnectionMismatchTest.json | 69 ------ .../ICS03ConnectionNotFoundTest.json | 52 ----- .../ICS03ConnectionOpenInitOKTest.json | 49 ---- .../ICS03ConnectionOpenTryOKTest.json | 52 ----- .../ICS03InvalidConsensusHeightTest.json | 36 --- .../model_based/ICS03MissingClientTest.json | 65 ------ modules/tests/support/model_based/Makefile | 5 - .../ICS02HeaderVerificationFailureTest.json | 0 .../{ => tests}/ICS02UpdateOKTest.json | 0 19 files changed, 23 insertions(+), 984 deletions(-) delete mode 100644 modules/tests/Makefile delete mode 100644 modules/tests/TODO delete mode 100644 modules/tests/support/model_based/ICS03.tla delete mode 100644 modules/tests/support/model_based/ICS03ConnectionMismatchTest.json delete mode 100644 modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json delete mode 100644 modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json delete mode 100644 modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json delete mode 100644 modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json delete mode 100644 modules/tests/support/model_based/ICS03MissingClientTest.json delete mode 100644 modules/tests/support/model_based/Makefile rename modules/tests/support/model_based/{ => tests}/ICS02HeaderVerificationFailureTest.json (100%) rename modules/tests/support/model_based/{ => tests}/ICS02UpdateOKTest.json (100%) diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index 293461bda1..e76c9f7d60 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -197,13 +197,6 @@ impl PartialEq for ClientId { pub struct ConnectionId(String); impl ConnectionId { - /// Builds a new connection identifier. - pub fn new(counter: u64) -> Result { - let prefix = ConnectionId::default().to_string(); - let id = format!("{}-{}", prefix, counter); - Self::from_str(id.as_str()) - } - /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 @@ -290,13 +283,6 @@ impl Default for PortId { pub struct ChannelId(String); impl ChannelId { - /// Builds a new channel identifier. - pub fn new(counter: u64) -> Result { - let prefix = ConnectionId::default().to_string(); - let id = format!("{}-{}", prefix, counter); - Self::from_str(id.as_str()) - } - /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index 6bb829924e..c656363513 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -88,10 +88,10 @@ pub struct MockContext { port_capabilities: HashMap, /// Counter for connection identifiers (see `next_connection_id`). - connection_ids_counter: u64, + connection_ids_counter: u32, /// Counter for channel identifiers (see `next_channel_id`). - channel_ids_counter: u64, + channel_ids_counter: u32, } /// Returns a MockContext with bare minimum initialization: no clients, no connections and no channels are @@ -392,9 +392,11 @@ impl ChannelReader for MockContext { impl ChannelKeeper for MockContext { fn next_channel_id(&mut self) -> ChannelId { - let counter = self.channel_ids_counter; + let prefix = ChannelId::default().to_string(); + let suffix = self.channel_ids_counter; self.channel_ids_counter += 1; - ChannelId::new(counter).unwrap() + + ChannelId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() } fn store_channel( @@ -495,9 +497,11 @@ impl ConnectionReader for MockContext { impl ConnectionKeeper for MockContext { fn next_connection_id(&mut self) -> ConnectionId { - let counter = self.connection_ids_counter; + let prefix = ConnectionId::default().to_string(); + let suffix = self.connection_ids_counter; self.connection_ids_counter += 1; - ConnectionId::new(counter).unwrap() + + ConnectionId::from_str(format!("{}-{}", prefix, suffix).as_str()).unwrap() } fn store_connection( diff --git a/modules/tests/Makefile b/modules/tests/Makefile deleted file mode 100644 index 7d64c99e0d..0000000000 --- a/modules/tests/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - cargo t --features mocks -- --nocapture main diff --git a/modules/tests/TODO b/modules/tests/TODO deleted file mode 100644 index 062411140c..0000000000 --- a/modules/tests/TODO +++ /dev/null @@ -1,4 +0,0 @@ -- conn open try does not increment the connection id counter; looks like a bug -- the model allows a conn open try to succeed without a conn open try (likely because we don't have proofs) - - one possible solution is the following; let A be the chain where a conn open init occurs and B the counterparty chain; when processing the conn open init, A should write a proof of it to B's set of proofs; a coon open try at B should then only succeed if B's set of proofs contains a proof of the corresponding conn open init -- TLC doesn't finish with `MaxClientsPerChain = 2` diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index d5baf8cee7..e7ef6e8365 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -7,23 +7,15 @@ use ibc::ics02_client::error::Kind as ICS02ErrorKind; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; -use ibc::ics03_connection::connection::Counterparty; -use ibc::ics03_connection::error::Kind as ICS03ErrorKind; -use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use ibc::ics03_connection::msgs::ConnectionMsg; -use ibc::ics03_connection::version::Version; use ibc::ics18_relayer::context::ICS18Context; use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; -use ibc::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes}; -use ibc::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; +use ibc::ics24_host::identifier::{ChainId, ClientId}; use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; use ibc::ics26_routing::msgs::ICS26Envelope; use ibc::mock::client_state::{MockClientState, MockConsensusState}; use ibc::mock::context::MockContext; use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; -use ibc::proofs::{ConsensusProof, Proofs}; use ibc::Height; use std::collections::HashMap; use std::error::Error; @@ -101,29 +93,16 @@ impl IBCTestExecutor { } // TODO: this is sometimes called version/revision number but seems - // unrelated with the `Version` type below; is that so? + // unrelated with the `Version` type; is that so? fn epoch() -> u64 { 0 } - fn version() -> Version { - Version::default() - } - - fn versions() -> Vec { - vec![Self::version()] - } - fn client_id(client_id: u64) -> ClientId { ClientId::new(ClientType::Mock, client_id) .expect("it should be possible to create the client identifier") } - fn connection_id(connection_id: u64) -> ConnectionId { - ConnectionId::new(connection_id) - .expect("it should be possible to create the connection identifier") - } - fn height(height: u64) -> Height { Height::new(Self::epoch(), height) } @@ -148,48 +127,6 @@ impl IBCTestExecutor { AccountId::new([0; 20]) } - fn counterparty(client_id: u64, connection_id: Option) -> Counterparty { - let client_id = Self::client_id(client_id); - let connection_id = connection_id.map(|connection_id| Self::connection_id(connection_id)); - let prefix = Self::commitment_prefix(); - Counterparty::new(client_id, connection_id, prefix) - } - - fn delay_period() -> u64 { - 0 - } - - fn commitment_prefix() -> CommitmentPrefix { - vec![0].into() - } - - fn commitment_proof_bytes() -> CommitmentProofBytes { - vec![0].into() - } - - fn consensus_proof(height: u64) -> ConsensusProof { - let consensus_proof = Self::commitment_proof_bytes(); - let consensus_height = Self::height(height); - ConsensusProof::new(consensus_proof, consensus_height) - .expect("it should be possible to create the consensus proof") - } - - fn proofs(height: u64) -> Proofs { - let object_proof = Self::commitment_proof_bytes(); - let client_proof = None; - let consensus_proof = Some(Self::consensus_proof(height)); - let other_proof = None; - let height = Self::height(height); - Proofs::new( - object_proof, - client_proof, - consensus_proof, - other_proof, - height, - ) - .expect("it should be possible to create the proofs") - } - /// Check that chain heights match the ones in the model. fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { @@ -219,7 +156,6 @@ impl modelator::TestExecutor for IBCTestExecutor { } fn next_step(&mut self, step: Step) -> bool { - println!("{:?}", step); let outcome_matches = match step.action.action_type { ActionType::None => panic!("unexpected action type"), ActionType::ICS02CreateClient => { @@ -306,162 +242,17 @@ impl modelator::TestExecutor for IBCTestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - ActionType::ICS03ConnectionOpenInit => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("connection open init action should have a chain identifier"); - let client_id = step - .action - .client_id - .expect("connection open init action should have a client identifier"); - let counterparty_client_id = step.action.counterparty_client_id.expect( - "connection open init action should have a counterparty client identifier", - ); - - // get chain's context - let ctx = self.chain_context_mut(&chain_id); - - // create ICS26 message and deliver it - let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenInit( - MsgConnectionOpenInit { - client_id: Self::client_id(client_id), - counterparty: Self::counterparty(counterparty_client_id, None), - version: Self::version(), - delay_period: Self::delay_period(), - signer: Self::signer(), - }, - )); - let result = ctx.deliver(msg); - - // check the expected outcome - match step.action_outcome { - ActionOutcome::ICS03ConnectionOpenInitOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - ActionOutcome::ICS03MissingClient => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - matches!( - handler_error_kind, - ICS03ErrorKind::MissingClient(error_client_id) - if error_client_id == Self::client_id(client_id) - ) - } - action => panic!("unexpected action outcome {:?}", action), - } - } - ActionType::ICS03ConnectionOpenTry => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("connection open try action should have a chain identifier"); - let client_id = step - .action - .client_id - .expect("connection open try action should have a client identifier"); - let client_height = step - .action - .client_height - .expect("connection open try action should have a client height"); - let counterparty_client_id = step.action.counterparty_client_id.expect( - "connection open try action should have a counterparty client identifier", - ); - let connection_id = step.action.connection_id; - let counterparty_connection_id = step.action.counterparty_connection_id.expect( - "connection open try action should have a counterparty connection identifier", - ); - - // get chain's context - let ctx = self.chain_context_mut(&chain_id); - - // create ICS26 message and deliver it - let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( - MsgConnectionOpenTry { - previous_connection_id: connection_id.map(Self::connection_id), - client_id: Self::client_id(client_id), - client_state: None, - counterparty: Self::counterparty( - counterparty_client_id, - Some(counterparty_connection_id), - ), - counterparty_versions: Self::versions(), - proofs: Self::proofs(client_height), - delay_period: Self::delay_period(), - signer: Self::signer(), - }, - ))); - let result = dbg!(ctx.deliver(msg)); - - // check the expected outcome - match step.action_outcome { - ActionOutcome::ICS03ConnectionOpenTryOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - ActionOutcome::ICS03InvalidConsensusHeight => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - matches!( - handler_error_kind, - ICS03ErrorKind::InvalidConsensusHeight(error_consensus_height, _) - if error_consensus_height == Self::height(client_height) - ) - } - ActionOutcome::ICS03ConnectionNotFound => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - connection_id.is_some() - && matches!( - handler_error_kind, - ICS03ErrorKind::ConnectionNotFound(error_connection_id) - if error_connection_id == Self::connection_id(connection_id.unwrap()) - ) - } - ActionOutcome::ICS03ConnectionMismatch => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - connection_id.is_some() - && matches!( - handler_error_kind, - ICS03ErrorKind::ConnectionMismatch(error_connection_id) - if error_connection_id == Self::connection_id(connection_id.unwrap()) - ) - } - action => panic!("unexpected action outcome {:?}", action), - } - } }; // also check that chain heights match outcome_matches && self.check_chain_heights(step.chains) } } -const TESTS_DIR: &str = "tests/support/model_based"; +const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn main() { - let tests = vec![ - "ICS02UpdateOKTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", - "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", - ]; + let tests = vec!["ICS02UpdateOKTest", "ICS02HeaderVerificationFailureTest"]; for test in tests { let path = format!("{}/{}.json", TESTS_DIR, test); diff --git a/modules/tests/step.rs b/modules/tests/step.rs index 67f97882bc..98c831e050 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; use std::collections::HashMap; use std::fmt::Debug; @@ -25,32 +25,6 @@ pub struct Action { #[serde(alias = "clientHeight")] pub client_height: Option, - - #[serde(alias = "counterpartyClientId")] - pub counterparty_client_id: Option, - - #[serde(alias = "connectionId")] - #[serde(default, deserialize_with = "deserialize_connection_id")] - pub connection_id: Option, - - #[serde(alias = "counterpartyConnectionId")] - #[serde(default, deserialize_with = "deserialize_connection_id")] - pub counterparty_connection_id: Option, -} - -/// On the model, a non-existing `connection_id` is represented with -1. -/// For this reason, this function maps a `Some(-1)` to a `None`. -fn deserialize_connection_id<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let connection_id: Option = Deserialize::deserialize(deserializer)?; - let connection_id = if connection_id == Some(-1) { - None - } else { - connection_id.map(|connection_id| connection_id as u64) - }; - Ok(connection_id) } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -58,8 +32,6 @@ pub enum ActionType { None, ICS02CreateClient, ICS02UpdateClient, - ICS03ConnectionOpenInit, - ICS03ConnectionOpenTry, } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -69,12 +41,6 @@ pub enum ActionOutcome { ICS02UpdateOK, ICS02ClientNotFound, ICS02HeaderVerificationFailure, - ICS03ConnectionOpenInitOK, - ICS03MissingClient, - ICS03ConnectionOpenTryOK, - ICS03InvalidConsensusHeight, - ICS03ConnectionNotFound, - ICS03ConnectionMismatch, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 89ddfe6de2..7586626558 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,6 +1,6 @@ --------------------------------- MODULE IBC ---------------------------------- -EXTENDS Integers, FiniteSets, ICS02, ICS03 +EXTENDS Integers, FiniteSets, ICS02 \* ids of existing chains CONSTANT ChainIds @@ -10,9 +10,6 @@ ASSUME MaxClientsPerChain >= 0 \* max height which clients can reach CONSTANT MaxClientHeight ASSUME MaxClientHeight >= 0 -\* max number of connections to be created per chain -CONSTANT MaxConnectionsPerChain -ASSUME MaxConnectionsPerChain >= 0 \* mapping from chain id to its data VARIABLE chains @@ -30,10 +27,7 @@ ActionType == [ type |-> STRING, chainId |-> STRING, clientHeight |-> Int, - clientId |-> Int, - connectionId |-> Int, - counterpartyClientId |-> Int, - counterpartyConnectionId |-> Int + clientId |-> Int ] AsAction(a) == a <: ActionType (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) @@ -44,15 +38,6 @@ ChainHeights == Int ClientIds == 0..(MaxClientsPerChain - 1) \* set of possible client heights ClientHeights == 1..MaxClientHeight -\* set of possible connection identifiers -ConnectionIds == 0..(MaxConnectionsPerChain- 1) -\* set of possible connection states -ConnectionStates == { - "Uninit", - "Init", - "TryOpen", - "Open" -} \* data kept per cliennt Client == [ @@ -62,25 +47,11 @@ Client == [ Clients == [ ClientIds -> Client ] -\* data kept per connection -Connection == [ - state: ConnectionStates, - clientId: ClientIds \union {ClientIdNone}, - counterpartyClientId: ClientIds \union {ClientIdNone}, - connectionId: ConnectionIds \union {ConnectionIdNone}, - counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} -] -\* mapping from connection identifier to its data -Connections == [ - ConnectionIds -> Connection -] \* data kept per chain Chain == [ height: ChainHeights, clients: Clients, - clientIdCounter: 0..MaxClientsPerChain, - connections: Connections, - connectionIdCounter: 0..MaxConnectionsPerChain + clientIdCounter: 0..MaxClientsPerChain ] \* mapping from chain identifier to its data Chains == [ @@ -102,27 +73,10 @@ UpdateClientActions == [ clientHeight: ClientHeights, clientId: ClientIds ] <: {ActionType} -ConnectionOpenInitActions == [ - type: {"ICS03ConnectionOpenInit"}, - chainId: ChainIds, - clientId: ClientIds, - counterpartyClientId: ClientIds -] <: {ActionType} -ConnectionOpenTryActions == [ - type: {"ICS03ConnectionOpenTry"}, - chainId: ChainIds, - clientHeight: ClientHeights, - clientId: ClientIds, - counterpartyClientId: ClientIds, - connectionId: ConnectionIds \union {ConnectionIdNone}, - counterpartyConnectionId: ConnectionIds -] <: {ActionType} Actions == NoneActions \union CreateClientActions \union - UpdateClientActions \union - ConnectionOpenInitActions \union - ConnectionOpenTryActions + UpdateClientActions \* set of possible action outcomes ActionOutcomes == { @@ -133,15 +87,7 @@ ActionOutcomes == { \* ICS02_UpdateClient outcomes: "ICS02UpdateOK", "ICS02ClientNotFound", - "ICS02HeaderVerificationFailure", - \* ICS03_ConnectionOpenInit outcomes: - "ICS03ConnectionOpenInitOK", - "ICS03MissingClient", - \* ICS03_ConnectionOpenTry outcomes: - "ICS03ConnectionOpenTryOK", - "ICS03InvalidConsensusHeight", - "ICS03ConnectionNotFound", - "ICS03ConnectionMismatch" + "ICS02HeaderVerificationFailure" } (***************************** Specification *********************************) @@ -187,75 +133,6 @@ UpdateClient(chainId, clientId, clientHeight) == clientHeight |-> clientHeight]) /\ actionOutcome' = result.outcome -ConnectionOpenInit(chainId, clientId, counterpartyClientId) == - LET chain == chains[chainId] IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN - LET result == ICS03_ConnectionOpenInit( - clients, - connections, - connectionIdCounter, - clientId, - counterpartyClientId - ) IN - \* update the chain - LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), - !.connections = result.connections, - !.connectionIdCounter = result.connectionIdCounter - ] IN - \* update `chains`, set the `action` and its `actionOutcome` - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS03ConnectionOpenInit", - chainId |-> chainId, - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId]) - /\ actionOutcome' = result.outcome - -ConnectionOpenTry( - chainId, - clientId, - clientHeight, - connectionId, - counterpartyClientId, - counterpartyConnectionId -) == - LET chain == chains[chainId] IN - LET height == chain.height IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN - LET result == ICS03_ConnectionOpenTry( - height, - clients, - connections, - connectionIdCounter, - clientId, - clientHeight, - connectionId, - counterpartyClientId, - counterpartyConnectionId - ) IN - \* update the chain - LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), - !.connections = result.connections, - !.connectionIdCounter = result.connectionIdCounter - ] IN - \* update `chains`, set the `action` and its `actionOutcome` - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS03ConnectionOpenTry", - chainId |-> chainId, - clientId |-> clientId, - clientHeight |-> clientHeight, - connectionId |-> connectionId, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId]) - /\ actionOutcome' = result.outcome - CreateClientAction == \* select a chain id \E chainId \in ChainIds: @@ -277,77 +154,16 @@ UpdateClientAction == \E clientHeight \in ClientHeights: UpdateClient(chainId, clientId, clientHeight) -ConnectionOpenInitAction == - \* select a chain id - \E chainId \in ChainIds: - \* select a client id - \E clientId \in ClientIds: - \* select a counterparty client id - \E counterpartyClientId \in ClientIds: - \* only create connection if the model constant `MaxConnectionsPerChain` - \* allows it - IF chains[chainId].connectionIdCounter \in ConnectionIds THEN - ConnectionOpenInit(chainId, clientId, counterpartyClientId) - ELSE - UNCHANGED vars - -ConnectionOpenTryAction == - \* select a chain id - \E chainId \in ChainIds: - \* select a client id - \E clientId \in ClientIds: - \* select a claimed height for the client - \E clientHeight \in ClientHeights: - \* select a connection id (which can be none) - \E connectionId \in ConnectionIds \union {ConnectionIdNone}: - \* select a counterparty client id - \E counterpartyClientId \in ClientIds: - \* select a counterparty connection id - \E counterpartyConnectionId \in ConnectionIds: - IF connectionId = ConnectionIdNone THEN - \* in this case we're trying to create a new connection; only create - \* connection if the model constant `MaxConnectionsPerChain` allows - \* it - IF chains[chainId].connectionIdCounter \in ConnectionIds THEN - ConnectionOpenTry( - chainId, - clientId, - clientHeight, - connectionId, - counterpartyClientId, - counterpartyConnectionId - ) - ELSE - UNCHANGED vars - ELSE - ConnectionOpenTry( - chainId, - clientId, - clientHeight, - connectionId, - counterpartyClientId, - counterpartyConnectionId - ) - Init == - \* create a client and a connection with none values + \* create a client with none values LET clientNone == [ height |-> HeightNone ] IN - LET connectionNone == [ - state |-> "Uninit", - clientId |-> ClientIdNone, - counterpartyClientId |-> ClientIdNone, - connectionId |-> ConnectionIdNone, - counterpartyConnectionId |-> ConnectionIdNone - ] IN \* create an empty chain LET emptyChain == [ height |-> 0, clients |-> [clientId \in ClientIds |-> clientNone], - clientIdCounter |-> 0, - connections |-> [connectionId \in ConnectionIds |-> connectionNone], - connectionIdCounter |-> 0 + clientIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] /\ action = AsAction([type |-> "None"]) @@ -356,8 +172,6 @@ Init == Next == \/ CreateClientAction \/ UpdateClientAction - \/ ConnectionOpenInitAction - \/ ConnectionOpenTryAction \/ UNCHANGED vars (******************************** Invariants *********************************) diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 4090d7a7f4..55958ebe13 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -11,10 +11,4 @@ INVARIANTS \* ICS02CreateOKTest \* ICS02UpdateOKTest \* ICS02ClientNotFoundTest - \* ICS02HeaderVerificationFailureTest - \* ICS03ConnectionOpenInitOKTest - \* ICS03MissingClientTest - ICS03ConnectionOpenTryOKTest - \* ICS03InvalidConsensusHeightTest - \* ICS03ConnectionNotFoundTest - \* ICS03ConnectionMismatchTest + \* ICS02HeaderVerificationFailureTest \ No newline at end of file diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 35127df6ae..e8d4926557 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -14,33 +14,9 @@ ICS02ClientNotFound == ICS02HeaderVerificationFailure == /\ actionOutcome = "ICS02HeaderVerificationFailure" -ICS03ConnectionOpenInitOK == - /\ actionOutcome = "ICS03ConnectionOpenInitOK" - -ICS03MissingClient == - /\ actionOutcome = "ICS03MissingClient" - -ICS03ConnectionOpenTryOK == - /\ actionOutcome = "ICS03ConnectionOpenTryOK" - -ICS03InvalidConsensusHeight == - /\ actionOutcome = "ICS03InvalidConsensusHeight" - -ICS03ConnectionNotFound == - /\ actionOutcome = "ICS03ConnectionNotFound" - -ICS03ConnectionMismatch == - /\ actionOutcome = "ICS03ConnectionMismatch" - ICS02CreateOKTest == ~ICS02CreateOK ICS02UpdateOKTest == ~ICS02UpdateOK ICS02ClientNotFoundTest == ~ICS02ClientNotFound ICS02HeaderVerificationFailureTest == ~ICS02HeaderVerificationFailure -ICS03ConnectionOpenInitOKTest == ~ICS03ConnectionOpenInitOK -ICS03MissingClientTest == ~ICS03MissingClient -ICS03ConnectionOpenTryOKTest == ~ICS03ConnectionOpenTryOK -ICS03InvalidConsensusHeightTest == ~ICS03InvalidConsensusHeight -ICS03ConnectionNotFoundTest == ~ICS03ConnectionNotFound -ICS03ConnectionMismatchTest == ~ICS03ConnectionMismatch =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla deleted file mode 100644 index e9b3096a7f..0000000000 --- a/modules/tests/support/model_based/ICS03.tla +++ /dev/null @@ -1,158 +0,0 @@ ------------------------------- MODULE ICS03 ----------------------------------- - -EXTENDS Integers, FiniteSets, IBCDefinitions, ICS02 - -\* retrieves `connectionId`'s data -ICS03_GetConnection(connections, connectionId) == - connections[connectionId] - -\* check if `connectionId` exists -ICS03_ConnectionExists(connections, connectionId) == - ICS03_GetConnection(connections, connectionId).state /= "Uninit" - -\* update `connectionId`'s data -ICS03_SetConnection(connections, connectionId, connection) == - [connections EXCEPT ![connectionId] = connection] - -ICS03_ConnectionOpenInit( - clients, - connections, - connectionIdCounter, - clientId, - counterpartyClientId -) == - \* check if the client exists - IF ICS02_ClientExists(clients, clientId) THEN - \* if the client exists, - \* then check if the connection exists (it shouldn't) - IF ICS03_ConnectionExists(connections, connectionIdCounter) THEN - \* if the connection to be created already exists, - \* then there's an error in the model - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ModelError" - ] - ELSE - \* if it doesn't, create it - LET connection == [ - state |-> "Init", - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId, - connectionId |-> connectionIdCounter, - counterpartyConnectionId |-> ConnectionIdNone - ] IN - \* return result with updated state - [ - connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, - connection - ), - connectionIdCounter |-> connectionIdCounter + 1, - outcome |-> "ICS03ConnectionOpenInitOK" - ] - ELSE - \* if the client does not exist, then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03MissingClient" - ] - -\* TODO: errors generated when verifying proofs are never an outcome of this -\* model -ICS03_ConnectionOpenTry( - chainHeight, - clients, - connections, - connectionIdCounter, - clientId, - clientClaimedHeight, - connectionId, - counterpartyClientId, - counterpartyConnectionId -) == - \* check if client's claimed height is higher than the chain's height - IF clientClaimedHeight > chainHeight THEN - \* if client's height is too advanced, then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03InvalidConsensusHeight" - ] - \* TODO: add `chain_max_history_size` to the model to be able to also - \* return a `ICS03StaleConsensusHeight` error outcome - ELSE - \* check if a `connectionId` was set - IF connectionId /= ConnectionIdNone THEN - \* if so, check if the connection exists - IF ICS03_ConnectionExists(connections, connectionId) THEN - \* if the connection exists, verify that is matches the - \* the parameters provided - LET connection == ICS03_GetConnection( - connections, - connectionId - ) IN - IF /\ connection.state = "Init" - /\ connection.clientId = clientId - /\ connection.counterpartyClientId = counterpartyClientId - THEN - \* verification passed; update connection - LET updatedConnection == [ - state |-> "TryOpen", - clientId |-> clientId, - connectionId |-> connectionId, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId - ] IN - \* return result with updated state - [ - connections |-> ICS03_SetConnection( - connections, - connectionId, - updatedConnection - ), - \* as the connection identifier has already been - \* created, here we do not update the - \* `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03ConnectionOpenTryOK" - ] - ELSE - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03ConnectionMismatch" - ] - ELSE - \* if the connection does not exist, then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - outcome |-> "ICS03ConnectionNotFound" - ] - ELSE - \* verification passed; create connection - LET connection == [ - state |-> "TryOpen", - clientId |-> clientId, - \* generate a new connection identifier - connectionId |-> connectionIdCounter, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId - ] IN - \* return result with updated state - [ - connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, - connection - ), - \* since a new connection identifier has been created, here we - \* update the `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter + 1, - outcome |-> "ICS03ConnectionOpenTryOK" - ] - -=============================================================================== diff --git a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json deleted file mode 100644 index 6e579d841b..0000000000 --- a/modules/tests/support/model_based/ICS03ConnectionMismatchTest.json +++ /dev/null @@ -1,69 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 1 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientId": 0, - "counterpartyClientId": 1, - "type": "ICS03ConnectionOpenInit" - }, - "actionOutcome": "ICS03ConnectionOpenInitOK", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 2 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientHeight": 2, - "clientId": 1, - "connectionId": 0, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionMismatch", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 2 - } - } - } -] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json deleted file mode 100644 index 84666a043a..0000000000 --- a/modules/tests/support/model_based/ICS03ConnectionNotFoundTest.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 1 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientHeight": 1, - "clientId": 0, - "connectionId": 0, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionNotFound", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 1 - } - } - } -] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json deleted file mode 100644 index 6e3d67ed6b..0000000000 --- a/modules/tests/support/model_based/ICS03ConnectionOpenInitOKTest.json +++ /dev/null @@ -1,49 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 1 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientId": 0, - "counterpartyClientId": 0, - "type": "ICS03ConnectionOpenInit" - }, - "actionOutcome": "ICS03ConnectionOpenInitOK", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 2 - } - } - } -] diff --git a/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json deleted file mode 100644 index 2c2655da7b..0000000000 --- a/modules/tests/support/model_based/ICS03ConnectionOpenTryOKTest.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-A", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 1 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-A", - "clientHeight": 1, - "clientId": 0, - "connectionId": -1, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionOpenTryOK", - "chains": { - "chain-A": { - "height": 2 - }, - "chain-B": { - "height": 0 - } - } - } -] \ No newline at end of file diff --git a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json deleted file mode 100644 index 7c04490b6b..0000000000 --- a/modules/tests/support/model_based/ICS03InvalidConsensusHeightTest.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-A", - "clientHeight": 1, - "clientId": 0, - "connectionId": -1, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03InvalidConsensusHeight", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - } -] diff --git a/modules/tests/support/model_based/ICS03MissingClientTest.json b/modules/tests/support/model_based/ICS03MissingClientTest.json deleted file mode 100644 index 9200e16399..0000000000 --- a/modules/tests/support/model_based/ICS03MissingClientTest.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chain-A": { - "height": 0 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-A", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 1 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-A", - "clientHeight": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chain-A": { - "height": 2 - }, - "chain-B": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chain-B", - "clientId": 0, - "counterpartyClientId": 0, - "type": "ICS03ConnectionOpenInit" - }, - "actionOutcome": "ICS03MissingClient", - "chains": { - "chain-A": { - "height": 2 - }, - "chain-B": { - "height": 0 - } - } - } -] diff --git a/modules/tests/support/model_based/Makefile b/modules/tests/support/model_based/Makefile deleted file mode 100644 index e0cdfbb248..0000000000 --- a/modules/tests/support/model_based/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -check: - apalache-mc check --inv=ModelNeverErrors IBC.tla - -test: - apalache-mc check IBCTests.tla diff --git a/modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json similarity index 100% rename from modules/tests/support/model_based/ICS02HeaderVerificationFailureTest.json rename to modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json diff --git a/modules/tests/support/model_based/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json similarity index 100% rename from modules/tests/support/model_based/ICS02UpdateOKTest.json rename to modules/tests/support/model_based/tests/ICS02UpdateOKTest.json From 035651e68338fc82c6d76762b11622bf9538d6fc Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 8 Feb 2021 23:42:48 +0100 Subject: [PATCH 040/104] Add README --- modules/tests/model_based.rs | 2 +- .../tests/support/model_based/IBCTests.cfg | 8 +--- .../tests/support/model_based/IBCTests.tla | 16 ++++---- modules/tests/support/model_based/README.md | 37 +++++++++++++++++++ 4 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 modules/tests/support/model_based/README.md diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index e7ef6e8365..906aa64a2f 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -251,7 +251,7 @@ impl modelator::TestExecutor for IBCTestExecutor { const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] -fn main() { +fn model_based() { let tests = vec!["ICS02UpdateOKTest", "ICS02HeaderVerificationFailureTest"]; for test in tests { diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 55958ebe13..0fde2766a1 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -5,10 +5,4 @@ CONSTANTS MaxConnectionsPerChain = 2 INIT Init -NEXT Next - -INVARIANTS - \* ICS02CreateOKTest - \* ICS02UpdateOKTest - \* ICS02ClientNotFoundTest - \* ICS02HeaderVerificationFailureTest \ No newline at end of file +NEXT Next \ No newline at end of file diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index e8d4926557..245461c3c9 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -2,21 +2,21 @@ EXTENDS IBC -ICS02CreateOK == +ICS02CreateOKTest == /\ actionOutcome = "ICS02CreateOK" -ICS02UpdateOK == +ICS02UpdateOKTest == /\ actionOutcome = "ICS02UpdateOK" -ICS02ClientNotFound == +ICS02ClientNotFoundTest == /\ actionOutcome = "ICS02ClientNotFound" -ICS02HeaderVerificationFailure == +ICS02HeaderVerificationFailureTest == /\ actionOutcome = "ICS02HeaderVerificationFailure" -ICS02CreateOKTest == ~ICS02CreateOK -ICS02UpdateOKTest == ~ICS02UpdateOK -ICS02ClientNotFoundTest == ~ICS02ClientNotFound -ICS02HeaderVerificationFailureTest == ~ICS02HeaderVerificationFailure +ICS02CreateOKTestNeg == ~ICS02CreateOKTest +ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest +ICS02ClientNotFoundTestNeg == ~ICS02ClientNotFoundTest +ICS02HeaderVerificationFailureTestNeg == ~ICS02HeaderVerificationFailureTest =============================================================================== diff --git a/modules/tests/support/model_based/README.md b/modules/tests/support/model_based/README.md new file mode 100644 index 0000000000..980aadde05 --- /dev/null +++ b/modules/tests/support/model_based/README.md @@ -0,0 +1,37 @@ +## Model-based tests for IBC modules + +This directory contains the model-based tests for the IBC modules. They are "model-based" because they are generated from a `TLA+` model of the IBC modules (see [IBC.tla](IBC.tla)). + +Tests are `TLA+` assertions that describe the desired shape of the test. One of the assertions in [IBCTests.tla](IBCTests.tla) is the following: + +```tla +ICS02UpdateOKTest == + /\ actionOutcome = "ICS02UpdateOK" +``` + +This very simple assertion describes a test where the [model](IBC.tla) variable `actionOutcome` reaches the value `"ICS02UpdateOK"`, which occurs when a light client is successfully updated to a new height (see [ICS02.tla](ICS02.tla)). + +To generate a test from the `ICS02UpdateOKTest` assertion, we first define an invariant negating it: +```tla +ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest +``` + +Then, we ask [`Apalache`](https://apalache.informal.systems), a model checker for `TLA+`, to prove it: + +```bash +apalache-mc check --inv=ICS02UpdateOKTestNeg IBCTests.tla +``` + +Because the invariant is wrong, `Apalache` will find a counterexample showing that it is indeed possible that a light-client is sucessfully updated to a new height. This counterexample is our test. + +### Current limitations + +The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples (like those in [tests/](tests/), which are currently generated manually) that can be easily mapped to Rust (see [step.rs](../../step.rs)). + +### Running the model-based tests + +The model-based tests can be run with the following command: + +```bash +cargo test -p ibc --features mocks -- model_based +``` From b6854ce33fcb99fe85300209906d0a9095ec906c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 8 Feb 2021 23:52:33 +0100 Subject: [PATCH 041/104] Improve README --- modules/tests/support/model_based/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/tests/support/model_based/README.md b/modules/tests/support/model_based/README.md index 980aadde05..d2d0497221 100644 --- a/modules/tests/support/model_based/README.md +++ b/modules/tests/support/model_based/README.md @@ -26,7 +26,8 @@ Because the invariant is wrong, `Apalache` will find a counterexample showing th ### Current limitations -The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples (like those in [tests/](tests/), which are currently generated manually) that can be easily mapped to Rust (see [step.rs](../../step.rs)). +The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples like those in [tests/](tests/). +These are currently generated manually, but can be easily mapped to Rust (see [step.rs](../../step.rs)). ### Running the model-based tests From cd484a68151712f1afbf3d1533ab6f4c70580809 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 00:03:07 +0100 Subject: [PATCH 042/104] Remove MBT intro --- modules/tests/README.md | 46 ----------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 modules/tests/README.md diff --git a/modules/tests/README.md b/modules/tests/README.md deleted file mode 100644 index 3e4b1fb7cc..0000000000 --- a/modules/tests/README.md +++ /dev/null @@ -1,46 +0,0 @@ -### Model-based testing - -Let's say we want to test a system where: -- users can be created and deleted -- users have an id (say `u`) -- existing users have different ids - -#### i. Testing -- sequence of actions and expected outcomes - - `Test :: Vec<(Action, ActionOutcome)>` - - __test a)__: - - if I create user `u` (`action_1`), the operation should _succeed_ (`action_outcome_1`) - - if then I delete user `u` (`action_2`), the operation should _succeed_ (`action_outcome_2`) - - `Test = [(action_1, action_outcome_1), (action_2, action_outcome_2)]` - - __test b)__: - - if I create a user `u` (`action_1`), the operation should _succeed_ (`action_outcome_1`) - - if I then I create user `u` (`action_2`), the operation should _fail_ with an `ExistingUser` error (`action_outcome_2`) -- let's say that an action + its expected outcome is a `Step` - - `Step :: (Action, ActionOutcome)` - - `Test :: Vec` - - -#### ii. Model - -- what's a model? - - it's description of a system - - in our case, it's a __description of the system under test__ -- how do we write a model? - - in a language called `TLA+` -- what do we do with a model? - - e.g. prove invariants about it using a model checker - - example of an invariant: "existing users have different ids" - - model checkers for `TLA+`: `TLC` and `Apalache` - -#### How do we join i. and ii.? - -1. use the model to generate tests - - let's say we want a test where some user is deleted successfully - - define an invariant __negating the test__: - - "it's not possible that a user is deleted successfully" - - then we ask `Apalache` to prove it - - because the invariant is false, `Apalache` will find a counter example that shows it - - for example, it can find __test a)__ -2. monitor the model - - track each model action and its outcome - - define two `TLA+` variables: `action` and `actionOutcome` \ No newline at end of file From d69d15e9daaf7f7819623b8d83126b14e83aea0f Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 00:08:24 +0100 Subject: [PATCH 043/104] new lines --- modules/tests/support/model_based/IBC.cfg | 2 +- modules/tests/support/model_based/IBCTests.cfg | 2 +- .../model_based/tests/ICS02HeaderVerificationFailureTest.json | 2 +- modules/tests/support/model_based/tests/ICS02UpdateOKTest.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 25f40c9106..3bcce4efea 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -9,4 +9,4 @@ NEXT Next INVARIANTS TypeOK - ModelNeverErrors \ No newline at end of file + ModelNeverErrors diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 0fde2766a1..8ce87d740b 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -5,4 +5,4 @@ CONSTANTS MaxConnectionsPerChain = 2 INIT Init -NEXT Next \ No newline at end of file +NEXT Next diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index dbad8fc3ba..e19671052a 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -46,4 +46,4 @@ } } } -] \ No newline at end of file +] diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index 309d6aa953..86f427443f 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -112,4 +112,4 @@ } } } -] \ No newline at end of file +] From 5e9dd634a3bc04c0f193ab3872b83dc00505d1d4 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 12:38:58 +0100 Subject: [PATCH 044/104] Make MBT README more easily discoverable --- modules/tests/{support/model_based => }/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename modules/tests/{support/model_based => }/README.md (71%) diff --git a/modules/tests/support/model_based/README.md b/modules/tests/README.md similarity index 71% rename from modules/tests/support/model_based/README.md rename to modules/tests/README.md index d2d0497221..e3d19d2813 100644 --- a/modules/tests/support/model_based/README.md +++ b/modules/tests/README.md @@ -1,15 +1,15 @@ ## Model-based tests for IBC modules -This directory contains the model-based tests for the IBC modules. They are "model-based" because they are generated from a `TLA+` model of the IBC modules (see [IBC.tla](IBC.tla)). +This directory contains the model-based tests for the IBC modules. They are "model-based" because they are generated from a `TLA+` model of the IBC modules (see [IBC.tla](support/model_based/IBC.tla)). -Tests are `TLA+` assertions that describe the desired shape of the test. One of the assertions in [IBCTests.tla](IBCTests.tla) is the following: +Tests are `TLA+` assertions that describe the desired shape of the test. One of the assertions in [IBCTests.tla](support/model_based/IBCTests.tla) is the following: ```tla ICS02UpdateOKTest == /\ actionOutcome = "ICS02UpdateOK" ``` -This very simple assertion describes a test where the [model](IBC.tla) variable `actionOutcome` reaches the value `"ICS02UpdateOK"`, which occurs when a light client is successfully updated to a new height (see [ICS02.tla](ICS02.tla)). +This very simple assertion describes a test where the [model](support/model_based/IBC.tla) variable `actionOutcome` reaches the value `"ICS02UpdateOK"`, which occurs when a light client is successfully updated to a new height (see [ICS02.tla](support/model_based/ICS02.tla)). To generate a test from the `ICS02UpdateOKTest` assertion, we first define an invariant negating it: ```tla @@ -26,8 +26,8 @@ Because the invariant is wrong, `Apalache` will find a counterexample showing th ### Current limitations -The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples like those in [tests/](tests/). -These are currently generated manually, but can be easily mapped to Rust (see [step.rs](../../step.rs)). +The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples like those in [support/model_based/tests/](support/model_based/tests/). +These are currently generated manually, but can be easily mapped to Rust (see [step.rs](step.rs)). ### Running the model-based tests From fb20ce0161ff8ad7009b68af9ff8978e508f4ee9 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 14:17:31 +0100 Subject: [PATCH 045/104] IBCTestExecutor: Map from ChainId (instead of String) to MockContext --- modules/tests/model_based.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 906aa64a2f..1b411914e5 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -26,7 +26,7 @@ use tendermint::account::Id as AccountId; #[derive(Debug)] struct IBCTestExecutor { // mapping from chain identifier to its context - contexts: HashMap, + contexts: HashMap, } impl IBCTestExecutor { @@ -39,9 +39,10 @@ impl IBCTestExecutor { /// Create a `MockContext` for a given `chain_id`. /// Panic if a context for `chain_id` already exists. fn init_chain_context(&mut self, chain_id: String, initial_height: u64) { + let chain_id = Self::chain_id(chain_id); let max_history_size = 1; let ctx = MockContext::new( - ChainId::new(chain_id.clone(), Self::epoch()), + chain_id.clone(), HostType::Mock, max_history_size, Height::new(Self::epoch(), initial_height), @@ -51,17 +52,17 @@ impl IBCTestExecutor { /// Returns a reference to the `MockContext` of a given `chain_id`. /// Panic if the context for `chain_id` is not found. - fn chain_context(&self, chain_id: &String) -> &MockContext { + fn chain_context(&self, chain_id: String) -> &MockContext { self.contexts - .get(chain_id) + .get(&Self::chain_id(chain_id)) .expect("chain context should have been initialized") } /// Returns a mutable reference to the `MockContext` of a given `chain_id`. /// Panic if the context for `chain_id` is not found. - fn chain_context_mut(&mut self, chain_id: &String) -> &mut MockContext { + fn chain_context_mut(&mut self, chain_id: String) -> &mut MockContext { self.contexts - .get_mut(chain_id) + .get_mut(&Self::chain_id(chain_id)) .expect("chain context should have been initialized") } @@ -92,6 +93,10 @@ impl IBCTestExecutor { .clone() } + fn chain_id(chain_id: String) -> ChainId { + ChainId::new(chain_id, Self::epoch()) + } + // TODO: this is sometimes called version/revision number but seems // unrelated with the `Version` type; is that so? fn epoch() -> u64 { @@ -130,7 +135,7 @@ impl IBCTestExecutor { /// Check that chain heights match the ones in the model. fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { - let ctx = self.chain_context(&chain_id); + let ctx = self.chain_context(chain_id); ctx.query_latest_height() == Self::height(chain.height) }) } @@ -170,7 +175,7 @@ impl modelator::TestExecutor for IBCTestExecutor { .expect("create client action should have a client height"); // get chain's context - let ctx = self.chain_context_mut(&chain_id); + let ctx = self.chain_context_mut(chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { @@ -205,7 +210,7 @@ impl modelator::TestExecutor for IBCTestExecutor { .expect("update client action should have a client height"); // get chain's context - let ctx = self.chain_context_mut(&chain_id); + let ctx = self.chain_context_mut(chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { From 75db6bb9621e3a6db269100332e137d3a526a822 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 14:20:24 +0100 Subject: [PATCH 046/104] s/epoch/revision --- modules/tests/model_based.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 1b411914e5..8927aa78dc 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -45,7 +45,7 @@ impl IBCTestExecutor { chain_id.clone(), HostType::Mock, max_history_size, - Height::new(Self::epoch(), initial_height), + Height::new(Self::revision(), initial_height), ); assert!(self.contexts.insert(chain_id, ctx).is_none()); } @@ -94,12 +94,10 @@ impl IBCTestExecutor { } fn chain_id(chain_id: String) -> ChainId { - ChainId::new(chain_id, Self::epoch()) + ChainId::new(chain_id, Self::revision()) } - // TODO: this is sometimes called version/revision number but seems - // unrelated with the `Version` type; is that so? - fn epoch() -> u64 { + fn revision() -> u64 { 0 } @@ -109,7 +107,7 @@ impl IBCTestExecutor { } fn height(height: u64) -> Height { - Height::new(Self::epoch(), height) + Height::new(Self::revision(), height) } fn mock_header(height: u64) -> MockHeader { From a10286398eee2ff375e727720b716d1293bcf12c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 15:45:43 +0100 Subject: [PATCH 047/104] Move from eyre to thiserror --- modules/Cargo.toml | 1 - modules/tests/model_based.rs | 6 ++--- modules/tests/modelator.rs | 52 +++++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/modules/Cargo.toml b/modules/Cargo.toml index c84b1ff5b9..1a4a2c29b9 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -54,6 +54,5 @@ version = "=0.18.0" optional = true [dev-dependencies] -eyre = "0.6.5" tokio = { version = "1.0", features = ["macros"] } tendermint-testgen = { version = "=0.18.0" } # Needed for generating (synthetic) light blocks. diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 8927aa78dc..81e5d64d3a 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -258,11 +258,11 @@ fn model_based() { let tests = vec!["ICS02UpdateOKTest", "ICS02HeaderVerificationFailureTest"]; for test in tests { - let path = format!("{}/{}.json", TESTS_DIR, test); - let executor = IBCTestExecutor::new(); + let test_path = format!("{}/{}.json", TESTS_DIR, test); + let test_executor = IBCTestExecutor::new(); // we should be able to just return the `Result` once the following issue // is fixed: https://github.com/rust-lang/rust/issues/43301 - if let Err(e) = modelator::test_driver(executor, path) { + if let Err(e) = modelator::test(test_executor, &test_path) { panic!("{:?}", e); } } diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index 6f0f9b7b22..61e0c3e95f 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -1,29 +1,50 @@ -use eyre::{eyre, Context, Result}; use serde::de::DeserializeOwned; use std::fmt::Debug; use std::fs::File; use std::io::BufReader; -use std::path::Path; +use thiserror::Error; +#[derive(Error, Debug)] +pub enum ModelatorError { + #[error("test '{path}' not found: {error}")] + TestNotFound { path: String, error: String }, + #[error("test '{path}' could not be deserialized: {error}")] + InvalidTest { path: String, error: String }, + #[error("test '{path}' failed on step {step_index}/{step_count}:\nstep:\n{step:#?}\nexecutor:\n{executor:#?}")] + FailedTest { + path: String, + step_index: usize, + step_count: usize, + step: Step, + executor: Executor, + }, +} pub trait TestExecutor { fn initial_step(&mut self, step: S) -> bool; fn next_step(&mut self, step: S) -> bool; } -pub fn test_driver(mut executor: Executor, path: P) -> Result<()> +pub fn test( + mut executor: Executor, + path: &str, +) -> Result<(), ModelatorError> where - Executor: TestExecutor + Debug, - Step: DeserializeOwned + Debug + Clone, - P: AsRef, + Executor: TestExecutor + Debug, + State: DeserializeOwned + Debug + Clone, { // open test file - let file = File::open(path.as_ref()) - .wrap_err_with(|| format!("test {:?} not found.", path.as_ref()))?; + let file = File::open(path).map_err(|error| ModelatorError::TestNotFound { + path: path.to_string(), + error: error.to_string(), + })?; let reader = BufReader::new(file); // parse test file - let steps: Vec = serde_json::de::from_reader(reader) - .wrap_err_with(|| format!("test {:?} could not be deserialized", path.as_ref()))?; + let steps: Vec = + serde_json::de::from_reader(reader).map_err(|error| ModelatorError::InvalidTest { + path: path.to_string(), + error: error.to_string(), + })?; let step_count = steps.len(); for (i, step) in steps.into_iter().enumerate() { @@ -35,14 +56,13 @@ where }; if !ok { - return Err(eyre!( - "test {:?} failed on step {}/{}:\n{:#?}\n\nexecutor:\n{:#?}", - path.as_ref(), - i + 1, + return Err(ModelatorError::FailedTest { + path: path.to_string(), + step_index: i + 1, step_count, step, - executor - )); + executor, + }); } } Ok(()) From 2e5d6de82f69a14046b8555f95c706701b140415 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 16:33:56 +0100 Subject: [PATCH 048/104] Improve README --- modules/tests/README.md | 31 +++++++++++++++++-- modules/tests/support/model_based/IBC.cfg | 1 - .../tests/support/model_based/IBCTests.cfg | 1 - 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index e3d19d2813..23bab24365 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -1,27 +1,52 @@ ## Model-based tests for IBC modules +### The model + This directory contains the model-based tests for the IBC modules. They are "model-based" because they are generated from a `TLA+` model of the IBC modules (see [IBC.tla](support/model_based/IBC.tla)). -Tests are `TLA+` assertions that describe the desired shape of the test. One of the assertions in [IBCTests.tla](support/model_based/IBCTests.tla) is the following: +To instantiate the model, we define in [IBC.cfg](support/model_based/IBC.cfg) the following model constants: + - `ChainIds = {"chain-A", "chain-B"}`, indicating that two chains, `chain-A` and `chain-B`, will be created + - `MaxClientsPerChain = 1`, indicating that at most 1 client per chain will be created + - `MaxClientHeight = 2`, indicating that clients will reach at most height 2 + +The [IBC.cfg](support/model_based/IBC.cfg) file also defines two simple invariants: +```tla +INVARIANTS + TypeOK + ModelNeverErrors +``` + +Then, we can ask [`Apalache`](https://apalache.informal.systems), a model checker for `TLA+`, to check that these invariants hold: +```bash +apalache-mc check --inv=ICS02UpdateOKTestNeg IBC.tla +``` + +The above command automatically reads what we have defined in [IBC.cfg](support/model_based/IBC.cfg). + +### The tests + +Tests are `TLA+` assertions that describe the desired shape of the test (see [IBCTests.tla](support/model_based/IBCTests.tla)). One of the assertions in [IBCTests.tla](support/model_based/IBCTests.tla) is the following: ```tla ICS02UpdateOKTest == /\ actionOutcome = "ICS02UpdateOK" ``` -This very simple assertion describes a test where the [model](support/model_based/IBC.tla) variable `actionOutcome` reaches the value `"ICS02UpdateOK"`, which occurs when a light client is successfully updated to a new height (see [ICS02.tla](support/model_based/ICS02.tla)). +This very simple assertion describes a test where the [model](support/model_based/IBC.tla) variable `actionOutcome` reaches the value `"ICS02UpdateOK"`, which occurs when a client is successfully updated to a new height (see [ICS02.tla](support/model_based/ICS02.tla)). To generate a test from the `ICS02UpdateOKTest` assertion, we first define an invariant negating it: ```tla ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ``` -Then, we ask [`Apalache`](https://apalache.informal.systems), a model checker for `TLA+`, to prove it: +Then, we ask [`Apalache`], to prove it: ```bash apalache-mc check --inv=ICS02UpdateOKTestNeg IBCTests.tla ``` +(Again, the above command automatically reads what we have defined in [IBCTests.cfg](support/model_based/IBCTests.cfg).) + Because the invariant is wrong, `Apalache` will find a counterexample showing that it is indeed possible that a light-client is sucessfully updated to a new height. This counterexample is our test. ### Current limitations diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 3bcce4efea..b9ed63584a 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -2,7 +2,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} MaxClientsPerChain = 1 MaxClientHeight = 2 - MaxConnectionsPerChain = 2 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 8ce87d740b..a499c75463 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -2,7 +2,6 @@ CONSTANTS ChainIds = {"chain-A", "chain-B"} MaxClientsPerChain = 1 MaxClientHeight = 2 - MaxConnectionsPerChain = 2 INIT Init NEXT Next From dfb683ddde7bff90236621189a2db3177a2c9711 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 16:38:09 +0100 Subject: [PATCH 049/104] Improve README --- modules/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index 23bab24365..da1c7a3546 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -47,7 +47,7 @@ apalache-mc check --inv=ICS02UpdateOKTestNeg IBCTests.tla (Again, the above command automatically reads what we have defined in [IBCTests.cfg](support/model_based/IBCTests.cfg).) -Because the invariant is wrong, `Apalache` will find a counterexample showing that it is indeed possible that a light-client is sucessfully updated to a new height. This counterexample is our test. +Because the invariant is wrong, `Apalache` will find a counterexample showing that it is indeed possible that a client is sucessfully updated to a new height. This counterexample is our test. ### Current limitations From 7e24841f3d61eafe83ed76f745deca05fb54508d Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 9 Feb 2021 16:44:10 +0100 Subject: [PATCH 050/104] Improve arguments order in modelator::test --- modules/tests/model_based.rs | 6 +++--- modules/tests/modelator.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 81e5d64d3a..5f11385afd 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -258,11 +258,11 @@ fn model_based() { let tests = vec!["ICS02UpdateOKTest", "ICS02HeaderVerificationFailureTest"]; for test in tests { - let test_path = format!("{}/{}.json", TESTS_DIR, test); - let test_executor = IBCTestExecutor::new(); + let test = format!("{}/{}.json", TESTS_DIR, test); + let executor = IBCTestExecutor::new(); // we should be able to just return the `Result` once the following issue // is fixed: https://github.com/rust-lang/rust/issues/43301 - if let Err(e) = modelator::test(test_executor, &test_path) { + if let Err(e) = modelator::test(&test, executor) { panic!("{:?}", e); } } diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index 61e0c3e95f..cbd15b18e3 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -25,8 +25,8 @@ pub trait TestExecutor { } pub fn test( - mut executor: Executor, path: &str, + mut executor: Executor, ) -> Result<(), ModelatorError> where Executor: TestExecutor + Debug, From 5d6bf08c7fcfe4d9040c661f0f044ebf641ea31f Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 10 Feb 2021 15:00:53 +0100 Subject: [PATCH 051/104] Improve chain identifiers --- modules/tests/support/model_based/IBC.cfg | 2 +- .../tests/support/model_based/IBCTests.cfg | 2 +- .../ICS02HeaderVerificationFailureTest.json | 16 ++++---- .../model_based/tests/ICS02UpdateOKTest.json | 40 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index b9ed63584a..73976184c4 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,5 +1,5 @@ CONSTANTS - ChainIds = {"chain-A", "chain-B"} + ChainIds = {"chainA-0", "chainB-0"} MaxClientsPerChain = 1 MaxClientHeight = 2 diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index a499c75463..e4c28bc288 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,5 +1,5 @@ CONSTANTS - ChainIds = {"chain-A", "chain-B"} + ChainIds = {"chainA-0", "chainB-0"} MaxClientsPerChain = 1 MaxClientHeight = 2 diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index e19671052a..32a85c138a 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -5,43 +5,43 @@ }, "actionOutcome": "None", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 0 } } }, { "action": { - "chainId": "chain-B", + "chainId": "chainB-0", "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 1 } } }, { "action": { - "chainId": "chain-B", + "chainId": "chainB-0", "clientHeight": 1, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02HeaderVerificationFailure", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 1 } } diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index 86f427443f..5275bfcda3 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -5,109 +5,109 @@ }, "actionOutcome": "None", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 0 } } }, { "action": { - "chainId": "chain-B", + "chainId": "chainB-0", "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 1 } } }, { "action": { - "chainId": "chain-B", + "chainId": "chainB-0", "clientHeight": 2, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 0 }, - "chain-B": { + "chainB-0": { "height": 2 } } }, { "action": { - "chainId": "chain-A", + "chainId": "chainA-0", "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 1 }, - "chain-B": { + "chainB-0": { "height": 2 } } }, { "action": { - "chainId": "chain-A", + "chainId": "chainA-0", "clientHeight": 2, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 2 }, - "chain-B": { + "chainB-0": { "height": 2 } } }, { "action": { - "chainId": "chain-A", + "chainId": "chainA-0", "clientHeight": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 3 }, - "chain-B": { + "chainB-0": { "height": 2 } } }, { "action": { - "chainId": "chain-A", + "chainId": "chainA-0", "clientHeight": 2, "clientId": 1, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chain-A": { + "chainA-0": { "height": 4 }, - "chain-B": { + "chainB-0": { "height": 2 } } From 60e4aba3fba998c10243058095e54e97a7a7cfbb Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 10 Feb 2021 20:06:51 +0100 Subject: [PATCH 052/104] Improve README --- modules/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index da1c7a3546..54e6491585 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -39,7 +39,7 @@ To generate a test from the `ICS02UpdateOKTest` assertion, we first define an in ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ``` -Then, we ask [`Apalache`], to prove it: +Then, we ask `Apalache`, to prove it: ```bash apalache-mc check --inv=ICS02UpdateOKTestNeg IBCTests.tla From c700ba5210aaec601206e45455495e7c14267252 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 10 Feb 2021 20:32:39 +0100 Subject: [PATCH 053/104] Start ICS03 --- modules/src/ics24_host/identifier.rs | 6 + modules/tests/model_based.rs | 214 +++++++++++++++++- modules/tests/step.rs | 38 +++- modules/tests/support/model_based/IBC.cfg | 1 + modules/tests/support/model_based/IBC.tla | 200 +++++++++++++++- .../tests/support/model_based/IBCTests.cfg | 1 + .../tests/support/model_based/IBCTests.tla | 24 ++ modules/tests/support/model_based/ICS03.tla | 158 +++++++++++++ .../tests/ICS03ConnectionMismatchTest.json | 69 ++++++ .../tests/ICS03ConnectionNotFoundTest.json | 52 +++++ .../tests/ICS03ConnectionOpenInitOKTest.json | 49 ++++ .../tests/ICS03ConnectionOpenTryOKTest.json | 52 +++++ .../ICS03InvalidConsensusHeightTest.json | 36 +++ .../tests/ICS03MissingClientTest.json | 65 ++++++ 14 files changed, 953 insertions(+), 12 deletions(-) create mode 100644 modules/tests/support/model_based/ICS03.tla create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json create mode 100644 modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json create mode 100644 modules/tests/support/model_based/tests/ICS03MissingClientTest.json diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index e76c9f7d60..ce5cadc5ca 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -197,6 +197,12 @@ impl PartialEq for ClientId { pub struct ConnectionId(String); impl ConnectionId { + pub fn new(counter: u64) -> Result { + let prefix = ConnectionId::default().to_string(); + let id = format!("{}-{}", prefix, counter); + Self::from_str(id.as_str()) + } + /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 5f11385afd..1521c1fa82 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -7,15 +7,23 @@ use ibc::ics02_client::error::Kind as ICS02ErrorKind; use ibc::ics02_client::msgs::create_client::MsgCreateAnyClient; use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; +use ibc::ics03_connection::connection::Counterparty; +use ibc::ics03_connection::error::Kind as ICS03ErrorKind; +use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; +use ibc::ics03_connection::msgs::ConnectionMsg; +use ibc::ics03_connection::version::Version; use ibc::ics18_relayer::context::ICS18Context; use ibc::ics18_relayer::error::{Error as ICS18Error, Kind as ICS18ErrorKind}; -use ibc::ics24_host::identifier::{ChainId, ClientId}; +use ibc::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes}; +use ibc::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; use ibc::ics26_routing::error::{Error as ICS26Error, Kind as ICS26ErrorKind}; use ibc::ics26_routing::msgs::ICS26Envelope; use ibc::mock::client_state::{MockClientState, MockConsensusState}; use ibc::mock::context::MockContext; use ibc::mock::header::MockHeader; use ibc::mock::host::HostType; +use ibc::proofs::{ConsensusProof, Proofs}; use ibc::Height; use std::collections::HashMap; use std::error::Error; @@ -101,11 +109,24 @@ impl IBCTestExecutor { 0 } + fn version() -> Version { + Version::default() + } + + fn versions() -> Vec { + vec![Self::version()] + } + fn client_id(client_id: u64) -> ClientId { ClientId::new(ClientType::Mock, client_id) .expect("it should be possible to create the client identifier") } + fn connection_id(connection_id: u64) -> ConnectionId { + ConnectionId::new(connection_id) + .expect("it should be possible to create the connection identifier") + } + fn height(height: u64) -> Height { Height::new(Self::revision(), height) } @@ -130,6 +151,48 @@ impl IBCTestExecutor { AccountId::new([0; 20]) } + fn counterparty(client_id: u64, connection_id: Option) -> Counterparty { + let client_id = Self::client_id(client_id); + let connection_id = connection_id.map(|connection_id| Self::connection_id(connection_id)); + let prefix = Self::commitment_prefix(); + Counterparty::new(client_id, connection_id, prefix) + } + + fn delay_period() -> u64 { + 0 + } + + fn commitment_prefix() -> CommitmentPrefix { + vec![0].into() + } + + fn commitment_proof_bytes() -> CommitmentProofBytes { + vec![0].into() + } + + fn consensus_proof(height: u64) -> ConsensusProof { + let consensus_proof = Self::commitment_proof_bytes(); + let consensus_height = Self::height(height); + ConsensusProof::new(consensus_proof, consensus_height) + .expect("it should be possible to create the consensus proof") + } + + fn proofs(height: u64) -> Proofs { + let object_proof = Self::commitment_proof_bytes(); + let client_proof = None; + let consensus_proof = Some(Self::consensus_proof(height)); + let other_proof = None; + let height = Self::height(height); + Proofs::new( + object_proof, + client_proof, + consensus_proof, + other_proof, + height, + ) + .expect("it should be possible to create the proofs") + } + /// Check that chain heights match the ones in the model. fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { @@ -245,6 +308,142 @@ impl modelator::TestExecutor for IBCTestExecutor { action => panic!("unexpected action outcome {:?}", action), } } + ActionType::ICS03ConnectionOpenInit => { + // get action parameters + let chain_id = step + .action + .chain_id + .expect("connection open init action should have a chain identifier"); + let client_id = step + .action + .client_id + .expect("connection open init action should have a client identifier"); + let counterparty_client_id = step.action.counterparty_client_id.expect( + "connection open init action should have a counterparty client identifier", + ); + + // get chain's context + let ctx = self.chain_context_mut(chain_id); + + // create ICS26 message and deliver it + let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenInit( + MsgConnectionOpenInit { + client_id: Self::client_id(client_id), + counterparty: Self::counterparty(counterparty_client_id, None), + version: Self::version(), + delay_period: Self::delay_period(), + signer: Self::signer(), + }, + )); + let result = ctx.deliver(msg); + + // check the expected outcome + match step.action_outcome { + ActionOutcome::ICS03ConnectionOpenInitOK => { + // the implementaion matches the model if no error occurs + result.is_ok() + } + ActionOutcome::ICS03MissingClient => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + matches!( + handler_error_kind, + ICS03ErrorKind::MissingClient(error_client_id) + if error_client_id == Self::client_id(client_id) + ) + } + action => panic!("unexpected action outcome {:?}", action), + } + } + ActionType::ICS03ConnectionOpenTry => { + // get action parameters + let chain_id = step + .action + .chain_id + .expect("connection open try action should have a chain identifier"); + let client_id = step + .action + .client_id + .expect("connection open try action should have a client identifier"); + let client_height = step + .action + .client_height + .expect("connection open try action should have a client height"); + let counterparty_client_id = step.action.counterparty_client_id.expect( + "connection open try action should have a counterparty client identifier", + ); + let connection_id = step.action.connection_id; + let counterparty_connection_id = step.action.counterparty_connection_id.expect( + "connection open try action should have a counterparty connection identifier", + ); + + // get chain's context + let ctx = self.chain_context_mut(chain_id); + + // create ICS26 message and deliver it + let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( + MsgConnectionOpenTry { + previous_connection_id: connection_id.map(Self::connection_id), + client_id: Self::client_id(client_id), + client_state: None, + counterparty: Self::counterparty( + counterparty_client_id, + Some(counterparty_connection_id), + ), + counterparty_versions: Self::versions(), + proofs: Self::proofs(client_height), + delay_period: Self::delay_period(), + signer: Self::signer(), + }, + ))); + let result = ctx.deliver(msg); + + // check the expected outcome + match step.action_outcome { + ActionOutcome::ICS03ConnectionOpenTryOK => { + // the implementaion matches the model if no error occurs + result.is_ok() + } + ActionOutcome::ICS03InvalidConsensusHeight => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + matches!( + handler_error_kind, + ICS03ErrorKind::InvalidConsensusHeight(error_consensus_height, _) + if error_consensus_height == Self::height(client_height) + ) + } + ActionOutcome::ICS03ConnectionNotFound => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + connection_id.is_some() + && matches!( + handler_error_kind, + ICS03ErrorKind::ConnectionNotFound(error_connection_id) + if error_connection_id == Self::connection_id(connection_id.unwrap()) + ) + } + ActionOutcome::ICS03ConnectionMismatch => { + let handler_error_kind = + Self::extract_handler_error_kind::(result); + // the implementaion matches the model if there's an + // error matching the expected outcome + connection_id.is_some() + && matches!( + handler_error_kind, + ICS03ErrorKind::ConnectionMismatch(error_connection_id) + if error_connection_id == Self::connection_id(connection_id.unwrap()) + ) + } + action => panic!("unexpected action outcome {:?}", action), + } + } }; // also check that chain heights match outcome_matches && self.check_chain_heights(step.chains) @@ -254,8 +453,17 @@ impl modelator::TestExecutor for IBCTestExecutor { const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] -fn model_based() { - let tests = vec!["ICS02UpdateOKTest", "ICS02HeaderVerificationFailureTest"]; +fn main() { + let tests = vec![ + "ICS02UpdateOKTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", + ]; for test in tests { let test = format!("{}/{}.json", TESTS_DIR, test); diff --git a/modules/tests/step.rs b/modules/tests/step.rs index 98c831e050..b1dae82dad 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -1,4 +1,4 @@ -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; use std::collections::HashMap; use std::fmt::Debug; @@ -25,6 +25,32 @@ pub struct Action { #[serde(alias = "clientHeight")] pub client_height: Option, + + #[serde(alias = "counterpartyClientId")] + pub counterparty_client_id: Option, + + #[serde(alias = "connectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + pub connection_id: Option, + + #[serde(alias = "counterpartyConnectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + pub counterparty_connection_id: Option, +} + +/// On the model, a non-existing `connection_id` is represented with -1. +/// For this reason, this function maps a `Some(-1)` to a `None`. +fn deserialize_connection_id<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let connection_id: Option = Deserialize::deserialize(deserializer)?; + let connection_id = if connection_id == Some(-1) { + None + } else { + connection_id.map(|connection_id| connection_id as u64) + }; + Ok(connection_id) } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -32,6 +58,8 @@ pub enum ActionType { None, ICS02CreateClient, ICS02UpdateClient, + ICS03ConnectionOpenInit, + ICS03ConnectionOpenTry, } #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -41,9 +69,15 @@ pub enum ActionOutcome { ICS02UpdateOK, ICS02ClientNotFound, ICS02HeaderVerificationFailure, + ICS03ConnectionOpenInitOK, + ICS03MissingClient, + ICS03ConnectionOpenTryOK, + ICS03InvalidConsensusHeight, + ICS03ConnectionNotFound, + ICS03ConnectionMismatch, } #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct Chain { pub height: u64, -} +} \ No newline at end of file diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 73976184c4..140fe49ebb 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -2,6 +2,7 @@ CONSTANTS ChainIds = {"chainA-0", "chainB-0"} MaxClientsPerChain = 1 MaxClientHeight = 2 + MaxConnectionsPerChain = 2 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 7586626558..89ddfe6de2 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,6 +1,6 @@ --------------------------------- MODULE IBC ---------------------------------- -EXTENDS Integers, FiniteSets, ICS02 +EXTENDS Integers, FiniteSets, ICS02, ICS03 \* ids of existing chains CONSTANT ChainIds @@ -10,6 +10,9 @@ ASSUME MaxClientsPerChain >= 0 \* max height which clients can reach CONSTANT MaxClientHeight ASSUME MaxClientHeight >= 0 +\* max number of connections to be created per chain +CONSTANT MaxConnectionsPerChain +ASSUME MaxConnectionsPerChain >= 0 \* mapping from chain id to its data VARIABLE chains @@ -27,7 +30,10 @@ ActionType == [ type |-> STRING, chainId |-> STRING, clientHeight |-> Int, - clientId |-> Int + clientId |-> Int, + connectionId |-> Int, + counterpartyClientId |-> Int, + counterpartyConnectionId |-> Int ] AsAction(a) == a <: ActionType (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) @@ -38,6 +44,15 @@ ChainHeights == Int ClientIds == 0..(MaxClientsPerChain - 1) \* set of possible client heights ClientHeights == 1..MaxClientHeight +\* set of possible connection identifiers +ConnectionIds == 0..(MaxConnectionsPerChain- 1) +\* set of possible connection states +ConnectionStates == { + "Uninit", + "Init", + "TryOpen", + "Open" +} \* data kept per cliennt Client == [ @@ -47,11 +62,25 @@ Client == [ Clients == [ ClientIds -> Client ] +\* data kept per connection +Connection == [ + state: ConnectionStates, + clientId: ClientIds \union {ClientIdNone}, + counterpartyClientId: ClientIds \union {ClientIdNone}, + connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} +] +\* mapping from connection identifier to its data +Connections == [ + ConnectionIds -> Connection +] \* data kept per chain Chain == [ height: ChainHeights, clients: Clients, - clientIdCounter: 0..MaxClientsPerChain + clientIdCounter: 0..MaxClientsPerChain, + connections: Connections, + connectionIdCounter: 0..MaxConnectionsPerChain ] \* mapping from chain identifier to its data Chains == [ @@ -73,10 +102,27 @@ UpdateClientActions == [ clientHeight: ClientHeights, clientId: ClientIds ] <: {ActionType} +ConnectionOpenInitActions == [ + type: {"ICS03ConnectionOpenInit"}, + chainId: ChainIds, + clientId: ClientIds, + counterpartyClientId: ClientIds +] <: {ActionType} +ConnectionOpenTryActions == [ + type: {"ICS03ConnectionOpenTry"}, + chainId: ChainIds, + clientHeight: ClientHeights, + clientId: ClientIds, + counterpartyClientId: ClientIds, + connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyConnectionId: ConnectionIds +] <: {ActionType} Actions == NoneActions \union CreateClientActions \union - UpdateClientActions + UpdateClientActions \union + ConnectionOpenInitActions \union + ConnectionOpenTryActions \* set of possible action outcomes ActionOutcomes == { @@ -87,7 +133,15 @@ ActionOutcomes == { \* ICS02_UpdateClient outcomes: "ICS02UpdateOK", "ICS02ClientNotFound", - "ICS02HeaderVerificationFailure" + "ICS02HeaderVerificationFailure", + \* ICS03_ConnectionOpenInit outcomes: + "ICS03ConnectionOpenInitOK", + "ICS03MissingClient", + \* ICS03_ConnectionOpenTry outcomes: + "ICS03ConnectionOpenTryOK", + "ICS03InvalidConsensusHeight", + "ICS03ConnectionNotFound", + "ICS03ConnectionMismatch" } (***************************** Specification *********************************) @@ -133,6 +187,75 @@ UpdateClient(chainId, clientId, clientHeight) == clientHeight |-> clientHeight]) /\ actionOutcome' = result.outcome +ConnectionOpenInit(chainId, clientId, counterpartyClientId) == + LET chain == chains[chainId] IN + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN + LET result == ICS03_ConnectionOpenInit( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId + ) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), + !.connections = result.connections, + !.connectionIdCounter = result.connectionIdCounter + ] IN + \* update `chains`, set the `action` and its `actionOutcome` + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([ + type |-> "ICS03ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId]) + /\ actionOutcome' = result.outcome + +ConnectionOpenTry( + chainId, + clientId, + clientHeight, + connectionId, + counterpartyClientId, + counterpartyConnectionId +) == + LET chain == chains[chainId] IN + LET height == chain.height IN + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN + LET result == ICS03_ConnectionOpenTry( + height, + clients, + connections, + connectionIdCounter, + clientId, + clientHeight, + connectionId, + counterpartyClientId, + counterpartyConnectionId + ) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), + !.connections = result.connections, + !.connectionIdCounter = result.connectionIdCounter + ] IN + \* update `chains`, set the `action` and its `actionOutcome` + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = AsAction([ + type |-> "ICS03ConnectionOpenTry", + chainId |-> chainId, + clientId |-> clientId, + clientHeight |-> clientHeight, + connectionId |-> connectionId, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId]) + /\ actionOutcome' = result.outcome + CreateClientAction == \* select a chain id \E chainId \in ChainIds: @@ -154,16 +277,77 @@ UpdateClientAction == \E clientHeight \in ClientHeights: UpdateClient(chainId, clientId, clientHeight) +ConnectionOpenInitAction == + \* select a chain id + \E chainId \in ChainIds: + \* select a client id + \E clientId \in ClientIds: + \* select a counterparty client id + \E counterpartyClientId \in ClientIds: + \* only create connection if the model constant `MaxConnectionsPerChain` + \* allows it + IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + ConnectionOpenInit(chainId, clientId, counterpartyClientId) + ELSE + UNCHANGED vars + +ConnectionOpenTryAction == + \* select a chain id + \E chainId \in ChainIds: + \* select a client id + \E clientId \in ClientIds: + \* select a claimed height for the client + \E clientHeight \in ClientHeights: + \* select a connection id (which can be none) + \E connectionId \in ConnectionIds \union {ConnectionIdNone}: + \* select a counterparty client id + \E counterpartyClientId \in ClientIds: + \* select a counterparty connection id + \E counterpartyConnectionId \in ConnectionIds: + IF connectionId = ConnectionIdNone THEN + \* in this case we're trying to create a new connection; only create + \* connection if the model constant `MaxConnectionsPerChain` allows + \* it + IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + ConnectionOpenTry( + chainId, + clientId, + clientHeight, + connectionId, + counterpartyClientId, + counterpartyConnectionId + ) + ELSE + UNCHANGED vars + ELSE + ConnectionOpenTry( + chainId, + clientId, + clientHeight, + connectionId, + counterpartyClientId, + counterpartyConnectionId + ) + Init == - \* create a client with none values + \* create a client and a connection with none values LET clientNone == [ height |-> HeightNone ] IN + LET connectionNone == [ + state |-> "Uninit", + clientId |-> ClientIdNone, + counterpartyClientId |-> ClientIdNone, + connectionId |-> ConnectionIdNone, + counterpartyConnectionId |-> ConnectionIdNone + ] IN \* create an empty chain LET emptyChain == [ height |-> 0, clients |-> [clientId \in ClientIds |-> clientNone], - clientIdCounter |-> 0 + clientIdCounter |-> 0, + connections |-> [connectionId \in ConnectionIds |-> connectionNone], + connectionIdCounter |-> 0 ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] /\ action = AsAction([type |-> "None"]) @@ -172,6 +356,8 @@ Init == Next == \/ CreateClientAction \/ UpdateClientAction + \/ ConnectionOpenInitAction + \/ ConnectionOpenTryAction \/ UNCHANGED vars (******************************** Invariants *********************************) diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index e4c28bc288..af4cc9337f 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -2,6 +2,7 @@ CONSTANTS ChainIds = {"chainA-0", "chainB-0"} MaxClientsPerChain = 1 MaxClientHeight = 2 + MaxConnectionsPerChain = 2 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 245461c3c9..b8e5271d9f 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -14,9 +14,33 @@ ICS02ClientNotFoundTest == ICS02HeaderVerificationFailureTest == /\ actionOutcome = "ICS02HeaderVerificationFailure" +ICS03ConnectionOpenInitOKTest == + /\ actionOutcome = "ICS03ConnectionOpenInitOK" + +ICS03MissingClientTest == + /\ actionOutcome = "ICS03MissingClient" + +ICS03ConnectionOpenTryOKTest == + /\ actionOutcome = "ICS03ConnectionOpenTryOK" + +ICS03InvalidConsensusHeightTest == + /\ actionOutcome = "ICS03InvalidConsensusHeight" + +ICS03ConnectionNotFoundTest == + /\ actionOutcome = "ICS03ConnectionNotFound" + +ICS03ConnectionMismatchTest == + /\ actionOutcome = "ICS03ConnectionMismatch" + ICS02CreateOKTestNeg == ~ICS02CreateOKTest ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ICS02ClientNotFoundTestNeg == ~ICS02ClientNotFoundTest ICS02HeaderVerificationFailureTestNeg == ~ICS02HeaderVerificationFailureTest +ICS03ConnectionOpenInitOKTestNeg == ~ICS03ConnectionOpenInitOKTest +ICS03MissingClientTestNeg == ~ICS03MissingClientTest +ICS03ConnectionOpenTryOKTestNeg == ~ICS03ConnectionOpenTryOKTest +ICS03InvalidConsensusHeightTestNeg == ~ICS03InvalidConsensusHeightTest +ICS03ConnectionNotFoundTestNeg == ~ICS03ConnectionNotFoundTest +ICS03ConnectionMismatchTestNeg == ~ICS03ConnectionMismatchTest =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla new file mode 100644 index 0000000000..e9b3096a7f --- /dev/null +++ b/modules/tests/support/model_based/ICS03.tla @@ -0,0 +1,158 @@ +------------------------------ MODULE ICS03 ----------------------------------- + +EXTENDS Integers, FiniteSets, IBCDefinitions, ICS02 + +\* retrieves `connectionId`'s data +ICS03_GetConnection(connections, connectionId) == + connections[connectionId] + +\* check if `connectionId` exists +ICS03_ConnectionExists(connections, connectionId) == + ICS03_GetConnection(connections, connectionId).state /= "Uninit" + +\* update `connectionId`'s data +ICS03_SetConnection(connections, connectionId, connection) == + [connections EXCEPT ![connectionId] = connection] + +ICS03_ConnectionOpenInit( + clients, + connections, + connectionIdCounter, + clientId, + counterpartyClientId +) == + \* check if the client exists + IF ICS02_ClientExists(clients, clientId) THEN + \* if the client exists, + \* then check if the connection exists (it shouldn't) + IF ICS03_ConnectionExists(connections, connectionIdCounter) THEN + \* if the connection to be created already exists, + \* then there's an error in the model + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ModelError" + ] + ELSE + \* if it doesn't, create it + LET connection == [ + state |-> "Init", + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId, + connectionId |-> connectionIdCounter, + counterpartyConnectionId |-> ConnectionIdNone + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), + connectionIdCounter |-> connectionIdCounter + 1, + outcome |-> "ICS03ConnectionOpenInitOK" + ] + ELSE + \* if the client does not exist, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03MissingClient" + ] + +\* TODO: errors generated when verifying proofs are never an outcome of this +\* model +ICS03_ConnectionOpenTry( + chainHeight, + clients, + connections, + connectionIdCounter, + clientId, + clientClaimedHeight, + connectionId, + counterpartyClientId, + counterpartyConnectionId +) == + \* check if client's claimed height is higher than the chain's height + IF clientClaimedHeight > chainHeight THEN + \* if client's height is too advanced, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03InvalidConsensusHeight" + ] + \* TODO: add `chain_max_history_size` to the model to be able to also + \* return a `ICS03StaleConsensusHeight` error outcome + ELSE + \* check if a `connectionId` was set + IF connectionId /= ConnectionIdNone THEN + \* if so, check if the connection exists + IF ICS03_ConnectionExists(connections, connectionId) THEN + \* if the connection exists, verify that is matches the + \* the parameters provided + LET connection == ICS03_GetConnection( + connections, + connectionId + ) IN + IF /\ connection.state = "Init" + /\ connection.clientId = clientId + /\ connection.counterpartyClientId = counterpartyClientId + THEN + \* verification passed; update connection + LET updatedConnection == [ + state |-> "TryOpen", + clientId |-> clientId, + connectionId |-> connectionId, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionId, + updatedConnection + ), + \* as the connection identifier has already been + \* created, here we do not update the + \* `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionOpenTryOK" + ] + ELSE + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionMismatch" + ] + ELSE + \* if the connection does not exist, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + outcome |-> "ICS03ConnectionNotFound" + ] + ELSE + \* verification passed; create connection + LET connection == [ + state |-> "TryOpen", + clientId |-> clientId, + \* generate a new connection identifier + connectionId |-> connectionIdCounter, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), + \* since a new connection identifier has been created, here we + \* update the `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter + 1, + outcome |-> "ICS03ConnectionOpenTryOK" + ] + +=============================================================================== diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json new file mode 100644 index 0000000000..a652b34167 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -0,0 +1,69 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientId": 0, + "counterpartyClientId": 1, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 2 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientHeight": 2, + "clientId": 1, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionMismatch", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 2 + } + } + } +] diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json new file mode 100644 index 0000000000..d88923f9b9 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -0,0 +1,52 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientHeight": 1, + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionNotFound", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 1 + } + } + } +] diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json new file mode 100644 index 0000000000..38142cd831 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -0,0 +1,49 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 2 + } + } + } +] diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json new file mode 100644 index 0000000000..0683ad02ca --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -0,0 +1,52 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainA-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 1 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainA-0", + "clientHeight": 1, + "clientId": 0, + "connectionId": -1, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionOpenTryOK", + "chains": { + "chainA-0": { + "height": 2 + }, + "chainB-0": { + "height": 0 + } + } + } +] diff --git a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json new file mode 100644 index 0000000000..47100a553d --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json @@ -0,0 +1,36 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainA-0", + "clientHeight": 1, + "clientId": 0, + "connectionId": -1, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03InvalidConsensusHeight", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + } +] diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json new file mode 100644 index 0000000000..5aefb9f176 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json @@ -0,0 +1,65 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA-0": { + "height": 0 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainA-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 1 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainA-0", + "clientHeight": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA-0": { + "height": 2 + }, + "chainB-0": { + "height": 0 + } + } + }, + { + "action": { + "chainId": "chainB-0", + "clientId": 0, + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03MissingClient", + "chains": { + "chainA-0": { + "height": 2 + }, + "chainB-0": { + "height": 0 + } + } + } +] From 7233987acf60ad090c14514f5a4f4bc7678bb305 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 11 Feb 2021 17:02:51 +0100 Subject: [PATCH 054/104] Store all client heights and improve names in model output actions to match those in the implementation --- .../src/ics02_client/handler/update_client.rs | 5 + modules/tests/model_based.rs | 49 +++--- modules/tests/modelator.rs | 2 +- modules/tests/step.rs | 19 ++- modules/tests/support/model_based/IBC.cfg | 6 +- modules/tests/support/model_based/IBC.tla | 142 ++++++++---------- .../support/model_based/IBCDefinitions.tla | 25 ++- .../tests/support/model_based/IBCTests.cfg | 6 +- modules/tests/support/model_based/ICS02.tla | 15 +- modules/tests/support/model_based/ICS03.tla | 18 +-- .../ICS02HeaderVerificationFailureTest.json | 21 +-- .../model_based/tests/ICS02UpdateOKTest.json | 55 +++---- .../tests/ICS03ConnectionMismatchTest.json | 29 ++-- .../tests/ICS03ConnectionNotFoundTest.json | 23 +-- .../tests/ICS03ConnectionOpenInitOKTest.json | 19 +-- .../tests/ICS03ConnectionOpenTryOKTest.json | 23 +-- .../ICS03InvalidConsensusHeightTest.json | 14 +- .../tests/ICS03MissingClientTest.json | 28 ++-- 18 files changed, 267 insertions(+), 232 deletions(-) diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index 56f3062456..69c3a57a64 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -32,6 +32,8 @@ pub fn process( } = msg; // Read client type from the host chain store. The client should already exist. + // TODO: this first get is not needed; + // the client type can be retrieved using the client_state below let client_type = ctx .client_type(&client_id) .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; @@ -44,12 +46,15 @@ pub fn process( .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; let latest_height = client_state.latest_height(); + // TODO: how can the following error happen? + // it feels like it should be a panic, not an error ctx.consensus_state(&client_id, latest_height) .ok_or_else(|| Kind::ConsensusStateNotFound(client_id.clone(), latest_height))?; // Use client_state to validate the new header against the latest consensus_state. // This function will return the new client_state (its latest_height changed) and a // consensus_state obtained from header. These will be later persisted by the keeper. + // TODO: update_state is confusing as it actually doesn't update the state let (new_client_state, new_consensus_state) = client_def .check_header_and_update_state(client_state, header) .map_err(|e| Kind::HeaderVerificationFailure.context(e.to_string()))?; diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index 1521c1fa82..a27e110e1c 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -230,18 +230,22 @@ impl modelator::TestExecutor for IBCTestExecutor { .action .chain_id .expect("create client action should have a chain identifier"); - let client_height = step + let client_state = step .action - .client_height - .expect("create client action should have a client height"); + .client_state + .expect("create client action should have a client state"); + let consensus_state = step + .action + .consensus_state + .expect("create client action should have a consensus state"); // get chain's context let ctx = self.chain_context_mut(chain_id); // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::CreateClient(MsgCreateAnyClient { - client_state: Self::client_state(client_height), - consensus_state: Self::consensus_state(client_height), + client_state: Self::client_state(client_state), + consensus_state: Self::consensus_state(consensus_state), signer: Self::signer(), })); let result = ctx.deliver(msg); @@ -265,10 +269,10 @@ impl modelator::TestExecutor for IBCTestExecutor { .action .client_id .expect("update client action should have a client identifier"); - let client_height = step + let header = step .action - .client_height - .expect("update client action should have a client height"); + .header + .expect("update client action should have a header"); // get chain's context let ctx = self.chain_context_mut(chain_id); @@ -276,7 +280,7 @@ impl modelator::TestExecutor for IBCTestExecutor { // create ICS26 message and deliver it let msg = ICS26Envelope::ICS2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { client_id: Self::client_id(client_id), - header: Self::header(client_height), + header: Self::header(header), signer: Self::signer(), })); let result = ctx.deliver(msg); @@ -363,18 +367,18 @@ impl modelator::TestExecutor for IBCTestExecutor { .action .chain_id .expect("connection open try action should have a chain identifier"); + let previous_connection_id = step.action.previous_connection_id; let client_id = step .action .client_id .expect("connection open try action should have a client identifier"); - let client_height = step + let client_state = step .action - .client_height - .expect("connection open try action should have a client height"); + .client_state + .expect("connection open try action should have a client state"); let counterparty_client_id = step.action.counterparty_client_id.expect( "connection open try action should have a counterparty client identifier", ); - let connection_id = step.action.connection_id; let counterparty_connection_id = step.action.counterparty_connection_id.expect( "connection open try action should have a counterparty connection identifier", ); @@ -385,15 +389,17 @@ impl modelator::TestExecutor for IBCTestExecutor { // create ICS26 message and deliver it let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( MsgConnectionOpenTry { - previous_connection_id: connection_id.map(Self::connection_id), + previous_connection_id: previous_connection_id.map(Self::connection_id), client_id: Self::client_id(client_id), client_state: None, + // TODO: it should be like this: + // client_state: Some(Self::client_state(client_state)), counterparty: Self::counterparty( counterparty_client_id, Some(counterparty_connection_id), ), counterparty_versions: Self::versions(), - proofs: Self::proofs(client_height), + proofs: Self::proofs(client_state), delay_period: Self::delay_period(), signer: Self::signer(), }, @@ -414,7 +420,7 @@ impl modelator::TestExecutor for IBCTestExecutor { matches!( handler_error_kind, ICS03ErrorKind::InvalidConsensusHeight(error_consensus_height, _) - if error_consensus_height == Self::height(client_height) + if error_consensus_height == Self::height(client_state) ) } ActionOutcome::ICS03ConnectionNotFound => { @@ -422,11 +428,11 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an // error matching the expected outcome - connection_id.is_some() + previous_connection_id.is_some() && matches!( handler_error_kind, ICS03ErrorKind::ConnectionNotFound(error_connection_id) - if error_connection_id == Self::connection_id(connection_id.unwrap()) + if error_connection_id == Self::connection_id(previous_connection_id.unwrap()) ) } ActionOutcome::ICS03ConnectionMismatch => { @@ -434,11 +440,11 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result); // the implementaion matches the model if there's an // error matching the expected outcome - connection_id.is_some() + previous_connection_id.is_some() && matches!( handler_error_kind, ICS03ErrorKind::ConnectionMismatch(error_connection_id) - if error_connection_id == Self::connection_id(connection_id.unwrap()) + if error_connection_id == Self::connection_id(previous_connection_id.unwrap()) ) } action => panic!("unexpected action outcome {:?}", action), @@ -467,11 +473,12 @@ fn main() { for test in tests { let test = format!("{}/{}.json", TESTS_DIR, test); + println!("> running {}", test); let executor = IBCTestExecutor::new(); // we should be able to just return the `Result` once the following issue // is fixed: https://github.com/rust-lang/rust/issues/43301 if let Err(e) = modelator::test(&test, executor) { - panic!("{:?}", e); + panic!("{}", e); } } } diff --git a/modules/tests/modelator.rs b/modules/tests/modelator.rs index cbd15b18e3..8af34be9b3 100644 --- a/modules/tests/modelator.rs +++ b/modules/tests/modelator.rs @@ -10,7 +10,7 @@ pub enum ModelatorError { TestNotFound { path: String, error: String }, #[error("test '{path}' could not be deserialized: {error}")] InvalidTest { path: String, error: String }, - #[error("test '{path}' failed on step {step_index}/{step_count}:\nstep:\n{step:#?}\nexecutor:\n{executor:#?}")] + #[error("test '{path}' failed on step {step_index}/{step_count}:\nstep: {step:#?}\nexecutor: {executor:#?}")] FailedTest { path: String, step_index: usize, diff --git a/modules/tests/step.rs b/modules/tests/step.rs index b1dae82dad..c3601e4ded 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -20,19 +20,24 @@ pub struct Action { #[serde(alias = "chainId")] pub chain_id: Option, + #[serde(alias = "clientState")] + pub client_state: Option, + + #[serde(alias = "consensusState")] + pub consensus_state: Option, + #[serde(alias = "clientId")] pub client_id: Option, - #[serde(alias = "clientHeight")] - pub client_height: Option, + pub header: Option, + + #[serde(alias = "previousConnectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + pub previous_connection_id: Option, #[serde(alias = "counterpartyClientId")] pub counterparty_client_id: Option, - #[serde(alias = "connectionId")] - #[serde(default, deserialize_with = "deserialize_connection_id")] - pub connection_id: Option, - #[serde(alias = "counterpartyConnectionId")] #[serde(default, deserialize_with = "deserialize_connection_id")] pub counterparty_connection_id: Option, @@ -80,4 +85,4 @@ pub enum ActionOutcome { #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct Chain { pub height: u64, -} \ No newline at end of file +} diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 140fe49ebb..8c5640fcc3 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,8 +1,8 @@ CONSTANTS - ChainIds = {"chainA-0", "chainB-0"} + ChainIds = {"chainA", "chainB"} + MaxChainHeight = 7 MaxClientsPerChain = 1 - MaxClientHeight = 2 - MaxConnectionsPerChain = 2 + MaxConnectionsPerChain = 1 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 89ddfe6de2..60ed43662a 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -4,12 +4,12 @@ EXTENDS Integers, FiniteSets, ICS02, ICS03 \* ids of existing chains CONSTANT ChainIds +\* max height which chains can reach +CONSTANT MaxChainHeight +ASSUME MaxChainHeight >= 0 \* max number of client to be created per chain CONSTANT MaxClientsPerChain ASSUME MaxClientsPerChain >= 0 -\* max height which clients can reach -CONSTANT MaxClientHeight -ASSUME MaxClientHeight >= 0 \* max number of connections to be created per chain CONSTANT MaxConnectionsPerChain ASSUME MaxConnectionsPerChain >= 0 @@ -22,28 +22,10 @@ VARIABLE action VARIABLE actionOutcome vars == <> -(********************** TYPE ANNOTATIONS FOR APALACHE ************************) -\* operator for type annotations -a <: b == a - -ActionType == [ - type |-> STRING, - chainId |-> STRING, - clientHeight |-> Int, - clientId |-> Int, - connectionId |-> Int, - counterpartyClientId |-> Int, - counterpartyConnectionId |-> Int -] -AsAction(a) == a <: ActionType -(******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) - \* set of possible chain heights -ChainHeights == Int +Heights == 1..MaxChainHeight \* set of possible client identifiers ClientIds == 0..(MaxClientsPerChain - 1) -\* set of possible client heights -ClientHeights == 1..MaxClientHeight \* set of possible connection identifiers ConnectionIds == 0..(MaxConnectionsPerChain- 1) \* set of possible connection states @@ -56,7 +38,7 @@ ConnectionStates == { \* data kept per cliennt Client == [ - height: ClientHeights \union {HeightNone} + heights: SUBSET Heights ] \* mapping from client identifier to its height Clients == [ @@ -76,7 +58,7 @@ Connections == [ ] \* data kept per chain Chain == [ - height: ChainHeights, + height: Heights, clients: Clients, clientIdCounter: 0..MaxClientsPerChain, connections: Connections, @@ -94,13 +76,17 @@ NoneActions == [ CreateClientActions == [ type: {"ICS02CreateClient"}, chainId: ChainIds, - clientHeight: ClientHeights + \* client state contains simply a height + clientState: Heights, + \* consensus state contains simply a height + consensusState: Heights ] <: {ActionType} UpdateClientActions == [ type: {"ICS02UpdateClient"}, chainId: ChainIds, - clientHeight: ClientHeights, - clientId: ClientIds + clientId: ClientIds, + \* header contains simply a height + header: Heights ] <: {ActionType} ConnectionOpenInitActions == [ type: {"ICS03ConnectionOpenInit"}, @@ -111,10 +97,12 @@ ConnectionOpenInitActions == [ ConnectionOpenTryActions == [ type: {"ICS03ConnectionOpenTry"}, chainId: ChainIds, - clientHeight: ClientHeights, + \* `previousConnectionId` can be none + previousConnectionId: ConnectionIds \union {ConnectionIdNone}, clientId: ClientIds, + \* client state contains simply a height + clientState: Heights, counterpartyClientId: ClientIds, - connectionId: ConnectionIds \union {ConnectionIdNone}, counterpartyConnectionId: ConnectionIds ] <: {ActionType} Actions == @@ -150,11 +138,11 @@ ActionOutcomes == { UpdateChainHeight(height, outcome, okOutcome) == IF outcome = okOutcome THEN height + 1 ELSE height -CreateClient(chainId, clientHeight) == +CreateClient(chainId, height) == LET chain == chains[chainId] IN LET clients == chain.clients IN LET clientIdCounter == chain.clientIdCounter IN - LET result == ICS02_CreateClient(clients, clientIdCounter, clientHeight) IN + LET result == ICS02_CreateClient(clients, clientIdCounter, height) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS02CreateOK"), @@ -166,13 +154,14 @@ CreateClient(chainId, clientHeight) == /\ action' = AsAction([ type |-> "ICS02CreateClient", chainId |-> chainId, - clientHeight |-> clientHeight]) + clientState |-> height, + consensusState |-> height]) /\ actionOutcome' = result.outcome -UpdateClient(chainId, clientId, clientHeight) == +UpdateClient(chainId, clientId, height) == LET chain == chains[chainId] IN LET clients == chain.clients IN - LET result == ICS02_UpdateClient(clients, clientId, clientHeight) IN + LET result == ICS02_UpdateClient(clients, clientId, height) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03CreateOK"), @@ -184,7 +173,7 @@ UpdateClient(chainId, clientId, clientHeight) == type |-> "ICS02UpdateClient", chainId |-> chainId, clientId |-> clientId, - clientHeight |-> clientHeight]) + header |-> height]) /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == @@ -216,25 +205,25 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ConnectionOpenTry( chainId, + previousConnectionId, clientId, - clientHeight, - connectionId, + height, counterpartyClientId, counterpartyConnectionId ) == LET chain == chains[chainId] IN - LET height == chain.height IN + LET chainHeight == chain.height IN LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN LET result == ICS03_ConnectionOpenTry( - height, + chainHeight, clients, connections, connectionIdCounter, + previousConnectionId, clientId, - clientHeight, - connectionId, + height, counterpartyClientId, counterpartyConnectionId ) IN @@ -249,71 +238,63 @@ ConnectionOpenTry( /\ action' = AsAction([ type |-> "ICS03ConnectionOpenTry", chainId |-> chainId, + previousConnectionId |-> previousConnectionId, clientId |-> clientId, - clientHeight |-> clientHeight, - connectionId |-> connectionId, + clientState |-> height, counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> counterpartyConnectionId]) /\ actionOutcome' = result.outcome -CreateClientAction == - \* select a chain id - \E chainId \in ChainIds: +CreateClientAction(chainId) == \* select a height for the client to be created at - \E clientHeight \in ClientHeights: + \E height \in Heights: \* only create client if the model constant `MaxClientsPerChain` allows \* it - IF chains[chainId].clientIdCounter \in ClientIds THEN - CreateClient(chainId, clientHeight) + IF chains[chainId].clientIdCounter < MaxClientsPerChain THEN + CreateClient(chainId, height) ELSE UNCHANGED vars -UpdateClientAction == - \* select a chain id - \E chainId \in ChainIds: +UpdateClientAction(chainId) == \* select a client to be updated (which may not exist) \E clientId \in ClientIds: \* select a height for the client to be updated - \E clientHeight \in ClientHeights: - UpdateClient(chainId, clientId, clientHeight) + \E height \in Heights: + UpdateClient(chainId, clientId, height) -ConnectionOpenInitAction == - \* select a chain id - \E chainId \in ChainIds: +ConnectionOpenInitAction(chainId) == \* select a client id \E clientId \in ClientIds: \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* only create connection if the model constant `MaxConnectionsPerChain` \* allows it - IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + IF chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN ConnectionOpenInit(chainId, clientId, counterpartyClientId) ELSE UNCHANGED vars -ConnectionOpenTryAction == - \* select a chain id - \E chainId \in ChainIds: +ConnectionOpenTryAction(chainId) == + \* select a previous connection id (which can be none) + \E previousConnectionId \in ConnectionIds \union {ConnectionIdNone}: \* select a client id \E clientId \in ClientIds: \* select a claimed height for the client - \E clientHeight \in ClientHeights: - \* select a connection id (which can be none) - \E connectionId \in ConnectionIds \union {ConnectionIdNone}: + \E height \in Heights: \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* select a counterparty connection id \E counterpartyConnectionId \in ConnectionIds: - IF connectionId = ConnectionIdNone THEN + IF previousConnectionId = ConnectionIdNone THEN \* in this case we're trying to create a new connection; only create \* connection if the model constant `MaxConnectionsPerChain` allows \* it - IF chains[chainId].connectionIdCounter \in ConnectionIds THEN + IF chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN ConnectionOpenTry( chainId, + previousConnectionId, clientId, - clientHeight, - connectionId, + height, counterpartyClientId, counterpartyConnectionId ) @@ -322,9 +303,9 @@ ConnectionOpenTryAction == ELSE ConnectionOpenTry( chainId, + previousConnectionId, clientId, - clientHeight, - connectionId, + height, counterpartyClientId, counterpartyConnectionId ) @@ -332,7 +313,7 @@ ConnectionOpenTryAction == Init == \* create a client and a connection with none values LET clientNone == [ - height |-> HeightNone + heights |-> AsSetInt({}) ] IN LET connectionNone == [ state |-> "Uninit", @@ -343,7 +324,7 @@ Init == ] IN \* create an empty chain LET emptyChain == [ - height |-> 0, + height |-> 1, clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, connections |-> [connectionId \in ConnectionIds |-> connectionNone], @@ -354,11 +335,18 @@ Init == /\ actionOutcome = "None" Next == - \/ CreateClientAction - \/ UpdateClientAction - \/ ConnectionOpenInitAction - \/ ConnectionOpenTryAction - \/ UNCHANGED vars + \* select a chain id + \E chainId \in ChainIds: + \* perform action on chain if the model constant `MaxChainHeight` allows + \* it + IF chains[chainId].height < MaxChainHeight THEN + \/ CreateClientAction(chainId) + \/ UpdateClientAction(chainId) + \/ ConnectionOpenInitAction(chainId) + \* \/ ConnectionOpenTryAction(chainId) + \/ UNCHANGED vars + ELSE + \/ UNCHANGED vars (******************************** Invariants *********************************) diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index 0d5e8e2385..561531d1cc 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -2,10 +2,31 @@ EXTENDS Integers, FiniteSets +(********************** TYPE ANNOTATIONS FOR APALACHE ************************) +\* operator for type annotations +a <: b == a + +ActionType == [ + type |-> STRING, + chainId |-> STRING, + clientState |-> Int, + consensusState |-> Int, + clientId |-> Int, + header |-> Int, + previousConnectionId |-> Int, + counterpartyClientId |-> Int, + counterpartyConnectionId |-> Int +] +AsAction(a) == a <: ActionType +AsSetInt(S) == S <: {Int} +(******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) + +(******************************** Utils **************************************) +Max(S) == CHOOSE x \in S: \A y \in S: y <= x +(*****************************************************************************) + \* if a client identifier is not set then it is -1 ClientIdNone == -1 -\* if a client identifier is not set then it is -1 -HeightNone == -1 \* if a connection identifier is not set then it is -1 ConnectionIdNone == -1 diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index af4cc9337f..375b9745e4 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,8 +1,8 @@ CONSTANTS - ChainIds = {"chainA-0", "chainB-0"} + ChainIds = {"chainA", "chainB"} + MaxChainHeight = 7 MaxClientsPerChain = 1 - MaxClientHeight = 2 - MaxConnectionsPerChain = 2 + MaxConnectionsPerChain = 1 INIT Init NEXT Next diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 84fa0c4727..f4da6c3816 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -8,13 +8,13 @@ ICS02_GetClient(clients, clientId) == \* check if `clientId` exists ICS02_ClientExists(clients, clientId) == - ICS02_GetClient(clients, clientId).height /= HeightNone + ICS02_GetClient(clients, clientId).heights /= AsSetInt({}) \* update `clientId`'s data ICS02_SetClient(clients, clientId, client) == [clients EXCEPT ![clientId] = client] -ICS02_CreateClient(clients, clientIdCounter, clientHeight) == +ICS02_CreateClient(clients, clientIdCounter, height) == \* check if the client exists (it shouldn't) IF ICS02_ClientExists(clients, clientIdCounter) THEN \* if the client to be created already exists, @@ -27,7 +27,7 @@ ICS02_CreateClient(clients, clientIdCounter, clientHeight) == ELSE \* if it doesn't, create it LET client == [ - height |-> clientHeight + heights|-> {height} ] IN \* return result with updated state [ @@ -36,16 +36,17 @@ ICS02_CreateClient(clients, clientIdCounter, clientHeight) == outcome |-> "ICS02CreateOK" ] -ICS02_UpdateClient(clients, clientId, clientHeight) == +ICS02_UpdateClient(clients, clientId, height) == \* check if the client exists IF ICS02_ClientExists(clients, clientId) THEN \* if the client exists, check its height LET client == ICS02_GetClient(clients, clientId) IN - IF client.height < clientHeight THEN + LET latestHeight == Max(client.heights) IN + IF latestHeight < height THEN \* if the client's height is lower than the one being updated to \* then, update the client LET updatedClient == [client EXCEPT - !.height = clientHeight + !.heights = client.heights \union {height} ] IN \* return result with updated state [ @@ -65,7 +66,5 @@ ICS02_UpdateClient(clients, clientId, clientHeight) == clients |-> clients, outcome |-> "ICS02ClientNotFound" ] - \* TODO: distinguish between client state and consensus state to also be - \* able to return a `ConsensusStateNotFound` error outcome =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index e9b3096a7f..efa21a2718 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -67,14 +67,14 @@ ICS03_ConnectionOpenTry( clients, connections, connectionIdCounter, + previousConnectionId, clientId, - clientClaimedHeight, - connectionId, + height, counterpartyClientId, counterpartyConnectionId ) == \* check if client's claimed height is higher than the chain's height - IF clientClaimedHeight > chainHeight THEN + IF height > chainHeight THEN \* if client's height is too advanced, then set an error outcome [ connections |-> connections, @@ -84,15 +84,15 @@ ICS03_ConnectionOpenTry( \* TODO: add `chain_max_history_size` to the model to be able to also \* return a `ICS03StaleConsensusHeight` error outcome ELSE - \* check if a `connectionId` was set - IF connectionId /= ConnectionIdNone THEN + \* check if there's a `previousConnectionId` + IF previousConnectionId /= ConnectionIdNone THEN \* if so, check if the connection exists - IF ICS03_ConnectionExists(connections, connectionId) THEN + IF ICS03_ConnectionExists(connections, previousConnectionId) THEN \* if the connection exists, verify that is matches the \* the parameters provided LET connection == ICS03_GetConnection( connections, - connectionId + previousConnectionId ) IN IF /\ connection.state = "Init" /\ connection.clientId = clientId @@ -102,7 +102,7 @@ ICS03_ConnectionOpenTry( LET updatedConnection == [ state |-> "TryOpen", clientId |-> clientId, - connectionId |-> connectionId, + connectionId |-> previousConnectionId, counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> counterpartyConnectionId ] IN @@ -110,7 +110,7 @@ ICS03_ConnectionOpenTry( [ connections |-> ICS03_SetConnection( connections, - connectionId, + previousConnectionId, updatedConnection ), \* as the connection identifier has already been diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index 32a85c138a..dfe22dd307 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -5,43 +5,44 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "header": 1, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02HeaderVerificationFailure", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index 5275bfcda3..c41443ec45 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -5,109 +5,112 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 2, + "chainId": "chainB", + "header": 2, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 2 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 1 }, - "chainB-0": { + "chainB": { "height": 2 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 2, + "chainId": "chainA", + "header": 2, "clientId": 0, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chainA-0": { + "chainA": { "height": 2 }, - "chainB-0": { + "chainB": { "height": 2 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 3 }, - "chainB-0": { + "chainB": { "height": 2 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 2, + "chainId": "chainA", + "header": 2, "clientId": 1, "type": "ICS02UpdateClient" }, "actionOutcome": "ICS02UpdateOK", "chains": { - "chainA-0": { + "chainA": { "height": 4 }, - "chainB-0": { + "chainB": { "height": 2 } } diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index a652b34167..cd47bd504c 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -5,63 +5,64 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } }, { "action": { - "chainId": "chainB-0", + "chainId": "chainB", "clientId": 0, "counterpartyClientId": 1, "type": "ICS03ConnectionOpenInit" }, "actionOutcome": "ICS03ConnectionOpenInitOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 2 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 2, + "chainId": "chainB", + "previousConnectionId": 0, "clientId": 1, - "connectionId": 0, + "clientState": 2, "counterpartyClientId": 0, "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03ConnectionMismatch", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 2 } } diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index d88923f9b9..ab4b2d9af1 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -5,46 +5,47 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "previousConnectionId": 0, "clientId": 0, - "connectionId": 0, + "clientState": 1, "counterpartyClientId": 0, "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03ConnectionNotFound", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index 38142cd831..7b946e9ee9 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -5,43 +5,44 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", - "clientHeight": 1, + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 1 } } }, { "action": { - "chainId": "chainB-0", + "chainId": "chainB", "clientId": 0, "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, "actionOutcome": "ICS03ConnectionOpenInitOK", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 2 } } diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 0683ad02ca..31bff42a0e 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -5,46 +5,47 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 1 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "previousConnectionId": -1, "clientId": 0, - "connectionId": -1, + "clientState": 1, "counterpartyClientId": 0, "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03ConnectionOpenTryOK", "chains": { - "chainA-0": { + "chainA": { "height": 2 }, - "chainB-0": { + "chainB": { "height": 0 } } diff --git a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json index 47100a553d..4156b8bc91 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json @@ -5,30 +5,30 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "previousConnectionId": -1, "clientId": 0, - "connectionId": -1, + "clientState": 1, "counterpartyClientId": 0, "counterpartyConnectionId": 0, "type": "ICS03ConnectionOpenTry" }, "actionOutcome": "ICS03InvalidConsensusHeight", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json index 5aefb9f176..f88d40a375 100644 --- a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json @@ -5,59 +5,61 @@ }, "actionOutcome": "None", "chains": { - "chainA-0": { + "chainA": { "height": 0 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 1 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainA-0", - "clientHeight": 1, + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", "chains": { - "chainA-0": { + "chainA": { "height": 2 }, - "chainB-0": { + "chainB": { "height": 0 } } }, { "action": { - "chainId": "chainB-0", + "chainId": "chainB", "clientId": 0, "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, "actionOutcome": "ICS03MissingClient", "chains": { - "chainA-0": { + "chainA": { "height": 2 }, - "chainB-0": { + "chainB": { "height": 0 } } From ca8b839340ecc0615a351b713f400c9b8ee47da0 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 11 Feb 2021 18:12:41 +0100 Subject: [PATCH 055/104] Parse Action as an internally tagged enum --- modules/tests/model_based.rs | 101 ++++++++++------------------------- modules/tests/step.rs | 91 ++++++++++++++++++------------- 2 files changed, 80 insertions(+), 112 deletions(-) diff --git a/modules/tests/model_based.rs b/modules/tests/model_based.rs index a27e110e1c..9da1bbba2d 100644 --- a/modules/tests/model_based.rs +++ b/modules/tests/model_based.rs @@ -28,7 +28,7 @@ use ibc::Height; use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; -use step::{ActionOutcome, ActionType, Chain, Step}; +use step::{Action, ActionOutcome, Chain, Step}; use tendermint::account::Id as AccountId; #[derive(Debug)] @@ -204,11 +204,7 @@ impl IBCTestExecutor { impl modelator::TestExecutor for IBCTestExecutor { fn initial_step(&mut self, step: Step) -> bool { - assert_eq!( - step.action.action_type, - ActionType::None, - "unexpected action type" - ); + assert_eq!(step.action, Action::None, "unexpected action type"); assert_eq!( step.action_outcome, ActionOutcome::None, @@ -222,23 +218,13 @@ impl modelator::TestExecutor for IBCTestExecutor { } fn next_step(&mut self, step: Step) -> bool { - let outcome_matches = match step.action.action_type { - ActionType::None => panic!("unexpected action type"), - ActionType::ICS02CreateClient => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("create client action should have a chain identifier"); - let client_state = step - .action - .client_state - .expect("create client action should have a client state"); - let consensus_state = step - .action - .consensus_state - .expect("create client action should have a consensus state"); - + let outcome_matches = match step.action { + Action::None => panic!("unexpected action type"), + Action::ICS02CreateClient { + chain_id, + client_state, + consensus_state, + } => { // get chain's context let ctx = self.chain_context_mut(chain_id); @@ -259,21 +245,11 @@ impl modelator::TestExecutor for IBCTestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - ActionType::ICS02UpdateClient => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("update client action should have a chain identifier"); - let client_id = step - .action - .client_id - .expect("update client action should have a client identifier"); - let header = step - .action - .header - .expect("update client action should have a header"); - + Action::ICS02UpdateClient { + chain_id, + client_id, + header, + } => { // get chain's context let ctx = self.chain_context_mut(chain_id); @@ -312,20 +288,11 @@ impl modelator::TestExecutor for IBCTestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - ActionType::ICS03ConnectionOpenInit => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("connection open init action should have a chain identifier"); - let client_id = step - .action - .client_id - .expect("connection open init action should have a client identifier"); - let counterparty_client_id = step.action.counterparty_client_id.expect( - "connection open init action should have a counterparty client identifier", - ); - + Action::ICS03ConnectionOpenInit { + chain_id, + client_id, + counterparty_client_id, + } => { // get chain's context let ctx = self.chain_context_mut(chain_id); @@ -361,28 +328,14 @@ impl modelator::TestExecutor for IBCTestExecutor { action => panic!("unexpected action outcome {:?}", action), } } - ActionType::ICS03ConnectionOpenTry => { - // get action parameters - let chain_id = step - .action - .chain_id - .expect("connection open try action should have a chain identifier"); - let previous_connection_id = step.action.previous_connection_id; - let client_id = step - .action - .client_id - .expect("connection open try action should have a client identifier"); - let client_state = step - .action - .client_state - .expect("connection open try action should have a client state"); - let counterparty_client_id = step.action.counterparty_client_id.expect( - "connection open try action should have a counterparty client identifier", - ); - let counterparty_connection_id = step.action.counterparty_connection_id.expect( - "connection open try action should have a counterparty connection identifier", - ); - + Action::ICS03ConnectionOpenTry { + chain_id, + previous_connection_id, + client_id, + client_state, + counterparty_client_id, + counterparty_connection_id, + } => { // get chain's context let ctx = self.chain_context_mut(chain_id); diff --git a/modules/tests/step.rs b/modules/tests/step.rs index c3601e4ded..ce019d899e 100644 --- a/modules/tests/step.rs +++ b/modules/tests/step.rs @@ -12,35 +12,59 @@ pub struct Step { pub chains: HashMap, } -#[derive(Debug, Clone, Deserialize)] -pub struct Action { - #[serde(alias = "type")] - pub action_type: ActionType, - - #[serde(alias = "chainId")] - pub chain_id: Option, - - #[serde(alias = "clientState")] - pub client_state: Option, - - #[serde(alias = "consensusState")] - pub consensus_state: Option, - - #[serde(alias = "clientId")] - pub client_id: Option, - - pub header: Option, - - #[serde(alias = "previousConnectionId")] - #[serde(default, deserialize_with = "deserialize_connection_id")] - pub previous_connection_id: Option, - - #[serde(alias = "counterpartyClientId")] - pub counterparty_client_id: Option, - - #[serde(alias = "counterpartyConnectionId")] - #[serde(default, deserialize_with = "deserialize_connection_id")] - pub counterparty_connection_id: Option, +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(tag = "type")] +pub enum Action { + None, + ICS02CreateClient { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "clientState")] + client_state: u64, + + #[serde(alias = "consensusState")] + consensus_state: u64, + }, + ICS02UpdateClient { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "clientId")] + client_id: u64, + + header: u64, + }, + ICS03ConnectionOpenInit { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "clientId")] + client_id: u64, + + #[serde(alias = "counterpartyClientId")] + counterparty_client_id: u64, + }, + ICS03ConnectionOpenTry { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "previousConnectionId")] + #[serde(default, deserialize_with = "deserialize_connection_id")] + previous_connection_id: Option, + + #[serde(alias = "clientId")] + client_id: u64, + + #[serde(alias = "clientState")] + client_state: u64, + + #[serde(alias = "counterpartyClientId")] + counterparty_client_id: u64, + + #[serde(alias = "counterpartyConnectionId")] + counterparty_connection_id: u64, + }, } /// On the model, a non-existing `connection_id` is represented with -1. @@ -58,15 +82,6 @@ where Ok(connection_id) } -#[derive(Debug, Clone, PartialEq, Deserialize)] -pub enum ActionType { - None, - ICS02CreateClient, - ICS02UpdateClient, - ICS03ConnectionOpenInit, - ICS03ConnectionOpenTry, -} - #[derive(Debug, Clone, PartialEq, Deserialize)] pub enum ActionOutcome { None, From b37982a2826554d418287342892bd5cda181a5b0 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 12 Feb 2021 19:27:02 +0100 Subject: [PATCH 056/104] Separate action apply from action outcome checking --- modules/tests/executor/mod.rs | 225 ++++++++++++---------------------- 1 file changed, 80 insertions(+), 145 deletions(-) diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 2c08b28fa7..d87af2d488 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -46,7 +46,7 @@ impl IBCTestExecutor { /// Create a `MockContext` for a given `chain_id`. /// Panic if a context for `chain_id` already exists. - fn init_chain_context(&mut self, chain_id: String, initial_height: u64) { + pub fn init_chain_context(&mut self, chain_id: String, initial_height: u64) { let chain_id = Self::chain_id(chain_id); let max_history_size = 1; let ctx = MockContext::new( @@ -60,7 +60,7 @@ impl IBCTestExecutor { /// Returns a reference to the `MockContext` of a given `chain_id`. /// Panic if the context for `chain_id` is not found. - fn chain_context(&self, chain_id: String) -> &MockContext { + pub fn chain_context(&self, chain_id: String) -> &MockContext { self.contexts .get(&Self::chain_id(chain_id)) .expect("chain context should have been initialized") @@ -68,13 +68,13 @@ impl IBCTestExecutor { /// Returns a mutable reference to the `MockContext` of a given `chain_id`. /// Panic if the context for `chain_id` is not found. - fn chain_context_mut(&mut self, chain_id: String) -> &mut MockContext { + pub fn chain_context_mut(&mut self, chain_id: String) -> &mut MockContext { self.contexts .get_mut(&Self::chain_id(chain_id)) .expect("chain context should have been initialized") } - fn extract_handler_error_kind(ics18_result: Result<(), ICS18Error>) -> K + pub fn extract_handler_error_kind(ics18_result: Result<(), ICS18Error>) -> K where K: Clone + Debug + Display + Into + 'static, { @@ -101,83 +101,83 @@ impl IBCTestExecutor { .clone() } - fn chain_id(chain_id: String) -> ChainId { + pub fn chain_id(chain_id: String) -> ChainId { ChainId::new(chain_id, Self::revision()) } - fn revision() -> u64 { + pub fn revision() -> u64 { 0 } - fn version() -> Version { + pub fn version() -> Version { Version::default() } - fn versions() -> Vec { + pub fn versions() -> Vec { vec![Self::version()] } - fn client_id(client_id: u64) -> ClientId { + pub fn client_id(client_id: u64) -> ClientId { ClientId::new(ClientType::Mock, client_id) .expect("it should be possible to create the client identifier") } - fn connection_id(connection_id: u64) -> ConnectionId { + pub fn connection_id(connection_id: u64) -> ConnectionId { ConnectionId::new(connection_id) .expect("it should be possible to create the connection identifier") } - fn height(height: u64) -> Height { + pub fn height(height: u64) -> Height { Height::new(Self::revision(), height) } - fn mock_header(height: u64) -> MockHeader { + pub fn mock_header(height: u64) -> MockHeader { MockHeader(Self::height(height)) } - fn header(height: u64) -> AnyHeader { + pub fn header(height: u64) -> AnyHeader { AnyHeader::Mock(Self::mock_header(height)) } - fn client_state(height: u64) -> AnyClientState { + pub fn client_state(height: u64) -> AnyClientState { AnyClientState::Mock(MockClientState(Self::mock_header(height))) } - fn consensus_state(height: u64) -> AnyConsensusState { + pub fn consensus_state(height: u64) -> AnyConsensusState { AnyConsensusState::Mock(MockConsensusState(Self::mock_header(height))) } - fn signer() -> AccountId { + pub fn signer() -> AccountId { AccountId::new([0; 20]) } - fn counterparty(client_id: u64, connection_id: Option) -> Counterparty { + pub fn counterparty(client_id: u64, connection_id: Option) -> Counterparty { let client_id = Self::client_id(client_id); let connection_id = connection_id.map(|connection_id| Self::connection_id(connection_id)); let prefix = Self::commitment_prefix(); Counterparty::new(client_id, connection_id, prefix) } - fn delay_period() -> u64 { + pub fn delay_period() -> u64 { 0 } - fn commitment_prefix() -> CommitmentPrefix { + pub fn commitment_prefix() -> CommitmentPrefix { vec![0].into() } - fn commitment_proof_bytes() -> CommitmentProofBytes { + pub fn commitment_proof_bytes() -> CommitmentProofBytes { vec![0].into() } - fn consensus_proof(height: u64) -> ConsensusProof { + pub fn consensus_proof(height: u64) -> ConsensusProof { let consensus_proof = Self::commitment_proof_bytes(); let consensus_height = Self::height(height); ConsensusProof::new(consensus_proof, consensus_height) .expect("it should be possible to create the consensus proof") } - fn proofs(height: u64) -> Proofs { + pub fn proofs(height: u64) -> Proofs { let object_proof = Self::commitment_proof_bytes(); let client_proof = None; let consensus_proof = Some(Self::consensus_proof(height)); @@ -194,31 +194,15 @@ impl IBCTestExecutor { } /// Check that chain heights match the ones in the model. - fn check_chain_heights(&self, chains: HashMap) -> bool { + pub fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { let ctx = self.chain_context(chain_id); ctx.query_latest_height() == Self::height(chain.height) }) } -} -impl modelator::TestExecutor for IBCTestExecutor { - fn initial_step(&mut self, step: Step) -> bool { - assert_eq!(step.action, Action::None, "unexpected action type"); - assert_eq!( - step.action_outcome, - ActionOutcome::None, - "unexpected action outcome" - ); - // initiliaze all chains - for (chain_id, chain) in step.chains { - self.init_chain_context(chain_id, chain.height); - } - true - } - - fn next_step(&mut self, step: Step) -> bool { - let outcome_matches = match step.action { + pub fn apply(&mut self, action: Action) -> Result<(), ICS18Error> { + match action { Action::None => panic!("unexpected action type"), Action::ICS02CreateClient { chain_id, @@ -234,16 +218,7 @@ impl modelator::TestExecutor for IBCTestExecutor { consensus_state: Self::consensus_state(consensus_state), signer: Self::signer(), })); - let result = ctx.deliver(msg); - - // check the expected outcome: client create always succeeds - match step.action_outcome { - ActionOutcome::ICS02CreateOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - action => panic!("unexpected action outcome {:?}", action), - } + ctx.deliver(msg) } Action::ICS02UpdateClient { chain_id, @@ -259,34 +234,7 @@ impl modelator::TestExecutor for IBCTestExecutor { header: Self::header(header), signer: Self::signer(), })); - let result = ctx.deliver(msg); - - // check the expected outcome - match step.action_outcome { - ActionOutcome::ICS02UpdateOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - ActionOutcome::ICS02ClientNotFound => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - matches!( - handler_error_kind, - ICS02ErrorKind::ClientNotFound(error_client_id) - if error_client_id == Self::client_id(client_id) - ) - } - ActionOutcome::ICS02HeaderVerificationFailure => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - handler_error_kind == ICS02ErrorKind::HeaderVerificationFailure - } - action => panic!("unexpected action outcome {:?}", action), - } + ctx.deliver(msg) } Action::ICS03ConnectionOpenInit { chain_id, @@ -306,27 +254,7 @@ impl modelator::TestExecutor for IBCTestExecutor { signer: Self::signer(), }, )); - let result = ctx.deliver(msg); - - // check the expected outcome - match step.action_outcome { - ActionOutcome::ICS03ConnectionOpenInitOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - ActionOutcome::ICS03MissingClient => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - matches!( - handler_error_kind, - ICS03ErrorKind::MissingClient(error_client_id) - if error_client_id == Self::client_id(client_id) - ) - } - action => panic!("unexpected action outcome {:?}", action), - } + ctx.deliver(msg) } Action::ICS03ConnectionOpenTry { chain_id, @@ -357,52 +285,59 @@ impl modelator::TestExecutor for IBCTestExecutor { signer: Self::signer(), }, ))); - let result = ctx.deliver(msg); - - // check the expected outcome - match step.action_outcome { - ActionOutcome::ICS03ConnectionOpenTryOK => { - // the implementaion matches the model if no error occurs - result.is_ok() - } - ActionOutcome::ICS03InvalidConsensusHeight => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - matches!( - handler_error_kind, - ICS03ErrorKind::InvalidConsensusHeight(error_consensus_height, _) - if error_consensus_height == Self::height(client_state) - ) - } - ActionOutcome::ICS03ConnectionNotFound => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - previous_connection_id.is_some() - && matches!( - handler_error_kind, - ICS03ErrorKind::ConnectionNotFound(error_connection_id) - if error_connection_id == Self::connection_id(previous_connection_id.unwrap()) - ) - } - ActionOutcome::ICS03ConnectionMismatch => { - let handler_error_kind = - Self::extract_handler_error_kind::(result); - // the implementaion matches the model if there's an - // error matching the expected outcome - previous_connection_id.is_some() - && matches!( - handler_error_kind, - ICS03ErrorKind::ConnectionMismatch(error_connection_id) - if error_connection_id == Self::connection_id(previous_connection_id.unwrap()) - ) - } - action => panic!("unexpected action outcome {:?}", action), - } + ctx.deliver(msg) } + } + } +} + +impl modelator::TestExecutor for IBCTestExecutor { + fn initial_step(&mut self, step: Step) -> bool { + assert_eq!(step.action, Action::None, "unexpected action type"); + assert_eq!( + step.action_outcome, + ActionOutcome::None, + "unexpected action outcome" + ); + // initiliaze all chains + for (chain_id, chain) in step.chains { + self.init_chain_context(chain_id, chain.height); + } + true + } + + fn next_step(&mut self, step: Step) -> bool { + let result = self.apply(step.action); + let outcome_matches = match step.action_outcome { + ActionOutcome::None => panic!("unexpected action outcome"), + ActionOutcome::ICS02CreateOK => result.is_ok(), + ActionOutcome::ICS02UpdateOK => result.is_ok(), + ActionOutcome::ICS02ClientNotFound => matches!( + Self::extract_handler_error_kind::(result), + ICS02ErrorKind::ClientNotFound(_) + ), + ActionOutcome::ICS02HeaderVerificationFailure => matches!( + Self::extract_handler_error_kind::(result), + ICS02ErrorKind::HeaderVerificationFailure + ), + ActionOutcome::ICS03ConnectionOpenInitOK => result.is_ok(), + ActionOutcome::ICS03MissingClient => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::MissingClient(_) + ), + ActionOutcome::ICS03ConnectionOpenTryOK => result.is_ok(), + ActionOutcome::ICS03InvalidConsensusHeight => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::InvalidConsensusHeight(_, _) + ), + ActionOutcome::ICS03ConnectionNotFound => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::ConnectionNotFound(_) + ), + ActionOutcome::ICS03ConnectionMismatch => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::ConnectionMismatch(_) + ), }; // also check that chain heights match outcome_matches && self.check_chain_heights(step.chains) From acbe0d86a595067baf3fdc38e517da93cadca9a8 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 12 Feb 2021 19:42:12 +0100 Subject: [PATCH 057/104] improve conn open try enabling condition --- modules/tests/support/model_based/IBC.cfg | 2 +- modules/tests/support/model_based/IBC.tla | 24 ++++++------------- .../tests/support/model_based/IBCTests.cfg | 2 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 8c5640fcc3..6386b6c804 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chainA", "chainB"} - MaxChainHeight = 7 + MaxChainHeight = 5 MaxClientsPerChain = 1 MaxConnectionsPerChain = 1 diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 60ed43662a..f32f101274 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -285,22 +285,10 @@ ConnectionOpenTryAction(chainId) == \E counterpartyClientId \in ClientIds: \* select a counterparty connection id \E counterpartyConnectionId \in ConnectionIds: - IF previousConnectionId = ConnectionIdNone THEN - \* in this case we're trying to create a new connection; only create - \* connection if the model constant `MaxConnectionsPerChain` allows - \* it - IF chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN - ConnectionOpenTry( - chainId, - previousConnectionId, - clientId, - height, - counterpartyClientId, - counterpartyConnectionId - ) - ELSE - UNCHANGED vars - ELSE + \* only perform action if there was a previous connection or if the + \* model constant `MaxConnectionsPerChain` allows it + IF \/ previousConnectionId /= ConnectionIdNone + \/ chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN ConnectionOpenTry( chainId, previousConnectionId, @@ -309,6 +297,8 @@ ConnectionOpenTryAction(chainId) == counterpartyClientId, counterpartyConnectionId ) + ELSE + UNCHANGED vars Init == \* create a client and a connection with none values @@ -343,7 +333,7 @@ Next == \/ CreateClientAction(chainId) \/ UpdateClientAction(chainId) \/ ConnectionOpenInitAction(chainId) - \* \/ ConnectionOpenTryAction(chainId) + \/ ConnectionOpenTryAction(chainId) \/ UNCHANGED vars ELSE \/ UNCHANGED vars diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 375b9745e4..42750ecd40 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chainA", "chainB"} - MaxChainHeight = 7 + MaxChainHeight = 5 MaxClientsPerChain = 1 MaxConnectionsPerChain = 1 From 28ee9a9d4348f0bd84a7e6153ea240f2d39c319f Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 12 Feb 2021 19:51:30 +0100 Subject: [PATCH 058/104] Fix IBCTests.tla --- modules/tests/support/model_based/IBCTests.tla | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 0e7a02904a..b8e5271d9f 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -14,7 +14,6 @@ ICS02ClientNotFoundTest == ICS02HeaderVerificationFailureTest == /\ actionOutcome = "ICS02HeaderVerificationFailure" -<<<<<<< HEAD ICS03ConnectionOpenInitOKTest == /\ actionOutcome = "ICS03ConnectionOpenInitOK" @@ -33,20 +32,15 @@ ICS03ConnectionNotFoundTest == ICS03ConnectionMismatchTest == /\ actionOutcome = "ICS03ConnectionMismatch" -======= ->>>>>>> master ICS02CreateOKTestNeg == ~ICS02CreateOKTest ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ICS02ClientNotFoundTestNeg == ~ICS02ClientNotFoundTest ICS02HeaderVerificationFailureTestNeg == ~ICS02HeaderVerificationFailureTest -<<<<<<< HEAD ICS03ConnectionOpenInitOKTestNeg == ~ICS03ConnectionOpenInitOKTest ICS03MissingClientTestNeg == ~ICS03MissingClientTest ICS03ConnectionOpenTryOKTestNeg == ~ICS03ConnectionOpenTryOKTest ICS03InvalidConsensusHeightTestNeg == ~ICS03InvalidConsensusHeightTest ICS03ConnectionNotFoundTestNeg == ~ICS03ConnectionNotFoundTest ICS03ConnectionMismatchTestNeg == ~ICS03ConnectionMismatchTest -======= ->>>>>>> master =============================================================================== From 129ff9b0d43da9aa244ef27edb2b248fb5518cc9 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Wed, 17 Feb 2021 16:22:33 +0100 Subject: [PATCH 059/104] Add connectionProofs to each chain in TLA model --- modules/tests/support/model_based/IBC.tla | 189 ++++++++++-------- .../support/model_based/IBCDefinitions.tla | 2 + modules/tests/support/model_based/ICS02.tla | 7 +- modules/tests/support/model_based/ICS03.tla | 39 ++-- 4 files changed, 132 insertions(+), 105 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index f32f101274..5de98b112c 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -36,43 +36,11 @@ ConnectionStates == { "Open" } -\* data kept per cliennt -Client == [ - heights: SUBSET Heights -] -\* mapping from client identifier to its height -Clients == [ - ClientIds -> Client -] -\* data kept per connection -Connection == [ - state: ConnectionStates, - clientId: ClientIds \union {ClientIdNone}, - counterpartyClientId: ClientIds \union {ClientIdNone}, - connectionId: ConnectionIds \union {ConnectionIdNone}, - counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} -] -\* mapping from connection identifier to its data -Connections == [ - ConnectionIds -> Connection -] -\* data kept per chain -Chain == [ - height: Heights, - clients: Clients, - clientIdCounter: 0..MaxClientsPerChain, - connections: Connections, - connectionIdCounter: 0..MaxConnectionsPerChain -] -\* mapping from chain identifier to its data -Chains == [ - ChainIds -> Chain -] - \* set of possible actions NoneActions == [ type: {"None"} ] <: {ActionType} + CreateClientActions == [ type: {"ICS02CreateClient"}, chainId: ChainIds, @@ -88,6 +56,10 @@ UpdateClientActions == [ \* header contains simply a height header: Heights ] <: {ActionType} +ClientActions == + CreateClientActions \union + UpdateClientActions + ConnectionOpenInitActions == [ type: {"ICS03ConnectionOpenInit"}, chainId: ChainIds, @@ -97,21 +69,24 @@ ConnectionOpenInitActions == [ ConnectionOpenTryActions == [ type: {"ICS03ConnectionOpenTry"}, chainId: ChainIds, + clientId: ClientIds, \* `previousConnectionId` can be none previousConnectionId: ConnectionIds \union {ConnectionIdNone}, - clientId: ClientIds, \* client state contains simply a height clientState: Heights, + counterpartyChainId: ChainIds, counterpartyClientId: ClientIds, counterpartyConnectionId: ConnectionIds ] <: {ActionType} -Actions == - NoneActions \union - CreateClientActions \union - UpdateClientActions \union +ConnectionActions == ConnectionOpenInitActions \union ConnectionOpenTryActions +Actions == + NoneActions \union + ClientActions \union + ConnectionActions + \* set of possible action outcomes ActionOutcomes == { "None", @@ -132,6 +107,40 @@ ActionOutcomes == { "ICS03ConnectionMismatch" } +\* data kept per client +Client == [ + heights: SUBSET Heights +] +\* mapping from client identifier to its height +Clients == [ + ClientIds -> Client +] +\* data kept per connection +Connection == [ + state: ConnectionStates, + clientId: ClientIds \union {ClientIdNone}, + counterpartyClientId: ClientIds \union {ClientIdNone}, + connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} +] +\* mapping from connection identifier to its data +Connections == [ + ConnectionIds -> Connection +] +\* data kept per chain +Chain == [ + height: Heights, + clients: Clients, + clientIdCounter: 0..MaxClientsPerChain, + connections: Connections, + connectionIdCounter: 0..MaxConnectionsPerChain, + connectionProofs: SUBSET ConnectionActions +] +\* mapping from chain identifier to its data +Chains == [ + ChainIds -> Chain +] + (***************************** Specification *********************************) \* update chain height if outcome was ok @@ -140,9 +149,13 @@ UpdateChainHeight(height, outcome, okOutcome) == CreateClient(chainId, height) == LET chain == chains[chainId] IN - LET clients == chain.clients IN - LET clientIdCounter == chain.clientIdCounter IN - LET result == ICS02_CreateClient(clients, clientIdCounter, height) IN + LET result == ICS02_CreateClient(chain, height) IN + LET newAction == AsAction([ + type |-> "ICS02CreateClient", + chainId |-> chainId, + clientState |-> height, + consensusState |-> height + ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS02CreateOK"), @@ -151,17 +164,18 @@ CreateClient(chainId, height) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS02CreateClient", - chainId |-> chainId, - clientState |-> height, - consensusState |-> height]) + /\ action' = newAction /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, height) == LET chain == chains[chainId] IN - LET clients == chain.clients IN - LET result == ICS02_UpdateClient(clients, clientId, height) IN + LET result == ICS02_UpdateClient(chain, clientId, height) IN + LET newAction == AsAction([ + type |-> "ICS02UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + header |-> height + ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03CreateOK"), @@ -169,25 +183,22 @@ UpdateClient(chainId, clientId, height) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS02UpdateClient", - chainId |-> chainId, - clientId |-> clientId, - header |-> height]) + /\ action' = newAction /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == LET chain == chains[chainId] IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN LET result == ICS03_ConnectionOpenInit( - clients, - connections, - connectionIdCounter, + chain, clientId, counterpartyClientId ) IN + LET newAction == AsAction([ + type |-> "ICS03ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId + ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), @@ -196,37 +207,41 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS03ConnectionOpenInit", - chainId |-> chainId, - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId]) + /\ action' = newAction /\ actionOutcome' = result.outcome ConnectionOpenTry( chainId, - previousConnectionId, clientId, + previousConnectionId, height, + counterpartyChainId, counterpartyClientId, counterpartyConnectionId ) == LET chain == chains[chainId] IN - LET chainHeight == chain.height IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN + \* pass all the `chains` so that the model can check that the open try is + \* valid (i.e. there has been an open init on the counterparty chain); + \* the implementation uses proofs for this LET result == ICS03_ConnectionOpenTry( - chainHeight, - clients, - connections, - connectionIdCounter, - previousConnectionId, + chain, clientId, + previousConnectionId, height, + counterpartyChainId, counterpartyClientId, counterpartyConnectionId ) IN + LET newAction == AsAction([ + type |-> "ICS03ConnectionOpenTry", + chainId |-> chainId, + clientId |-> clientId, + previousConnectionId |-> previousConnectionId, + clientState |-> height, + counterpartyChainId |-> counterpartyChainId, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), @@ -235,14 +250,7 @@ ConnectionOpenTry( ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = AsAction([ - type |-> "ICS03ConnectionOpenTry", - chainId |-> chainId, - previousConnectionId |-> previousConnectionId, - clientId |-> clientId, - clientState |-> height, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId]) + /\ action' = newAction /\ actionOutcome' = result.outcome CreateClientAction(chainId) == @@ -275,25 +283,29 @@ ConnectionOpenInitAction(chainId) == UNCHANGED vars ConnectionOpenTryAction(chainId) == - \* select a previous connection id (which can be none) - \E previousConnectionId \in ConnectionIds \union {ConnectionIdNone}: \* select a client id \E clientId \in ClientIds: + \* select a previous connection id (which can be none) + \E previousConnectionId \in ConnectionIds \union {ConnectionIdNone}: \* select a claimed height for the client \E height \in Heights: + \* select a counterparty chain id + \E counterpartyChainId \in ChainIds: \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* select a counterparty connection id \E counterpartyConnectionId \in ConnectionIds: \* only perform action if there was a previous connection or if the - \* model constant `MaxConnectionsPerChain` allows it + \* model constant `MaxConnectionsPerChain` allows that a new connection + \* is created IF \/ previousConnectionId /= ConnectionIdNone - \/ chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN + \/ chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN ConnectionOpenTry( chainId, - previousConnectionId, clientId, + previousConnectionId, height, + counterpartyChainId, counterpartyClientId, counterpartyConnectionId ) @@ -318,7 +330,8 @@ Init == clients |-> [clientId \in ClientIds |-> clientNone], clientIdCounter |-> 0, connections |-> [connectionId \in ConnectionIds |-> connectionNone], - connectionIdCounter |-> 0 + connectionIdCounter |-> 0, + connectionProofs |-> AsSetAction({}) ] IN /\ chains = [chainId \in ChainIds |-> emptyChain] /\ action = AsAction([type |-> "None"]) diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index 561531d1cc..5a39072a79 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -14,10 +14,12 @@ ActionType == [ clientId |-> Int, header |-> Int, previousConnectionId |-> Int, + counterpartyChainId |-> STRING, counterpartyClientId |-> Int, counterpartyConnectionId |-> Int ] AsAction(a) == a <: ActionType +AsSetAction(S) == S <: {ActionType} AsSetInt(S) == S <: {Int} (******************* END OF TYPE ANNOTATIONS FOR APALACHE ********************) diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index f4da6c3816..3bbad68f0a 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -14,7 +14,9 @@ ICS02_ClientExists(clients, clientId) == ICS02_SetClient(clients, clientId, client) == [clients EXCEPT ![clientId] = client] -ICS02_CreateClient(clients, clientIdCounter, height) == +ICS02_CreateClient(chain, height) == + LET clients == chain.clients IN + LET clientIdCounter == chain.clientIdCounter IN \* check if the client exists (it shouldn't) IF ICS02_ClientExists(clients, clientIdCounter) THEN \* if the client to be created already exists, @@ -36,7 +38,8 @@ ICS02_CreateClient(clients, clientIdCounter, height) == outcome |-> "ICS02CreateOK" ] -ICS02_UpdateClient(clients, clientId, height) == +ICS02_UpdateClient(chain, clientId, height) == + LET clients == chain.clients IN \* check if the client exists IF ICS02_ClientExists(clients, clientId) THEN \* if the client exists, check its height diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index efa21a2718..989b7d4f1d 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -14,13 +14,10 @@ ICS03_ConnectionExists(connections, connectionId) == ICS03_SetConnection(connections, connectionId, connection) == [connections EXCEPT ![connectionId] = connection] -ICS03_ConnectionOpenInit( - clients, - connections, - connectionIdCounter, - clientId, - counterpartyClientId -) == +ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN \* check if the client exists IF ICS02_ClientExists(clients, clientId) THEN \* if the client exists, @@ -63,19 +60,24 @@ ICS03_ConnectionOpenInit( \* TODO: errors generated when verifying proofs are never an outcome of this \* model ICS03_ConnectionOpenTry( - chainHeight, - clients, - connections, - connectionIdCounter, - previousConnectionId, + chain, clientId, + previousConnectionId, height, + counterpartyChainId, counterpartyClientId, counterpartyConnectionId ) == + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionIdCounter == chain.connectionIdCounter IN + LET connectionProofs == chain.connectionProofs IN \* check if client's claimed height is higher than the chain's height - IF height > chainHeight THEN + IF height > chain.height THEN \* if client's height is too advanced, then set an error outcome + \* TODO: in the ICS03, this error also occurs if + \* "height == chain.height", which is not the case in the + \* Rust implementation [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, @@ -84,7 +86,11 @@ ICS03_ConnectionOpenTry( \* TODO: add `chain_max_history_size` to the model to be able to also \* return a `ICS03StaleConsensusHeight` error outcome ELSE - \* check if there's a `previousConnectionId` + \* check if there's a `previousConnectionId`. this situation can happen + \* where there are two concurrent open init's establishing a connection + \* between the same two chains, say chainA and chainB; then, when chainB + \* sees the open init from chainA, instead of creating a new connection + \* identifier, it can reuse the identifier created by its own open init. IF previousConnectionId /= ConnectionIdNone THEN \* if so, check if the connection exists IF ICS03_ConnectionExists(connections, previousConnectionId) THEN @@ -97,8 +103,10 @@ ICS03_ConnectionOpenTry( IF /\ connection.state = "Init" /\ connection.clientId = clientId /\ connection.counterpartyClientId = counterpartyClientId + /\ connection.counterpartyConnectionId = counterpartyConnectionId THEN - \* verification passed; update connection + \* verification passed; update the connection state to + \* "TryOpen" LET updatedConnection == [ state |-> "TryOpen", clientId |-> clientId, @@ -133,6 +141,7 @@ ICS03_ConnectionOpenTry( outcome |-> "ICS03ConnectionNotFound" ] ELSE + \* TODO: check if there was an open init at the remote chain \* verification passed; create connection LET connection == [ state |-> "TryOpen", From 1d6d5e98a3c3505f814e7c4ba92246317ee015d4 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 18 Feb 2021 10:48:35 +0100 Subject: [PATCH 060/104] Generate actions in the handlers --- modules/tests/support/model_based/IBC.tla | 45 ++++----------------- modules/tests/support/model_based/ICS02.tla | 21 +++++++++- modules/tests/support/model_based/ICS03.tla | 27 ++++++++++++- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 5de98b112c..13b02b2104 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -149,13 +149,7 @@ UpdateChainHeight(height, outcome, okOutcome) == CreateClient(chainId, height) == LET chain == chains[chainId] IN - LET result == ICS02_CreateClient(chain, height) IN - LET newAction == AsAction([ - type |-> "ICS02CreateClient", - chainId |-> chainId, - clientState |-> height, - consensusState |-> height - ]) IN + LET result == ICS02_CreateClient(chain, chainId, height) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS02CreateOK"), @@ -164,18 +158,12 @@ CreateClient(chainId, height) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = newAction + /\ action' = result.action /\ actionOutcome' = result.outcome UpdateClient(chainId, clientId, height) == LET chain == chains[chainId] IN - LET result == ICS02_UpdateClient(chain, clientId, height) IN - LET newAction == AsAction([ - type |-> "ICS02UpdateClient", - chainId |-> chainId, - clientId |-> clientId, - header |-> height - ]) IN + LET result == ICS02_UpdateClient(chain, chainId, clientId, height) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03CreateOK"), @@ -183,22 +171,17 @@ UpdateClient(chainId, clientId, height) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = newAction + /\ action' = result.action /\ actionOutcome' = result.outcome ConnectionOpenInit(chainId, clientId, counterpartyClientId) == LET chain == chains[chainId] IN LET result == ICS03_ConnectionOpenInit( chain, + chainId, clientId, counterpartyClientId ) IN - LET newAction == AsAction([ - type |-> "ICS03ConnectionOpenInit", - chainId |-> chainId, - clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId - ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), @@ -207,7 +190,7 @@ ConnectionOpenInit(chainId, clientId, counterpartyClientId) == ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = newAction + /\ action' = result.action /\ actionOutcome' = result.outcome ConnectionOpenTry( @@ -220,11 +203,9 @@ ConnectionOpenTry( counterpartyConnectionId ) == LET chain == chains[chainId] IN - \* pass all the `chains` so that the model can check that the open try is - \* valid (i.e. there has been an open init on the counterparty chain); - \* the implementation uses proofs for this LET result == ICS03_ConnectionOpenTry( chain, + chainId, clientId, previousConnectionId, height, @@ -232,16 +213,6 @@ ConnectionOpenTry( counterpartyClientId, counterpartyConnectionId ) IN - LET newAction == AsAction([ - type |-> "ICS03ConnectionOpenTry", - chainId |-> chainId, - clientId |-> clientId, - previousConnectionId |-> previousConnectionId, - clientState |-> height, - counterpartyChainId |-> counterpartyChainId, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId - ]) IN \* update the chain LET updatedChain == [chain EXCEPT !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), @@ -250,7 +221,7 @@ ConnectionOpenTry( ] IN \* update `chains`, set the `action` and its `actionOutcome` /\ chains' = [chains EXCEPT ![chainId] = updatedChain] - /\ action' = newAction + /\ action' = result.action /\ actionOutcome' = result.outcome CreateClientAction(chainId) == diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 3bbad68f0a..80cc587b60 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -14,7 +14,13 @@ ICS02_ClientExists(clients, clientId) == ICS02_SetClient(clients, clientId, client) == [clients EXCEPT ![clientId] = client] -ICS02_CreateClient(chain, height) == +ICS02_CreateClient(chain, chainId, height) == + LET action == AsAction([ + type |-> "ICS02CreateClient", + chainId |-> chainId, + clientState |-> height, + consensusState |-> height + ]) IN LET clients == chain.clients IN LET clientIdCounter == chain.clientIdCounter IN \* check if the client exists (it shouldn't) @@ -24,6 +30,7 @@ ICS02_CreateClient(chain, height) == [ clients |-> clients, clientIdCounter |-> clientIdCounter, + action |-> action, outcome |-> "ModelError" ] ELSE @@ -35,10 +42,17 @@ ICS02_CreateClient(chain, height) == [ clients |-> ICS02_SetClient(clients, clientIdCounter, client), clientIdCounter |-> clientIdCounter + 1, + action |-> action, outcome |-> "ICS02CreateOK" ] -ICS02_UpdateClient(chain, clientId, height) == +ICS02_UpdateClient(chain, chainId, clientId, height) == + LET action == AsAction([ + type |-> "ICS02UpdateClient", + chainId |-> chainId, + clientId |-> clientId, + header |-> height + ]) IN LET clients == chain.clients IN \* check if the client exists IF ICS02_ClientExists(clients, clientId) THEN @@ -54,6 +68,7 @@ ICS02_UpdateClient(chain, clientId, height) == \* return result with updated state [ clients |-> ICS02_SetClient(clients, clientId, updatedClient), + action |-> action, outcome |-> "ICS02UpdateOK" ] ELSE @@ -61,12 +76,14 @@ ICS02_UpdateClient(chain, clientId, height) == \* updated to, then set an error outcome [ clients |-> clients, + action |-> action, outcome |-> "ICS02HeaderVerificationFailure" ] ELSE \* if the client does not exist, then set an error outcome [ clients |-> clients, + action |-> action, outcome |-> "ICS02ClientNotFound" ] diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 989b7d4f1d..0fa7c24e65 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -14,7 +14,13 @@ ICS03_ConnectionExists(connections, connectionId) == ICS03_SetConnection(connections, connectionId, connection) == [connections EXCEPT ![connectionId] = connection] -ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == +ICS03_ConnectionOpenInit(chain, chainId, clientId, counterpartyClientId) == + LET action == AsAction([ + type |-> "ICS03ConnectionOpenInit", + chainId |-> chainId, + clientId |-> clientId, + counterpartyClientId |-> counterpartyClientId + ]) IN LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN @@ -28,6 +34,7 @@ ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ModelError" ] ELSE @@ -47,6 +54,7 @@ ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == connection ), connectionIdCounter |-> connectionIdCounter + 1, + action |-> action, outcome |-> "ICS03ConnectionOpenInitOK" ] ELSE @@ -54,6 +62,7 @@ ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ICS03MissingClient" ] @@ -61,6 +70,7 @@ ICS03_ConnectionOpenInit(chain, clientId, counterpartyClientId) == \* model ICS03_ConnectionOpenTry( chain, + chainId, clientId, previousConnectionId, height, @@ -68,6 +78,16 @@ ICS03_ConnectionOpenTry( counterpartyClientId, counterpartyConnectionId ) == + LET action == AsAction([ + type |-> "ICS03ConnectionOpenTry", + chainId |-> chainId, + clientId |-> clientId, + previousConnectionId |-> previousConnectionId, + clientState |-> height, + counterpartyChainId |-> counterpartyChainId, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ]) IN LET clients == chain.clients IN LET connections == chain.connections IN LET connectionIdCounter == chain.connectionIdCounter IN @@ -81,6 +101,7 @@ ICS03_ConnectionOpenTry( [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ICS03InvalidConsensusHeight" ] \* TODO: add `chain_max_history_size` to the model to be able to also @@ -125,12 +146,14 @@ ICS03_ConnectionOpenTry( \* created, here we do not update the \* `connectionIdCounter` connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ICS03ConnectionOpenTryOK" ] ELSE [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ICS03ConnectionMismatch" ] ELSE @@ -138,6 +161,7 @@ ICS03_ConnectionOpenTry( [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, + action |-> action, outcome |-> "ICS03ConnectionNotFound" ] ELSE @@ -161,6 +185,7 @@ ICS03_ConnectionOpenTry( \* since a new connection identifier has been created, here we \* update the `connectionIdCounter` connectionIdCounter |-> connectionIdCounter + 1, + action |-> action, outcome |-> "ICS03ConnectionOpenTryOK" ] From 00afd55b61bd34a0546fc3be3573a3fe0c0a4091 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 18 Feb 2021 11:07:38 +0100 Subject: [PATCH 061/104] Save proofs in counterparty chain upon a successful action --- modules/tests/support/model_based/IBC.tla | 66 ++++++++++++++++----- modules/tests/support/model_based/ICS03.tla | 9 ++- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 13b02b2104..1f8caefd94 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -44,16 +44,16 @@ NoneActions == [ CreateClientActions == [ type: {"ICS02CreateClient"}, chainId: ChainIds, - \* client state contains simply a height + \* `clientState` contains simply a height clientState: Heights, - \* consensus state contains simply a height + \* `consensusState` contains simply a height consensusState: Heights ] <: {ActionType} UpdateClientActions == [ type: {"ICS02UpdateClient"}, chainId: ChainIds, clientId: ClientIds, - \* header contains simply a height + \* `header` contains simply a height header: Heights ] <: {ActionType} ClientActions == @@ -64,6 +64,7 @@ ConnectionOpenInitActions == [ type: {"ICS03ConnectionOpenInit"}, chainId: ChainIds, clientId: ClientIds, + counterpartyChainId: ChainIds, counterpartyClientId: ClientIds ] <: {ActionType} ConnectionOpenTryActions == [ @@ -72,7 +73,7 @@ ConnectionOpenTryActions == [ clientId: ClientIds, \* `previousConnectionId` can be none previousConnectionId: ConnectionIds \union {ConnectionIdNone}, - \* client state contains simply a height + \* `clientState` contains simply a height clientState: Heights, counterpartyChainId: ChainIds, counterpartyClientId: ClientIds, @@ -144,15 +145,25 @@ Chains == [ (***************************** Specification *********************************) \* update chain height if outcome was ok -UpdateChainHeight(height, outcome, okOutcome) == - IF outcome = okOutcome THEN height + 1 ELSE height +UpdateChainHeight(height, result, okOutcome) == + IF result.outcome = okOutcome THEN + height + 1 + ELSE + height + +\* update connection proofs if outcome was ok +UpdateConnectionProofs(connectionProofs, result, okOutcome) == + IF result.outcome = okOutcome THEN + connectionProofs \union {result.action} + ELSE + connectionProofs CreateClient(chainId, height) == LET chain == chains[chainId] IN LET result == ICS02_CreateClient(chain, chainId, height) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS02CreateOK"), + !.height = UpdateChainHeight(@, result, "ICS02CreateOK"), !.clients = result.clients, !.clientIdCounter = result.clientIdCounter ] IN @@ -166,7 +177,7 @@ UpdateClient(chainId, clientId, height) == LET result == ICS02_UpdateClient(chain, chainId, clientId, height) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS03CreateOK"), + !.height = UpdateChainHeight(@, result, "ICS03CreateOK"), !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` @@ -174,22 +185,35 @@ UpdateClient(chainId, clientId, height) == /\ action' = result.action /\ actionOutcome' = result.outcome -ConnectionOpenInit(chainId, clientId, counterpartyClientId) == +ConnectionOpenInit( + chainId, + clientId, + counterpartyChainId, + counterpartyClientId +) == LET chain == chains[chainId] IN LET result == ICS03_ConnectionOpenInit( chain, chainId, clientId, + counterpartyChainId, counterpartyClientId ) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenInitOK"), + !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenInitOK"), !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN + \* update the counterparty chain with a proof + LET counterpartyChain == chains[counterpartyChainId] IN + LET updatedCounterpartyChain == [counterpartyChain EXCEPT + !.connectionProofs = UpdateConnectionProofs(@, result, "ICS03ConnectionOpenInitOK") + ] IN \* update `chains`, set the `action` and its `actionOutcome` - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ chains' = [chains EXCEPT + ![chainId] = updatedChain, + ![counterpartyChainId] = updatedCounterpartyChain] /\ action' = result.action /\ actionOutcome' = result.outcome @@ -215,12 +239,19 @@ ConnectionOpenTry( ) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result.outcome, "ICS03ConnectionOpenTryOK"), + !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenTryOK"), !.connections = result.connections, !.connectionIdCounter = result.connectionIdCounter ] IN + \* update the counterparty chain with a proof + LET counterpartyChain == chains[counterpartyChainId] IN + LET updatedCounterpartyChain == [counterpartyChain EXCEPT + !.connectionProofs = UpdateConnectionProofs(@, result, "ICS03ConnectionOpenTryOK") + ] IN \* update `chains`, set the `action` and its `actionOutcome` - /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ chains' = [chains EXCEPT + ![chainId] = updatedChain, + ![counterpartyChainId] = updatedCounterpartyChain] /\ action' = result.action /\ actionOutcome' = result.outcome @@ -244,12 +275,19 @@ UpdateClientAction(chainId) == ConnectionOpenInitAction(chainId) == \* select a client id \E clientId \in ClientIds: + \* select a counterparty chain id + \E counterpartyChainId \in ChainIds: \* select a counterparty client id \E counterpartyClientId \in ClientIds: \* only create connection if the model constant `MaxConnectionsPerChain` \* allows it IF chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN - ConnectionOpenInit(chainId, clientId, counterpartyClientId) + ConnectionOpenInit( + chainId, + clientId, + counterpartyChainId, + counterpartyClientId + ) ELSE UNCHANGED vars diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 0fa7c24e65..f56398b99a 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -14,11 +14,18 @@ ICS03_ConnectionExists(connections, connectionId) == ICS03_SetConnection(connections, connectionId, connection) == [connections EXCEPT ![connectionId] = connection] -ICS03_ConnectionOpenInit(chain, chainId, clientId, counterpartyClientId) == +ICS03_ConnectionOpenInit( + chain, + chainId, + clientId, + counterpartyChainId, + counterpartyClientId +) == LET action == AsAction([ type |-> "ICS03ConnectionOpenInit", chainId |-> chainId, clientId |-> clientId, + counterpartyChainId |-> counterpartyChainId, counterpartyClientId |-> counterpartyClientId ]) IN LET clients == chain.clients IN From 8a2581db149e32de227c55d5f5b44f0e036e57fa Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 18 Feb 2021 11:29:01 +0100 Subject: [PATCH 062/104] Reduce state space --- modules/tests/executor/step.rs | 6 ++++++ modules/tests/mbt.rs | 16 +++++++++------- modules/tests/support/model_based/IBC.cfg | 2 +- modules/tests/support/model_based/IBCTests.cfg | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index ce019d899e..c4b5140119 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -42,6 +42,9 @@ pub enum Action { #[serde(alias = "clientId")] client_id: u64, + #[serde(alias = "counterpartyChainId")] + counterparty_chain_id: u64, + #[serde(alias = "counterpartyClientId")] counterparty_client_id: u64, }, @@ -59,6 +62,9 @@ pub enum Action { #[serde(alias = "clientState")] client_state: u64, + #[serde(alias = "counterpartyChainId")] + counterparty_chain_id: u64, + #[serde(alias = "counterpartyClientId")] counterparty_client_id: u64, diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 8cba945ced..66f9a1e26e 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,14 +5,16 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn main() { let tests = vec![ - "ICS02UpdateOKTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", + // "ICS02UpdateOKTest", + // "ICS02HeaderVerificationFailureTest", + // "ICS03ConnectionOpenInitOKTest", + // "ICS03MissingClientTest", + // the following test should fail but doesn't because proofs are not yet + // verified "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", + // "ICS03InvalidConsensusHeightTest", + // "ICS03ConnectionNotFoundTest", + // "ICS03ConnectionMismatchTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.cfg b/modules/tests/support/model_based/IBC.cfg index 6386b6c804..d2997417ae 100644 --- a/modules/tests/support/model_based/IBC.cfg +++ b/modules/tests/support/model_based/IBC.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chainA", "chainB"} - MaxChainHeight = 5 + MaxChainHeight = 4 MaxClientsPerChain = 1 MaxConnectionsPerChain = 1 diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg index 42750ecd40..6a9654bac4 100644 --- a/modules/tests/support/model_based/IBCTests.cfg +++ b/modules/tests/support/model_based/IBCTests.cfg @@ -1,6 +1,6 @@ CONSTANTS ChainIds = {"chainA", "chainB"} - MaxChainHeight = 5 + MaxChainHeight = 4 MaxClientsPerChain = 1 MaxConnectionsPerChain = 1 From cf54ff4441fe2a3f380ace4ee383d05a0c17470d Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 18 Feb 2021 21:06:03 +0100 Subject: [PATCH 063/104] Update tests --- modules/tests/executor/mod.rs | 2 + .../tests/support/model_based/IBCTests.cfg | 8 - .../tests/support/model_based/gen_tests.py | 37 +++ .../tests/ICS02ClientNotFoundTest.json | 101 +++++++ .../model_based/tests/ICS02CreateOKTest.json | 103 +++++++ .../ICS02HeaderVerificationFailureTest.json | 198 +++++++++--- .../model_based/tests/ICS02UpdateOKTest.json | 253 +++++++++------- .../tests/ICS03ConnectionMismatchTest.json | 282 ++++++++++++++---- .../tests/ICS03ConnectionNotFoundTest.json | 201 ++++++++++--- .../tests/ICS03ConnectionOpenInitOKTest.json | 199 +++++++++--- .../tests/ICS03ConnectionOpenTryOKTest.json | 147 ++++++--- .../ICS03InvalidConsensusHeightTest.json | 135 +++++++-- .../tests/ICS03MissingClientTest.json | 155 ++++++---- 13 files changed, 1373 insertions(+), 448 deletions(-) delete mode 100644 modules/tests/support/model_based/IBCTests.cfg create mode 100755 modules/tests/support/model_based/gen_tests.py create mode 100644 modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json create mode 100644 modules/tests/support/model_based/tests/ICS02CreateOKTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index d87af2d488..7b270b2d94 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -239,6 +239,7 @@ impl IBCTestExecutor { Action::ICS03ConnectionOpenInit { chain_id, client_id, + counterparty_chain_id: _, counterparty_client_id, } => { // get chain's context @@ -261,6 +262,7 @@ impl IBCTestExecutor { previous_connection_id, client_id, client_state, + counterparty_chain_id: _, counterparty_client_id, counterparty_connection_id, } => { diff --git a/modules/tests/support/model_based/IBCTests.cfg b/modules/tests/support/model_based/IBCTests.cfg deleted file mode 100644 index 6a9654bac4..0000000000 --- a/modules/tests/support/model_based/IBCTests.cfg +++ /dev/null @@ -1,8 +0,0 @@ -CONSTANTS - ChainIds = {"chainA", "chainB"} - MaxChainHeight = 4 - MaxClientsPerChain = 1 - MaxConnectionsPerChain = 1 - -INIT Init -NEXT Next diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py new file mode 100755 index 0000000000..cb68a281ab --- /dev/null +++ b/modules/tests/support/model_based/gen_tests.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import os + +CFG = """ +CONSTANTS + ChainIds = {"chainA", "chainB"} + MaxChainHeight = 4 + MaxClientsPerChain = 1 + MaxConnectionsPerChain = 1 + +INIT Init +NEXT Next + +""" + +tests = [ + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", +] + +for test in tests: + # create IBCTests.cfg file + with open("IBCTests.cfg", "w") as file: + file.write(CFG + "INVARIANT " + test + "Neg") + + # run tlc-json + os.system("tlc-json IBCTests.tla") + os.system("mv counterexample.json tests/" + test + ".json") diff --git a/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json b/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json new file mode 100644 index 0000000000..98bb5dea1f --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json @@ -0,0 +1,101 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "header": 1, + "type": "ICS02UpdateClient" + }, + "actionOutcome": "ICS02ClientNotFound", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS02CreateOKTest.json b/modules/tests/support/model_based/tests/ICS02CreateOKTest.json new file mode 100644 index 0000000000..4c74c17c80 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS02CreateOKTest.json @@ -0,0 +1,103 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index dfe22dd307..6b3ca8ac75 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -1,50 +1,156 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainB", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" }, - { - "action": { - "chainId": "chainB", - "header": 1, - "clientId": 0, - "type": "ICS02UpdateClient" - }, - "actionOutcome": "ICS02HeaderVerificationFailure", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "header": 1, + "type": "ICS02UpdateClient" + }, + "actionOutcome": "ICS02HeaderVerificationFailure", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index c41443ec45..9b8a59e527 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -1,118 +1,157 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainB", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } - }, - { - "action": { - "chainId": "chainB", - "header": 2, - "clientId": 0, - "type": "ICS02UpdateClient" + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS02UpdateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 2 - } - } - }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 1 - }, - "chainB": { - "height": 2 - } - } - }, - { - "action": { - "chainId": "chainA", - "header": 2, - "clientId": 0, - "type": "ICS02UpdateClient" + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS02UpdateOK", - "chains": { - "chainA": { - "height": 2 - }, - "chainB": { - "height": 2 - } - } + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 3 - }, - "chainB": { - "height": 2 - } - } + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "header": 2, + "type": "ICS02UpdateClient" }, - { - "action": { - "chainId": "chainA", - "header": 2, - "clientId": 1, - "type": "ICS02UpdateClient" + "actionOutcome": "ICS02UpdateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1, + 2 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS02UpdateOK", - "chains": { - "chainA": { - "height": 4 - }, - "chainB": { - "height": 2 - } - } + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index cd47bd504c..cfd4228b08 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -1,70 +1,230 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainB", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 2, + "consensusState": 2, + "type": "ICS02CreateClient" }, - { - "action": { - "chainId": "chainB", + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 2 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 2 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", "clientId": 0, - "counterpartyClientId": 1, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS03ConnectionOpenInitOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 2 - } - } + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": 0, + "type": "ICS03ConnectionOpenTry" }, - { - "action": { - "chainId": "chainB", - "previousConnectionId": 0, - "clientId": 1, - "clientState": 2, + "actionOutcome": "ICS03ConnectionMismatch", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 2 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionMismatch", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 2 - } - } + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index ab4b2d9af1..798bf48d94 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -1,53 +1,156 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainB", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "header": 1, + "type": "ICS02UpdateClient" }, - { - "action": { - "chainId": "chainB", - "previousConnectionId": 0, - "clientId": 0, - "clientState": 1, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionNotFound", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "ICS02ClientNotFound", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": 0, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionNotFound", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index 7b946e9ee9..dc4cf921c7 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -1,50 +1,165 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainB", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 1 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" }, - { - "action": { - "chainId": "chainB", + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", "clientId": 0, + "counterpartyChainId": "chainA", "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS03ConnectionOpenInitOK", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 2 - } - } + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 31bff42a0e..4507f2c87c 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -1,53 +1,116 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 1 - }, - "chainB": { - "height": 0 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" }, - { - "action": { + "actionOutcome": "ICS03ConnectionOpenTryOK", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { "chainId": "chainA", - "previousConnectionId": -1, "clientId": 0, "clientState": 1, + "counterpartyChainId": "chainA", "counterpartyClientId": 0, "counterpartyConnectionId": 0, + "previousConnectionId": -1, "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS03ConnectionOpenTryOK", - "chains": { - "chainA": { - "height": 2 - }, - "chainB": { - "height": 0 - } - } + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json index 4156b8bc91..e16c4ef05e 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json @@ -1,36 +1,105 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainA", - "previousConnectionId": -1, - "clientId": 0, - "clientState": 1, - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03InvalidConsensusHeight", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 2, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03InvalidConsensusHeight", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } } -] + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json index f88d40a375..53207d845d 100644 --- a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json @@ -1,67 +1,102 @@ [ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "height": 0 - }, - "chainB": { - "height": 0 - } - } + { + "action": { + "type": "None" }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 1 - }, - "chainB": { - "height": 0 - } - } - }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "height": 2 - }, - "chainB": { - "height": 0 - } - } + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" }, - { - "action": { - "chainId": "chainB", - "clientId": 0, - "counterpartyClientId": 0, - "type": "ICS03ConnectionOpenInit" + "actionOutcome": "ICS03MissingClient", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } }, - "actionOutcome": "ICS03MissingClient", - "chains": { - "chainA": { - "height": 2 - }, - "chainB": { - "height": 0 - } - } + "height": 1 + } } -] + } +] \ No newline at end of file From 5e04972b90acb1409caf67052967b3f34ac4ad67 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Thu, 18 Feb 2021 21:16:36 +0100 Subject: [PATCH 064/104] Fix ICS02UpdateClient --- modules/tests/executor/step.rs | 4 +- modules/tests/mbt.rs | 21 ++++---- modules/tests/support/model_based/IBC.tla | 2 +- .../model_based/tests/ICS02UpdateOKTest.json | 2 +- .../tests/ICS03ConnectionNotFoundTest.json | 51 ------------------- .../tests/ICS03ConnectionOpenInitOKTest.json | 8 +-- 6 files changed, 19 insertions(+), 69 deletions(-) diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index c4b5140119..39f00f906c 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -43,7 +43,7 @@ pub enum Action { client_id: u64, #[serde(alias = "counterpartyChainId")] - counterparty_chain_id: u64, + counterparty_chain_id: String, #[serde(alias = "counterpartyClientId")] counterparty_client_id: u64, @@ -63,7 +63,7 @@ pub enum Action { client_state: u64, #[serde(alias = "counterpartyChainId")] - counterparty_chain_id: u64, + counterparty_chain_id: String, #[serde(alias = "counterpartyClientId")] counterparty_client_id: u64, diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 66f9a1e26e..9c4781477b 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -3,18 +3,19 @@ mod executor; const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] -fn main() { +fn mbt() { let tests = vec![ - // "ICS02UpdateOKTest", - // "ICS02HeaderVerificationFailureTest", - // "ICS03ConnectionOpenInitOKTest", - // "ICS03MissingClientTest", - // the following test should fail but doesn't because proofs are not yet - // verified + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + // the following test should fail but doesn't because proofs are not yet verified "ICS03ConnectionOpenTryOKTest", - // "ICS03InvalidConsensusHeightTest", - // "ICS03ConnectionNotFoundTest", - // "ICS03ConnectionMismatchTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 1f8caefd94..2f25990e0e 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -177,7 +177,7 @@ UpdateClient(chainId, clientId, height) == LET result == ICS02_UpdateClient(chain, chainId, clientId, height) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result, "ICS03CreateOK"), + !.height = UpdateChainHeight(@, result, "ICS02UpdateOK"), !.clients = result.clients ] IN \* update `chains`, set the `action` and its `actionOutcome` diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index 9b8a59e527..bfb54b7493 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -130,7 +130,7 @@ "state": "Uninit" } }, - "height": 2 + "height": 3 }, "chainB": { "clientIdCounter": 0, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index 798bf48d94..d877871f1b 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -47,57 +47,6 @@ } } }, - { - "action": { - "chainId": "chainA", - "clientId": 0, - "header": 1, - "type": "ICS02UpdateClient" - }, - "actionOutcome": "ICS02ClientNotFound", - "chains": { - "chainA": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - }, - "chainB": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - } - } - }, { "action": { "chainId": "chainA", diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index dc4cf921c7..c39eab6033 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 1, - "consensusState": 1, + "clientState": 2, + "consensusState": 2, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, From a8023f2f49bc5d9164373429c0ee98f63e809bb6 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 10:43:31 +0100 Subject: [PATCH 065/104] Allow a conn open try to succeed only after a conn open init --- modules/tests/support/model_based/IBC.tla | 16 ++- .../tests/support/model_based/IBCTests.tla | 4 + modules/tests/support/model_based/ICS03.tla | 63 ++++++---- .../tests/support/model_based/gen_tests.py | 1 + .../tests/ICS03ConnectionMismatchTest.json | 12 +- .../tests/ICS03ConnectionNotFoundTest.json | 2 +- .../tests/ICS03ConnectionOpenInitOKTest.json | 42 +++---- .../tests/ICS03ConnectionOpenTryOKTest.json | 117 +----------------- .../ICS03InvalidConsensusHeightTest.json | 2 +- .../model_based/tests/ICS03InvalidProof.json | 1 + .../tests/ICS03MissingClientTest.json | 2 +- 11 files changed, 88 insertions(+), 174 deletions(-) create mode 100644 modules/tests/support/model_based/tests/ICS03InvalidProof.json diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 2f25990e0e..2dba776bcb 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -105,7 +105,8 @@ ActionOutcomes == { "ICS03ConnectionOpenTryOK", "ICS03InvalidConsensusHeight", "ICS03ConnectionNotFound", - "ICS03ConnectionMismatch" + "ICS03ConnectionMismatch", + "ICS03InvalidProof" } \* data kept per client @@ -260,7 +261,8 @@ CreateClientAction(chainId) == \E height \in Heights: \* only create client if the model constant `MaxClientsPerChain` allows \* it - IF chains[chainId].clientIdCounter < MaxClientsPerChain THEN + LET allowed == chains[chainId].clientIdCounter < MaxClientsPerChain IN + IF allowed THEN CreateClient(chainId, height) ELSE UNCHANGED vars @@ -281,7 +283,9 @@ ConnectionOpenInitAction(chainId) == \E counterpartyClientId \in ClientIds: \* only create connection if the model constant `MaxConnectionsPerChain` \* allows it - IF chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN + LET allowed == + chains[chainId].connectionIdCounter < MaxConnectionsPerChain IN + IF chainId /= counterpartyChainId /\ allowed THEN ConnectionOpenInit( chainId, clientId, @@ -307,8 +311,10 @@ ConnectionOpenTryAction(chainId) == \* only perform action if there was a previous connection or if the \* model constant `MaxConnectionsPerChain` allows that a new connection \* is created - IF \/ previousConnectionId /= ConnectionIdNone - \/ chains[chainId].connectionIdCounter < MaxConnectionsPerChain THEN + LET allowed == + \/ previousConnectionId /= ConnectionIdNone + \/ chains[chainId].connectionIdCounter < MaxConnectionsPerChain IN + IF chainId /= counterpartyChainId /\ allowed THEN ConnectionOpenTry( chainId, clientId, diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index b8e5271d9f..4a1b8b6fc8 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -32,6 +32,9 @@ ICS03ConnectionNotFoundTest == ICS03ConnectionMismatchTest == /\ actionOutcome = "ICS03ConnectionMismatch" +ICS03InvalidProofTest == + /\ actionOutcome = "ICS03InvalidProof" + ICS02CreateOKTestNeg == ~ICS02CreateOKTest ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ICS02ClientNotFoundTestNeg == ~ICS02ClientNotFoundTest @@ -42,5 +45,6 @@ ICS03ConnectionOpenTryOKTestNeg == ~ICS03ConnectionOpenTryOKTest ICS03InvalidConsensusHeightTestNeg == ~ICS03InvalidConsensusHeightTest ICS03ConnectionNotFoundTestNeg == ~ICS03ConnectionNotFoundTest ICS03ConnectionMismatchTestNeg == ~ICS03ConnectionMismatchTest +ICS03InvalidProofTestNeg == ~ICS03InvalidProofTest =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index f56398b99a..c52b444146 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -75,6 +75,7 @@ ICS03_ConnectionOpenInit( \* TODO: errors generated when verifying proofs are never an outcome of this \* model +\* TODO: check for a missing client? ICS03_ConnectionOpenTry( chain, chainId, @@ -172,28 +173,44 @@ ICS03_ConnectionOpenTry( outcome |-> "ICS03ConnectionNotFound" ] ELSE - \* TODO: check if there was an open init at the remote chain - \* verification passed; create connection - LET connection == [ - state |-> "TryOpen", - clientId |-> clientId, - \* generate a new connection identifier - connectionId |-> connectionIdCounter, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId - ] IN - \* return result with updated state - [ - connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, - connection - ), - \* since a new connection identifier has been created, here we - \* update the `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter + 1, - action |-> action, - outcome |-> "ICS03ConnectionOpenTryOK" - ] + \* check if there was an open init at the remote chain + LET openInitProofs == { + proof \in chain.connectionProofs : + /\ proof.type = "ICS03ConnectionOpenInit" + /\ chainId = counterpartyChainId + /\ clientId = counterpartyClientId + /\ counterpartyChainId = chainId + /\ counterpartyClientId = clientId + } IN + IF Cardinality(openInitProofs) > 0 THEN + \* verification passed; create connection + LET connection == [ + state |-> "TryOpen", + clientId |-> clientId, + \* generate a new connection identifier + connectionId |-> connectionIdCounter, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), + \* since a new connection identifier has been created, here we + \* update the `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter + 1, + action |-> action, + outcome |-> "ICS03ConnectionOpenTryOK" + ] + ELSE + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + action |-> action, + outcome |-> "ICS03InvalidProof" + ] =============================================================================== diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index cb68a281ab..c5631eafcb 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -25,6 +25,7 @@ "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", + "ICS03InvalidProof", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index cfd4228b08..3ea74c1282 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 2, - "consensusState": 2, + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, @@ -167,7 +167,7 @@ "chainId": "chainA", "clientId": 0, "clientState": 1, - "counterpartyChainId": "chainA", + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "counterpartyConnectionId": 0, "previousConnectionId": 0, @@ -180,7 +180,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index d877871f1b..87bda0f473 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -52,7 +52,7 @@ "chainId": "chainA", "clientId": 0, "clientState": 1, - "counterpartyChainId": "chainA", + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "counterpartyConnectionId": 0, "previousConnectionId": 0, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index c39eab6033..46d17af298 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 2, - "consensusState": 2, + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, @@ -104,7 +104,7 @@ "action": { "chainId": "chainA", "clientId": 0, - "counterpartyChainId": "chainA", + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, @@ -115,30 +115,22 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, - "connectionIdCounter": 0, - "connectionProofs": [ - { - "chainId": "chainA", - "clientId": 0, - "counterpartyChainId": "chainA", - "counterpartyClientId": 0, - "type": "ICS03ConnectionOpenInit" - } - ], + "connectionIdCounter": 1, + "connectionProofs": [], "connections": { "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Init" } }, - "height": 2 + "height": 3 }, "chainB": { "clientIdCounter": 0, @@ -148,7 +140,15 @@ } }, "connectionIdCounter": 0, - "connectionProofs": [], + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], "connections": { "0": { "clientId": -1, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 4507f2c87c..0637a088a0 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -1,116 +1 @@ -[ - { - "action": { - "type": "None" - }, - "actionOutcome": "None", - "chains": { - "chainA": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - }, - "chainB": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - } - } - }, - { - "action": { - "chainId": "chainA", - "clientId": 0, - "clientState": 1, - "counterpartyChainId": "chainA", - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "previousConnectionId": -1, - "type": "ICS03ConnectionOpenTry" - }, - "actionOutcome": "ICS03ConnectionOpenTryOK", - "chains": { - "chainA": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [ - { - "chainId": "chainA", - "clientId": 0, - "clientState": 1, - "counterpartyChainId": "chainA", - "counterpartyClientId": 0, - "counterpartyConnectionId": 0, - "previousConnectionId": -1, - "type": "ICS03ConnectionOpenTry" - } - ], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - }, - "chainB": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - } - } - } -] \ No newline at end of file +[] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json index e16c4ef05e..a89d61d1fe 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json @@ -52,7 +52,7 @@ "chainId": "chainA", "clientId": 0, "clientState": 2, - "counterpartyChainId": "chainA", + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "counterpartyConnectionId": 0, "previousConnectionId": -1, diff --git a/modules/tests/support/model_based/tests/ICS03InvalidProof.json b/modules/tests/support/model_based/tests/ICS03InvalidProof.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03InvalidProof.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json index 53207d845d..ab80e084c9 100644 --- a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json @@ -51,7 +51,7 @@ "action": { "chainId": "chainA", "clientId": 0, - "counterpartyChainId": "chainA", + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "type": "ICS03ConnectionOpenInit" }, From e9af4de0a5ab7ea8a83eff320b63b77c913549da Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 10:43:53 +0100 Subject: [PATCH 066/104] Improve modelator's error --- modules/tests/executor/modelator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tests/executor/modelator.rs b/modules/tests/executor/modelator.rs index 8af34be9b3..6c7f9a43df 100644 --- a/modules/tests/executor/modelator.rs +++ b/modules/tests/executor/modelator.rs @@ -10,12 +10,12 @@ pub enum ModelatorError { TestNotFound { path: String, error: String }, #[error("test '{path}' could not be deserialized: {error}")] InvalidTest { path: String, error: String }, - #[error("test '{path}' failed on step {step_index}/{step_count}:\nstep: {step:#?}\nexecutor: {executor:#?}")] + #[error("test '{path}' failed on step {step_index}/{step_count}:\nsteps: {steps:#?}\nexecutor: {executor:#?}")] FailedTest { path: String, step_index: usize, step_count: usize, - step: Step, + steps: Vec, executor: Executor, }, } @@ -47,7 +47,7 @@ where })?; let step_count = steps.len(); - for (i, step) in steps.into_iter().enumerate() { + for (i, step) in steps.iter().enumerate() { // check the step let ok = if i == 0 { executor.initial_step(step.clone()) @@ -60,7 +60,7 @@ where path: path.to_string(), step_index: i + 1, step_count, - step, + steps, executor, }); } From 35754911edd875b68fe45f0f0fa2b6301a50428c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 11:05:57 +0100 Subject: [PATCH 067/104] Generate tests --- modules/tests/executor/mod.rs | 17 ++- modules/tests/executor/step.rs | 1 + modules/tests/mbt.rs | 21 ++-- .../tests/support/model_based/gen_tests.py | 2 +- .../ICS02HeaderVerificationFailureTest.json | 8 +- .../tests/ICS03ConnectionMismatchTest.json | 10 +- .../tests/ICS03ConnectionNotFoundTest.json | 61 +++++++++- .../tests/ICS03ConnectionOpenInitOKTest.json | 8 +- .../model_based/tests/ICS03InvalidProof.json | 1 - .../tests/ICS03InvalidProofTest.json | 105 ++++++++++++++++++ 10 files changed, 203 insertions(+), 31 deletions(-) delete mode 100644 modules/tests/support/model_based/tests/ICS03InvalidProof.json create mode 100644 modules/tests/support/model_based/tests/ICS03InvalidProofTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 7b270b2d94..92c80dffa5 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -48,7 +48,8 @@ impl IBCTestExecutor { /// Panic if a context for `chain_id` already exists. pub fn init_chain_context(&mut self, chain_id: String, initial_height: u64) { let chain_id = Self::chain_id(chain_id); - let max_history_size = 1; + // never GC blocks + let max_history_size = usize::MAX; let ctx = MockContext::new( chain_id.clone(), HostType::Mock, @@ -193,6 +194,11 @@ impl IBCTestExecutor { .expect("it should be possible to create the proofs") } + /// Check that chain heights match the ones in the model. + pub fn validate_chains(&self) -> bool { + self.contexts.values().all(|ctx| ctx.validate().is_ok()) + } + /// Check that chain heights match the ones in the model. pub fn check_chain_heights(&self, chains: HashMap) -> bool { chains.into_iter().all(|(chain_id, chain)| { @@ -310,6 +316,7 @@ impl modelator::TestExecutor for IBCTestExecutor { fn next_step(&mut self, step: Step) -> bool { let result = self.apply(step.action); + println!("{:?}", result); let outcome_matches = match step.action_outcome { ActionOutcome::None => panic!("unexpected action outcome"), ActionOutcome::ICS02CreateOK => result.is_ok(), @@ -340,8 +347,12 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result), ICS03ErrorKind::ConnectionMismatch(_) ), + ActionOutcome::ICS03InvalidProof => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::InvalidProof + ), }; - // also check that chain heights match - outcome_matches && self.check_chain_heights(step.chains) + // also check the state of chains + outcome_matches && self.validate_chains() && self.check_chain_heights(step.chains) } } diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index 39f00f906c..37c3ee5f7d 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -101,6 +101,7 @@ pub enum ActionOutcome { ICS03InvalidConsensusHeight, ICS03ConnectionNotFound, ICS03ConnectionMismatch, + ICS03InvalidProof, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 9c4781477b..0993c3f30d 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,17 +5,18 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - "ICS02CreateOKTest", - "ICS02UpdateOKTest", - "ICS02ClientNotFoundTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", + // "ICS02CreateOKTest", + // "ICS02UpdateOKTest", + // "ICS02ClientNotFoundTest", + // "ICS02HeaderVerificationFailureTest", + // "ICS03ConnectionOpenInitOKTest", + // "ICS03MissingClientTest", // the following test should fail but doesn't because proofs are not yet verified - "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", + // "ICS03ConnectionOpenTryOKTest", + // "ICS03InvalidConsensusHeightTest", + // "ICS03ConnectionNotFoundTest", + // "ICS03ConnectionMismatchTest", + "ICS03InvalidProofTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index c5631eafcb..db183e2b75 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -25,7 +25,7 @@ "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", - "ICS03InvalidProof", + "ICS03InvalidProofTest", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index 6b3ca8ac75..d895bb0119 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 1, - "consensusState": 1, + "clientState": 2, + "consensusState": 2, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -114,7 +114,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index 3ea74c1282..40de6bd66e 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 1, - "consensusState": 1, + "clientState": 4, + "consensusState": 4, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 1 + 4 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 1 + 4 ] } }, @@ -180,7 +180,7 @@ "clients": { "0": { "heights": [ - 1 + 4 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index 87bda0f473..aeb99f636d 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -47,6 +47,59 @@ } } }, + { + "action": { + "chainId": "chainA", + "clientState": 2, + "consensusState": 2, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 2 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, { "action": { "chainId": "chainA", @@ -61,10 +114,12 @@ "actionOutcome": "ICS03ConnectionNotFound", "chains": { "chainA": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 2 + ] } }, "connectionIdCounter": 0, @@ -78,7 +133,7 @@ "state": "Uninit" } }, - "height": 1 + "height": 2 }, "chainB": { "clientIdCounter": 0, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index 46d17af298..e61ec8337b 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 1, - "consensusState": 1, + "clientState": 2, + "consensusState": 2, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03InvalidProof.json b/modules/tests/support/model_based/tests/ICS03InvalidProof.json deleted file mode 100644 index 0637a088a0..0000000000 --- a/modules/tests/support/model_based/tests/ICS03InvalidProof.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json new file mode 100644 index 0000000000..0bcf41180f --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json @@ -0,0 +1,105 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03InvalidProof", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file From 5170cc1e8d11b4305b23c9d6b6671439853cc5e3 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 11:07:31 +0100 Subject: [PATCH 068/104] Add MockContext::host_oldest_height --- modules/src/ics03_connection/context.rs | 3 +++ modules/src/ics03_connection/handler/verify.rs | 5 +---- modules/src/mock/context.rs | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/src/ics03_connection/context.rs b/modules/src/ics03_connection/context.rs index 718101a842..6dd70e5f83 100644 --- a/modules/src/ics03_connection/context.rs +++ b/modules/src/ics03_connection/context.rs @@ -22,6 +22,9 @@ pub trait ConnectionReader { /// Returns the current height of the local chain. fn host_current_height(&self) -> Height; + /// Returns the oldest height available on the local chain. + fn host_oldest_height(&self) -> Height; + /// Returns the number of consensus state entries that the local chain maintains. The history /// size determines the pruning window of the host chain. fn host_chain_history_size(&self) -> usize; diff --git a/modules/src/ics03_connection/handler/verify.rs b/modules/src/ics03_connection/handler/verify.rs index c26c52679a..007e8a9258 100644 --- a/modules/src/ics03_connection/handler/verify.rs +++ b/modules/src/ics03_connection/handler/verify.rs @@ -197,10 +197,7 @@ pub fn check_client_consensus_height( return Err(Kind::InvalidConsensusHeight(claimed_height, ctx.host_current_height()).into()); } - let oldest_available_height = - ctx.host_current_height().revision_height - ctx.host_chain_history_size() as u64; - - if claimed_height.revision_height < oldest_available_height { + if claimed_height < ctx.host_oldest_height() { // Fail if the consensus height is too old (has been pruned). return Err(Kind::StaleConsensusHeight(claimed_height, ctx.host_current_height()).into()); } diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index c27f8a33d4..defe4ad6da 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -470,6 +470,11 @@ impl ConnectionReader for MockContext { self.latest_height } + fn host_oldest_height(&self) -> Height { + // history must be non-empty, so `self.history[0]` is valid + self.history[0].height() + } + /// Returns the number of consensus state historical entries for the local chain. fn host_chain_history_size(&self) -> usize { self.max_history_size From 3b83a64b574b33a6ebb8ede07b24ecb95c701e2c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 11:12:43 +0100 Subject: [PATCH 069/104] Update CHANGELOG --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d9ec409f..5d42298441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,11 +32,10 @@ [comment]: <> ( - [nothing yet]) -[comment]: <> (### BUG FIXES) - -[comment]: <> (- [ibc]) +### BUG FIXES -[comment]: <> ( - [nothing yet]) +- [ibc] + - Overflow if `ctx.host_current_height().revision_height < ctx.host_chain_history_size()` ([#685]) [comment]: <> (- [ibc-relayer]) @@ -60,6 +59,8 @@ [comment]: <> ( - [nothing yet]) +[#685]: https://github.com/informalsystems/ibc-rs/issues/685 + ## v0.1.1 *February 17, 2021* From fc6a238b5804cf9a6793807164181c50a802a06c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 11:14:01 +0100 Subject: [PATCH 070/104] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d42298441..4d60818651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -[comment]: <> (## Unreleased Changes) +## Unreleased Changes [comment]: <> (> [high level summary]) From 4da1d34c9d0505a360060c69957394b9bb55690a Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 14:36:46 +0100 Subject: [PATCH 071/104] Fix conn open ack tests --- modules/src/ics03_connection/error.rs | 2 +- .../ics03_connection/handler/conn_open_ack.rs | 20 ++++++++++++------- .../src/ics03_connection/handler/verify.rs | 2 +- modules/src/mock/context.rs | 4 ++-- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/modules/src/ics03_connection/error.rs b/modules/src/ics03_connection/error.rs index aaa30a360a..eb49c07e17 100644 --- a/modules/src/ics03_connection/error.rs +++ b/modules/src/ics03_connection/error.rs @@ -23,7 +23,7 @@ pub enum Kind { #[error("consensus height claimed by the client on the other party is too advanced: {0} (host chain current height: {1})")] InvalidConsensusHeight(Height, Height), - #[error("consensus height claimed by the client on the other party falls outside of trusting period: {0} (host chain current height: {1})")] + #[error("consensus height claimed by the client on the other party has been pruned: {0} (host chain oldest height: {1})")] StaleConsensusHeight(Height, Height), #[error("identifier error")] diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index 187c5e5a09..ac13c39845 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -110,7 +110,6 @@ mod tests { use crate::ics24_host::identifier::{ChainId, ClientId}; use crate::mock::context::MockContext; use crate::mock::host::HostType; - use crate::Height; #[test] fn conn_open_ack_msg_processing() { @@ -131,11 +130,13 @@ mod tests { // Parametrize the host chain to have a height at least as recent as the // the height of the proofs in the Ack msg. + let latest_height = proof_height.increment(); + let max_history_size = 5; let default_context = MockContext::new( - ChainId::new("mockgaia".to_string(), 1), + ChainId::new("mockgaia".to_string(), latest_height.revision_number), HostType::Mock, - 5, - Height::new(1, msg_ack.proofs().height().increment().revision_height), + max_history_size, + latest_height, ); // A connection end that will exercise the successful path. @@ -188,7 +189,7 @@ mod tests { }, Test { name: "Processing fails because the connection does not exist in the context".to_string(), - ctx: MockContext::default(), // Empty context + ctx: default_context.clone(), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: false, error_kind: Some(Kind::UninitializedConnection(conn_id.clone())), @@ -216,12 +217,14 @@ mod tests { Test { name: "Processing fails due to mismatching counterparty conn id".to_string(), ctx: default_context + .clone() .with_client(&client_id, proof_height) .with_connection(conn_id.clone(), conn_end_cparty), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: false, error_kind: Some(Kind::ConnectionMismatch(conn_id.clone())) }, + /* Test { name: "Processing fails due to MissingLocalConsensusState".to_string(), ctx: MockContext::default() @@ -231,6 +234,7 @@ mod tests { want_pass: false, error_kind: Some(Kind::MissingLocalConsensusState) }, + */ ]; for test in tests { @@ -257,7 +261,6 @@ mod tests { } } Err(e) => { - println!("Error for {:?} was {:#?}", test.name, e.kind()); assert_eq!( test.want_pass, false, @@ -272,7 +275,10 @@ mod tests { assert_eq!( &expected_kind, e.kind(), - "conn_open_ack: expected error kind mismatches thrown error kind" + "conn_open_ack: failed for test: {}\nexpected error kind: {:?}\nfound: {:?}", + test.name, + expected_kind, + e.kind() ) } } diff --git a/modules/src/ics03_connection/handler/verify.rs b/modules/src/ics03_connection/handler/verify.rs index 007e8a9258..6f6e3c89c6 100644 --- a/modules/src/ics03_connection/handler/verify.rs +++ b/modules/src/ics03_connection/handler/verify.rs @@ -199,7 +199,7 @@ pub fn check_client_consensus_height( if claimed_height < ctx.host_oldest_height() { // Fail if the consensus height is too old (has been pruned). - return Err(Kind::StaleConsensusHeight(claimed_height, ctx.host_current_height()).into()); + return Err(Kind::StaleConsensusHeight(claimed_height, ctx.host_oldest_height()).into()); } // Height check is within normal bounds, check passes. diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index defe4ad6da..c6dd743d3f 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -102,10 +102,10 @@ pub struct MockContext { impl Default for MockContext { fn default() -> Self { Self::new( - ChainId::new("mockgaia".to_string(), 1), + ChainId::new("mockgaia".to_string(), 0), HostType::Mock, 5, - Height::new(1, 5), + Height::new(0, 5), ) } } From 56382c414d4e5c2d681591519901cb59fea989cc Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 13:37:23 +0000 Subject: [PATCH 072/104] Update CHANGELOG.md Co-authored-by: Adi Seredinschi --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d60818651..1308f92a56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,7 @@ ### BUG FIXES - [ibc] - - Overflow if `ctx.host_current_height().revision_height < ctx.host_chain_history_size()` ([#685]) + - Fix overflow bug in ICS03 client consensus height verification method ([#685]) [comment]: <> (- [ibc-relayer]) From c851c336c039286ef803cdae5e693d058cf0c342 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 14:39:13 +0100 Subject: [PATCH 073/104] Remove MockContext::host_chain_history_size --- modules/src/ics03_connection/context.rs | 4 ---- modules/src/ics03_connection/handler/conn_open_try.rs | 7 +++---- modules/src/mock/context.rs | 5 ----- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/modules/src/ics03_connection/context.rs b/modules/src/ics03_connection/context.rs index 6dd70e5f83..1f3d79a0fa 100644 --- a/modules/src/ics03_connection/context.rs +++ b/modules/src/ics03_connection/context.rs @@ -25,10 +25,6 @@ pub trait ConnectionReader { /// Returns the oldest height available on the local chain. fn host_oldest_height(&self) -> Height; - /// Returns the number of consensus state entries that the local chain maintains. The history - /// size determines the pruning window of the host chain. - fn host_chain_history_size(&self) -> usize; - /// Returns the prefix that the local chain uses in the KV store. fn commitment_prefix(&self) -> CommitmentPrefix; diff --git a/modules/src/ics03_connection/handler/conn_open_try.rs b/modules/src/ics03_connection/handler/conn_open_try.rs index 27f97ca7a6..c6a9977af1 100644 --- a/modules/src/ics03_connection/handler/conn_open_try.rs +++ b/modules/src/ics03_connection/handler/conn_open_try.rs @@ -107,7 +107,6 @@ mod tests { use crate::events::IBCEvent; use crate::ics03_connection::connection::State; - use crate::ics03_connection::context::ConnectionReader; use crate::ics03_connection::handler::{dispatch, ConnectionResult}; use crate::ics03_connection::msgs::conn_open_try::test_util::get_dummy_msg_conn_open_try; use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; @@ -127,13 +126,13 @@ mod tests { } let host_chain_height = Height::new(0, 35); + let max_history_size = 5; let context = MockContext::new( ChainId::new("mockgaia".to_string(), 0), HostType::Mock, - 5, + max_history_size, host_chain_height, ); - let pruning_window = context.host_chain_history_size() as u64; let client_consensus_state_height = 10; let msg_conn_try = MsgConnectionOpenTry::try_from(get_dummy_msg_conn_open_try( @@ -149,7 +148,7 @@ mod tests { )) .unwrap(); let pruned_height = host_chain_height - .sub(pruning_window + 1) + .sub(max_history_size as u64 + 1) .unwrap() .revision_height; // The consensus proof targets a missing height (pruned) on destination chain. diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index c6dd743d3f..c95d7818c8 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -475,11 +475,6 @@ impl ConnectionReader for MockContext { self.history[0].height() } - /// Returns the number of consensus state historical entries for the local chain. - fn host_chain_history_size(&self) -> usize { - self.max_history_size - } - fn commitment_prefix(&self) -> CommitmentPrefix { CommitmentPrefix::from(vec![]) } From f4e8c270c9062a55e8cc7c1543b7b53a6a4323d0 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 15:00:38 +0100 Subject: [PATCH 074/104] Fix clippy --- modules/src/ics03_connection/handler/conn_open_ack.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index ac13c39845..486a4fc28f 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -220,9 +220,9 @@ mod tests { .clone() .with_client(&client_id, proof_height) .with_connection(conn_id.clone(), conn_end_cparty), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), + msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), want_pass: false, - error_kind: Some(Kind::ConnectionMismatch(conn_id.clone())) + error_kind: Some(Kind::ConnectionMismatch(conn_id)) }, /* Test { From 7fa9932a9b34f4a80dcaae1e9edf7295c07511f9 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 15:09:19 +0100 Subject: [PATCH 075/104] Fix clippy --- modules/src/ics03_connection/handler/conn_open_ack.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index 486a4fc28f..c59e17445f 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -182,7 +182,7 @@ mod tests { ctx: default_context .clone() .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), default_conn_end.clone()), + .with_connection(conn_id.clone(), default_conn_end), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: true, error_kind: None, @@ -217,7 +217,6 @@ mod tests { Test { name: "Processing fails due to mismatching counterparty conn id".to_string(), ctx: default_context - .clone() .with_client(&client_id, proof_height) .with_connection(conn_id.clone(), conn_end_cparty), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), From b4f31b233842d382196aef906c74fff4aab5074c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 17:20:21 +0100 Subject: [PATCH 076/104] Fix ICS03_ConnectionOpenTry --- .../tests/support/model_based/IBCTests.tla | 7 + modules/tests/support/model_based/ICS03.tla | 8 +- .../tests/ICS03ConnectionOpenInitOKTest.json | 8 +- .../tests/ICS03ConnectionOpenTryOKTest.json | 242 +++++++++++++++++- 4 files changed, 256 insertions(+), 9 deletions(-) diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 4a1b8b6fc8..29100ed8fb 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -35,12 +35,19 @@ ICS03ConnectionMismatchTest == ICS03InvalidProofTest == /\ actionOutcome = "ICS03InvalidProof" +\* ICS02CreateClient tests ICS02CreateOKTestNeg == ~ICS02CreateOKTest + +\* ICS02UpdateClient tests ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ICS02ClientNotFoundTestNeg == ~ICS02ClientNotFoundTest ICS02HeaderVerificationFailureTestNeg == ~ICS02HeaderVerificationFailureTest + +\* ICS03ConnectionOpenInit tests ICS03ConnectionOpenInitOKTestNeg == ~ICS03ConnectionOpenInitOKTest ICS03MissingClientTestNeg == ~ICS03MissingClientTest + +\* ICS03ConnectionOpenTry tests ICS03ConnectionOpenTryOKTestNeg == ~ICS03ConnectionOpenTryOKTest ICS03InvalidConsensusHeightTestNeg == ~ICS03InvalidConsensusHeightTest ICS03ConnectionNotFoundTestNeg == ~ICS03ConnectionNotFoundTest diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index c52b444146..6fadacb84a 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -177,10 +177,10 @@ ICS03_ConnectionOpenTry( LET openInitProofs == { proof \in chain.connectionProofs : /\ proof.type = "ICS03ConnectionOpenInit" - /\ chainId = counterpartyChainId - /\ clientId = counterpartyClientId - /\ counterpartyChainId = chainId - /\ counterpartyClientId = clientId + /\ proof.chainId = counterpartyChainId + /\ proof.clientId = counterpartyClientId + /\ proof.counterpartyChainId = chainId + /\ proof.counterpartyClientId = clientId } IN IF Cardinality(openInitProofs) > 0 THEN \* verification passed; create connection diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index e61ec8337b..46d17af298 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 2, - "consensusState": 2, + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 0637a088a0..680a56fbef 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -1 +1,241 @@ -[] \ No newline at end of file +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionOpenTryOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "TryOpen" + } + }, + "height": 2 + } + } + } +] \ No newline at end of file From 4bd0ea952be80b2cbdf3a384975cfb471ed11d34 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 18:23:03 +0100 Subject: [PATCH 077/104] Finish connection open try --- modules/tests/executor/mod.rs | 4 + modules/tests/executor/step.rs | 1 + modules/tests/mbt.rs | 23 +-- modules/tests/support/model_based/IBC.tla | 2 + .../tests/support/model_based/IBCTests.tla | 4 + modules/tests/support/model_based/ICS03.tla | 97 +++++++---- .../tests/support/model_based/gen_tests.py | 1 + .../ICS02HeaderVerificationFailureTest.json | 8 +- .../tests/ICS03ConnectionMismatchTest.json | 10 +- .../tests/ICS03ConnectionNotFoundTest.json | 8 +- .../tests/ICS03ConnectionOpenTryOKTest.json | 81 ++++++++- .../tests/ICS03InvalidProofTest.json | 61 ++++++- .../ICS03MissingClientConsensusStateTest.json | 160 ++++++++++++++++++ 13 files changed, 389 insertions(+), 71 deletions(-) create mode 100644 modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 92c80dffa5..f13c4674fd 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -347,6 +347,10 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result), ICS03ErrorKind::ConnectionMismatch(_) ), + ActionOutcome::ICS03MissingClientConsensusState => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::MissingClientConsensusState(_, _) + ), ActionOutcome::ICS03InvalidProof => matches!( Self::extract_handler_error_kind::(result), ICS03ErrorKind::InvalidProof diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index 37c3ee5f7d..14f4afdb7e 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -101,6 +101,7 @@ pub enum ActionOutcome { ICS03InvalidConsensusHeight, ICS03ConnectionNotFound, ICS03ConnectionMismatch, + ICS03MissingClientConsensusState, ICS03InvalidProof, } diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 0993c3f30d..8a6a56c383 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,18 +5,19 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - // "ICS02CreateOKTest", - // "ICS02UpdateOKTest", - // "ICS02ClientNotFoundTest", - // "ICS02HeaderVerificationFailureTest", - // "ICS03ConnectionOpenInitOKTest", - // "ICS03MissingClientTest", + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", + "ICS03MissingClientConsensusStateTest", // the following test should fail but doesn't because proofs are not yet verified - // "ICS03ConnectionOpenTryOKTest", - // "ICS03InvalidConsensusHeightTest", - // "ICS03ConnectionNotFoundTest", - // "ICS03ConnectionMismatchTest", - "ICS03InvalidProofTest", + // "ICS03InvalidProofTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 2dba776bcb..79c52fd011 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -106,6 +106,8 @@ ActionOutcomes == { "ICS03InvalidConsensusHeight", "ICS03ConnectionNotFound", "ICS03ConnectionMismatch", + \* TODO: "ICS03MissingClient" is also an outcome + "ICS03MissingClientConsensusState", "ICS03InvalidProof" } diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 29100ed8fb..29ce3b95dd 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -32,6 +32,9 @@ ICS03ConnectionNotFoundTest == ICS03ConnectionMismatchTest == /\ actionOutcome = "ICS03ConnectionMismatch" +ICS03MissingClientConsensusStateTest == + /\ actionOutcome = "ICS03MissingClientConsensusState" + ICS03InvalidProofTest == /\ actionOutcome = "ICS03InvalidProof" @@ -52,6 +55,7 @@ ICS03ConnectionOpenTryOKTestNeg == ~ICS03ConnectionOpenTryOKTest ICS03InvalidConsensusHeightTestNeg == ~ICS03InvalidConsensusHeightTest ICS03ConnectionNotFoundTestNeg == ~ICS03ConnectionNotFoundTest ICS03ConnectionMismatchTestNeg == ~ICS03ConnectionMismatchTest +ICS03MissingClientConsensusStateTestNeg == ~ICS03MissingClientConsensusStateTest ICS03InvalidProofTestNeg == ~ICS03InvalidProofTest =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 6fadacb84a..1b41f06dac 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -73,9 +73,6 @@ ICS03_ConnectionOpenInit( outcome |-> "ICS03MissingClient" ] -\* TODO: errors generated when verifying proofs are never an outcome of this -\* model -\* TODO: check for a missing client? ICS03_ConnectionOpenTry( chain, chainId, @@ -173,44 +170,72 @@ ICS03_ConnectionOpenTry( outcome |-> "ICS03ConnectionNotFound" ] ELSE - \* check if there was an open init at the remote chain - LET openInitProofs == { - proof \in chain.connectionProofs : - /\ proof.type = "ICS03ConnectionOpenInit" - /\ proof.chainId = counterpartyChainId - /\ proof.clientId = counterpartyClientId - /\ proof.counterpartyChainId = chainId - /\ proof.counterpartyClientId = clientId - } IN - IF Cardinality(openInitProofs) > 0 THEN - \* verification passed; create connection - LET connection == [ - state |-> "TryOpen", - clientId |-> clientId, - \* generate a new connection identifier - connectionId |-> connectionIdCounter, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId - ] IN - \* return result with updated state - [ - connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, - connection - ), - \* since a new connection identifier has been created, here we - \* update the `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter + 1, - action |-> action, - outcome |-> "ICS03ConnectionOpenTryOK" - ] + \* check if the client exists + IF ICS02_ClientExists(clients, clientId) THEN + \* check if the client has a consensus state with this height + LET client == ICS02_GetClient(clients, clientId) IN + IF height \in client.heights THEN + \* check if there was an open init at the remote chain + LET openInitProofs == { + proof \in chain.connectionProofs : + /\ proof.type = "ICS03ConnectionOpenInit" + /\ proof.chainId = counterpartyChainId + /\ proof.clientId = counterpartyClientId + /\ proof.counterpartyChainId = chainId + /\ proof.counterpartyClientId = clientId + } IN + IF Cardinality(openInitProofs) > 0 THEN + \* verification passed; create connection + LET connection == [ + state |-> "TryOpen", + clientId |-> clientId, + \* generate a new connection identifier + connectionId |-> connectionIdCounter, + counterpartyClientId |-> counterpartyClientId, + counterpartyConnectionId |-> counterpartyConnectionId + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionIdCounter, + connection + ), + \* since a new connection identifier has been + \* created, here we update the `connectionIdCounter` + connectionIdCounter |-> connectionIdCounter + 1, + action |-> action, + outcome |-> "ICS03ConnectionOpenTryOK" + ] + ELSE + \* if there wasn't an open init at the remote chain, + \* then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + action |-> action, + outcome |-> "ICS03InvalidProof" + ] + ELSE + \* if the client does have a consensus state with this + \* height, then set an error outcome + [ + connections |-> connections, + connectionIdCounter |-> connectionIdCounter, + action |-> action, + outcome |-> "ICS03MissingClientConsensusState" + ] ELSE + \* if the client does not exist, then set an error outcome + \* TODO: the generation of tests cannot distinguish between an + \* an error here and an error in + \* `ICS03_ConnectionOpenInit`; we can solve this with in + \* history variable, like in the light client tests. [ connections |-> connections, connectionIdCounter |-> connectionIdCounter, action |-> action, - outcome |-> "ICS03InvalidProof" + outcome |-> "ICS03MissingClient" ] =============================================================================== diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index db183e2b75..d795b85ad6 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -25,6 +25,7 @@ "ICS03InvalidConsensusHeightTest", "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", + "ICS03MissingClientConsensusStateTest", "ICS03InvalidProofTest", ] diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index d895bb0119..6b3ca8ac75 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 2, - "consensusState": 2, + "clientState": 1, + "consensusState": 1, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, @@ -114,7 +114,7 @@ "clients": { "0": { "heights": [ - 2 + 1 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index 40de6bd66e..036d601f26 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 4, - "consensusState": 4, + "clientState": 2, + "consensusState": 2, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 4 + 2 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 4 + 2 ] } }, @@ -180,7 +180,7 @@ "clients": { "0": { "heights": [ - 4 + 2 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index aeb99f636d..b6429c138c 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 2, - "consensusState": 2, + "clientState": 3, + "consensusState": 3, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 2 + 3 ] } }, @@ -118,7 +118,7 @@ "clients": { "0": { "heights": [ - 2 + 3 ] } }, diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 680a56fbef..6499e39cab 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -50,8 +50,8 @@ { "action": { "chainId": "chainA", - "clientState": 1, - "consensusState": 1, + "clientState": 2, + "consensusState": 2, "type": "ICS02CreateClient" }, "actionOutcome": "ICS02CreateOK", @@ -61,7 +61,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -115,7 +115,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -162,6 +162,69 @@ } } }, + { + "action": { + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 2 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + } + } + }, { "action": { "chainId": "chainB", @@ -180,7 +243,7 @@ "clients": { "0": { "heights": [ - 1 + 2 ] } }, @@ -209,10 +272,12 @@ "height": 3 }, "chainB": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 1 + ] } }, "connectionIdCounter": 1, @@ -234,7 +299,7 @@ "state": "TryOpen" } }, - "height": 2 + "height": 3 } } } diff --git a/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json index 0bcf41180f..bea670184a 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json @@ -47,6 +47,59 @@ } } }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, { "action": { "chainId": "chainA", @@ -61,10 +114,12 @@ "actionOutcome": "ICS03InvalidProof", "chains": { "chainA": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 1 + ] } }, "connectionIdCounter": 0, @@ -78,7 +133,7 @@ "state": "Uninit" } }, - "height": 1 + "height": 2 }, "chainB": { "clientIdCounter": 0, diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json new file mode 100644 index 0000000000..663a59010f --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json @@ -0,0 +1,160 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 3, + "consensusState": 3, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03MissingClientConsensusState", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file From 87bd1d7412e56f4fa9dd078b08c1d326d624a3ce Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 19:45:39 +0100 Subject: [PATCH 078/104] Start conn open ack --- modules/tests/executor/mod.rs | 31 +++- modules/tests/executor/step.rs | 16 ++ modules/tests/mbt.rs | 23 +-- modules/tests/support/model_based/IBC.tla | 70 +++++++- .../tests/support/model_based/IBCTests.tla | 6 + modules/tests/support/model_based/ICS03.tla | 24 +++ .../tests/support/model_based/gen_tests.py | 25 +-- .../tests/ICS03ConnectionOpenAckOKTest.json | 167 ++++++++++++++++++ 8 files changed, 335 insertions(+), 27 deletions(-) create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index f13c4674fd..f135fa6af2 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -9,6 +9,7 @@ use ibc::ics02_client::msgs::update_client::MsgUpdateAnyClient; use ibc::ics02_client::msgs::ClientMsg; use ibc::ics03_connection::connection::Counterparty; use ibc::ics03_connection::error::Kind as ICS03ErrorKind; +use ibc::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use ibc::ics03_connection::msgs::ConnectionMsg; @@ -280,9 +281,8 @@ impl IBCTestExecutor { MsgConnectionOpenTry { previous_connection_id: previous_connection_id.map(Self::connection_id), client_id: Self::client_id(client_id), + // TODO: is this ever needed? client_state: None, - // TODO: it should be like this: - // client_state: Some(Self::client_state(client_state)), counterparty: Self::counterparty( counterparty_client_id, Some(counterparty_connection_id), @@ -295,6 +295,33 @@ impl IBCTestExecutor { ))); ctx.deliver(msg) } + Action::ICS03ConnectionOpenAck { + chain_id, + connection_id, + client_state, + counterparty_chain_id: _, + counterparty_connection_id, + } => { + // get chain's context + let ctx = self.chain_context_mut(chain_id); + + // create ICS26 message and deliver it + let msg = ICS26Envelope::ICS3Msg(ConnectionMsg::ConnectionOpenAck(Box::new( + MsgConnectionOpenAck { + connection_id: Self::connection_id(connection_id), + // TODO: the following should not be an option + counterparty_connection_id: Some(Self::connection_id( + counterparty_connection_id, + )), + // TODO: is this ever needed? + client_state: None, + proofs: Self::proofs(client_state), + version: Self::version(), + signer: Self::signer(), + }, + ))); + ctx.deliver(msg) + } } } } diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index 14f4afdb7e..eb23305d23 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -68,6 +68,22 @@ pub enum Action { #[serde(alias = "counterpartyClientId")] counterparty_client_id: u64, + #[serde(alias = "counterpartyConnectionId")] + counterparty_connection_id: u64, + }, + ICS03ConnectionOpenAck { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "connectionId")] + connection_id: u64, + + #[serde(alias = "clientState")] + client_state: u64, + + #[serde(alias = "counterpartyChainId")] + counterparty_chain_id: String, + #[serde(alias = "counterpartyConnectionId")] counterparty_connection_id: u64, }, diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 8a6a56c383..f53cbf315d 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,19 +5,20 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - "ICS02CreateOKTest", - "ICS02UpdateOKTest", - "ICS02ClientNotFoundTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", - "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", - "ICS03MissingClientConsensusStateTest", + // "ICS02CreateOKTest", + // "ICS02UpdateOKTest", + // "ICS02ClientNotFoundTest", + // "ICS02HeaderVerificationFailureTest", + // "ICS03ConnectionOpenInitOKTest", + // "ICS03MissingClientTest", + // "ICS03ConnectionOpenTryOKTest", + // "ICS03InvalidConsensusHeightTest", + // "ICS03ConnectionNotFoundTest", + // "ICS03ConnectionMismatchTest", + // "ICS03MissingClientConsensusStateTest", // the following test should fail but doesn't because proofs are not yet verified // "ICS03InvalidProofTest", + "ICS03ConnectionOpenAckOKTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 79c52fd011..6047e87c88 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -79,9 +79,19 @@ ConnectionOpenTryActions == [ counterpartyClientId: ClientIds, counterpartyConnectionId: ConnectionIds ] <: {ActionType} +ConnectionOpenAckActions == [ + type: {"ICS03ConnectionOpenAck"}, + chainId: ChainIds, + connectionId: ConnectionIds, + \* `clientState` contains simply a height + clientState: Heights, + counterpartyChainId: ChainIds, + counterpartyConnectionId: ConnectionIds +] <: {ActionType} ConnectionActions == ConnectionOpenInitActions \union - ConnectionOpenTryActions + ConnectionOpenTryActions \union + ConnectionOpenAckActions Actions == NoneActions \union @@ -108,7 +118,9 @@ ActionOutcomes == { "ICS03ConnectionMismatch", \* TODO: "ICS03MissingClient" is also an outcome "ICS03MissingClientConsensusState", - "ICS03InvalidProof" + "ICS03InvalidProof", + \* ICS03_ConnectionOpenAck outcomes: + "ICS03ConnectionOpenAckOK" } \* data kept per client @@ -258,6 +270,39 @@ ConnectionOpenTry( /\ action' = result.action /\ actionOutcome' = result.outcome +ConnectionOpenAck( + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId +) == + LET chain == chains[chainId] IN + LET result == ICS03_ConnectionOpenAck( + chain, + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId + ) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenAckOK"), + !.connections = result.connections + ] IN + \* update the counterparty chain with a proof + LET counterpartyChain == chains[counterpartyChainId] IN + LET updatedCounterpartyChain == [counterpartyChain EXCEPT + !.connectionProofs = UpdateConnectionProofs(@, result, "ICS03ConnectionOpenAckOK") + ] IN + \* update `chains`, set the `action` and its `actionOutcome` + /\ chains' = [chains EXCEPT + ![chainId] = updatedChain, + ![counterpartyChainId] = updatedCounterpartyChain] + /\ action' = result.action + /\ actionOutcome' = result.outcome + CreateClientAction(chainId) == \* select a height for the client to be created at \E height \in Heights: @@ -329,6 +374,26 @@ ConnectionOpenTryAction(chainId) == ELSE UNCHANGED vars +ConnectionOpenAckAction(chainId) == + \* select a connection id + \E connectionId \in ConnectionIds: + \* select a claimed height for the client + \E height \in Heights: + \* select a counterparty chain id + \E counterpartyChainId \in ChainIds: + \* select a counterparty connection id + \E counterpartyConnectionId \in ConnectionIds: + IF chainId /= counterpartyChainId THEN + ConnectionOpenAck( + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId + ) + ELSE + UNCHANGED vars + Init == \* create a client and a connection with none values LET clientNone == [ @@ -364,6 +429,7 @@ Next == \/ UpdateClientAction(chainId) \/ ConnectionOpenInitAction(chainId) \/ ConnectionOpenTryAction(chainId) + \/ ConnectionOpenAckAction(chainId) \/ UNCHANGED vars ELSE \/ UNCHANGED vars diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 29ce3b95dd..affea22937 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -38,6 +38,9 @@ ICS03MissingClientConsensusStateTest == ICS03InvalidProofTest == /\ actionOutcome = "ICS03InvalidProof" +ICS03ConnectionOpenAckOKTest == + /\ actionOutcome = "ICS03ConnectionOpenAckOK" + \* ICS02CreateClient tests ICS02CreateOKTestNeg == ~ICS02CreateOKTest @@ -58,4 +61,7 @@ ICS03ConnectionMismatchTestNeg == ~ICS03ConnectionMismatchTest ICS03MissingClientConsensusStateTestNeg == ~ICS03MissingClientConsensusStateTest ICS03InvalidProofTestNeg == ~ICS03InvalidProofTest +\* ICS03ConnectionOpenAck tests +ICS03ConnectionOpenAckOKTestNeg == ~ICS03ConnectionOpenAckOKTest + =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 1b41f06dac..bddfcd4291 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -238,4 +238,28 @@ ICS03_ConnectionOpenTry( outcome |-> "ICS03MissingClient" ] +ICS03_ConnectionOpenAck( + chain, + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId +) == + LET action == AsAction([ + type |-> "ICS03ConnectionOpenAck", + chainId |-> chainId, + connectionId |-> connectionId, + clientState |-> height, + counterpartyChainId |-> counterpartyChainId, + counterpartyConnectionId |-> counterpartyConnectionId + ]) IN + LET connections == chain.connections IN + LET connectionProofs == chain.connectionProofs IN + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03ConnectionOpenAckOK" + ] + =============================================================================== diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index d795b85ad6..cfe7117c0d 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -15,18 +15,19 @@ """ tests = [ - "ICS02CreateOKTest", - "ICS02UpdateOKTest", - "ICS02ClientNotFoundTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", - "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", - "ICS03MissingClientConsensusStateTest", - "ICS03InvalidProofTest", + # "ICS02CreateOKTest", + # "ICS02UpdateOKTest", + # "ICS02ClientNotFoundTest", + # "ICS02HeaderVerificationFailureTest", + # "ICS03ConnectionOpenInitOKTest", + # "ICS03MissingClientTest", + # "ICS03ConnectionOpenTryOKTest", + # "ICS03InvalidConsensusHeightTest", + # "ICS03ConnectionNotFoundTest", + # "ICS03ConnectionMismatchTest", + # "ICS03MissingClientConsensusStateTest", + # "ICS03InvalidProofTest", + "ICS03ConnectionOpenAckOKTest", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json new file mode 100644 index 0000000000..350aea49ec --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json @@ -0,0 +1,167 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + }, + "actionOutcome": "ICS03ConnectionOpenAckOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + } + ], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file From f751e0eac5b6a9cf61e99de1acf0f268e1c0381c Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Fri, 19 Feb 2021 19:53:58 +0100 Subject: [PATCH 079/104] handle ICS03ConnectionOpenAckOK --- modules/tests/executor/mod.rs | 1 + modules/tests/executor/step.rs | 1 + .../tests/ICS03ConnectionOpenAckOKTest.json | 61 +------------------ 3 files changed, 5 insertions(+), 58 deletions(-) diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 7c2afff05f..777e6069d2 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -382,6 +382,7 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result), ICS03ErrorKind::InvalidProof ), + ActionOutcome::ICS03ConnectionOpenAckOK => result.is_ok(), }; // also check the state of chains outcome_matches && self.validate_chains() && self.check_chain_heights(step.chains) diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index eb23305d23..c13a8842a1 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -119,6 +119,7 @@ pub enum ActionOutcome { ICS03ConnectionMismatch, ICS03MissingClientConsensusState, ICS03InvalidProof, + ICS03ConnectionOpenAckOK, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json index 350aea49ec..3926e07b2f 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json @@ -47,59 +47,6 @@ } } }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "consensusState": 1, - "type": "ICS02CreateClient" - }, - "actionOutcome": "ICS02CreateOK", - "chains": { - "chainA": { - "clientIdCounter": 1, - "clients": { - "0": { - "heights": [ - 1 - ] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 2 - }, - "chainB": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - } - } - }, { "action": { "chainId": "chainA", @@ -112,12 +59,10 @@ "actionOutcome": "ICS03ConnectionOpenAckOK", "chains": { "chainA": { - "clientIdCounter": 1, + "clientIdCounter": 0, "clients": { "0": { - "heights": [ - 1 - ] + "heights": [] } }, "connectionIdCounter": 0, @@ -131,7 +76,7 @@ "state": "Uninit" } }, - "height": 3 + "height": 2 }, "chainB": { "clientIdCounter": 0, From 1c6bd3a2c257eecd9c00fcde35d6488b38648c80 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Sat, 20 Feb 2021 13:34:12 +0100 Subject: [PATCH 080/104] Add conn open ack --- modules/tests/executor/mod.rs | 4 + modules/tests/executor/step.rs | 1 + modules/tests/mbt.rs | 1 + modules/tests/support/model_based/IBC.tla | 9 +- .../tests/support/model_based/IBCTests.tla | 4 + modules/tests/support/model_based/ICS02.tla | 65 +++-- modules/tests/support/model_based/ICS03.tla | 271 +++++++++++------- .../tests/support/model_based/gen_tests.py | 1 + .../ICS03UninitializedConnectionTest.json | 103 +++++++ 9 files changed, 325 insertions(+), 134 deletions(-) create mode 100644 modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index bf38e0a27f..fbbb5635cd 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -382,6 +382,10 @@ impl modelator::TestExecutor for IBCTestExecutor { ICS03ErrorKind::InvalidProof ), ActionOutcome::ICS03ConnectionOpenAckOK => result.is_ok(), + ActionOutcome::ICS03UninitializedConnection => matches!( + Self::extract_handler_error_kind::(result), + ICS03ErrorKind::UninitializedConnection(_) + ), }; // also check the state of chains outcome_matches && self.validate_chains() && self.check_chain_heights(step.chains) diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index c13a8842a1..9842097bdb 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -120,6 +120,7 @@ pub enum ActionOutcome { ICS03MissingClientConsensusState, ICS03InvalidProof, ICS03ConnectionOpenAckOK, + ICS03UninitializedConnection, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index f53cbf315d..4f3844b480 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -19,6 +19,7 @@ fn mbt() { // the following test should fail but doesn't because proofs are not yet verified // "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", + // "ICS03UninitializedConnectionTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 6047e87c88..bd4e3e7a18 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -116,12 +116,17 @@ ActionOutcomes == { "ICS03InvalidConsensusHeight", "ICS03ConnectionNotFound", "ICS03ConnectionMismatch", - \* TODO: "ICS03MissingClient" is also an outcome "ICS03MissingClientConsensusState", "ICS03InvalidProof", \* ICS03_ConnectionOpenAck outcomes: - "ICS03ConnectionOpenAckOK" + "ICS03ConnectionOpenAckOK", + "ICS03UninitializedConnection" } +\* TODO: the current generation of tests cannot distinguish between a +\* "ICS03ConnectionMismatch" generated in conn open try or one generated +\* in conn open ack; (there are other cases like "ICS03ConnectionMismatch") +\* we can solve this with in a variable 'history', like in the light +\* client tests. \* data kept per client Client == [ diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index affea22937..33c93d1b51 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -41,6 +41,9 @@ ICS03InvalidProofTest == ICS03ConnectionOpenAckOKTest == /\ actionOutcome = "ICS03ConnectionOpenAckOK" +ICS03UninitializedConnectionTest == + /\ actionOutcome = "ICS03UninitializedConnection" + \* ICS02CreateClient tests ICS02CreateOKTestNeg == ~ICS02CreateOKTest @@ -63,5 +66,6 @@ ICS03InvalidProofTestNeg == ~ICS03InvalidProofTest \* ICS03ConnectionOpenAck tests ICS03ConnectionOpenAckOKTestNeg == ~ICS03ConnectionOpenAckOKTest +ICS03UninitializedConnectionTestNeg == ~ICS03UninitializedConnectionTest =============================================================================== diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 80cc587b60..6350b1e399 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -21,15 +21,13 @@ ICS02_CreateClient(chain, chainId, height) == clientState |-> height, consensusState |-> height ]) IN - LET clients == chain.clients IN - LET clientIdCounter == chain.clientIdCounter IN \* check if the client exists (it shouldn't) - IF ICS02_ClientExists(clients, clientIdCounter) THEN + IF ICS02_ClientExists(chain.clients, chain.clientIdCounter) THEN \* if the client to be created already exists, \* then there's an error in the model [ - clients |-> clients, - clientIdCounter |-> clientIdCounter, + clients |-> chain.clients, + clientIdCounter |-> chain.clientIdCounter, action |-> action, outcome |-> "ModelError" ] @@ -40,8 +38,12 @@ ICS02_CreateClient(chain, chainId, height) == ] IN \* return result with updated state [ - clients |-> ICS02_SetClient(clients, clientIdCounter, client), - clientIdCounter |-> clientIdCounter + 1, + clients |-> ICS02_SetClient( + chain.clients, + chain.clientIdCounter, + client + ), + clientIdCounter |-> chain.clientIdCounter + 1, action |-> action, outcome |-> "ICS02CreateOK" ] @@ -53,38 +55,41 @@ ICS02_UpdateClient(chain, chainId, clientId, height) == clientId |-> clientId, header |-> height ]) IN - LET clients == chain.clients IN \* check if the client exists - IF ICS02_ClientExists(clients, clientId) THEN + IF ~ICS02_ClientExists(chain.clients, clientId) THEN + \* if the client does not exist, then set an error outcome + [ + clients |-> chain.clients, + action |-> action, + outcome |-> "ICS02ClientNotFound" + ] + ELSE \* if the client exists, check its height - LET client == ICS02_GetClient(clients, clientId) IN - LET latestHeight == Max(client.heights) IN - IF latestHeight < height THEN - \* if the client's height is lower than the one being updated to - \* then, update the client + LET client == ICS02_GetClient(chain.clients, clientId) IN + LET highestHeight == Max(client.heights) IN + IF highestHeight >= height THEN + \* if the client's new height is not higher than the highest client + \* height, then set an error outcome + [ + clients |-> chain.clients, + action |-> action, + outcome |-> "ICS02HeaderVerificationFailure" + ] + ELSE + \* if the client's new height is higher than the highest client + \* height, then update the client LET updatedClient == [client EXCEPT !.heights = client.heights \union {height} ] IN \* return result with updated state [ - clients |-> ICS02_SetClient(clients, clientId, updatedClient), + clients |-> ICS02_SetClient( + chain.clients, + clientId, + updatedClient + ), action |-> action, outcome |-> "ICS02UpdateOK" ] - ELSE - \* if the client's height is at least as high as the one being - \* updated to, then set an error outcome - [ - clients |-> clients, - action |-> action, - outcome |-> "ICS02HeaderVerificationFailure" - ] - ELSE - \* if the client does not exist, then set an error outcome - [ - clients |-> clients, - action |-> action, - outcome |-> "ICS02ClientNotFound" - ] =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index bddfcd4291..95ecc127b2 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -28,19 +28,24 @@ ICS03_ConnectionOpenInit( counterpartyChainId |-> counterpartyChainId, counterpartyClientId |-> counterpartyClientId ]) IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN \* check if the client exists - IF ICS02_ClientExists(clients, clientId) THEN + IF ~ICS02_ClientExists(chain.clients, clientId) THEN + \* if the client does not exist, then set an error outcome + [ + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, + action |-> action, + outcome |-> "ICS03MissingClient" + ] + ELSE \* if the client exists, \* then check if the connection exists (it shouldn't) - IF ICS03_ConnectionExists(connections, connectionIdCounter) THEN + IF ICS03_ConnectionExists(chain.connections, chain.connectionIdCounter) THEN \* if the connection to be created already exists, \* then there's an error in the model [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, action |-> action, outcome |-> "ModelError" ] @@ -50,28 +55,20 @@ ICS03_ConnectionOpenInit( state |-> "Init", clientId |-> clientId, counterpartyClientId |-> counterpartyClientId, - connectionId |-> connectionIdCounter, + connectionId |-> chain.connectionIdCounter, counterpartyConnectionId |-> ConnectionIdNone ] IN \* return result with updated state [ connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, + chain.connections, + chain.connectionIdCounter, connection ), - connectionIdCounter |-> connectionIdCounter + 1, + connectionIdCounter |-> chain.connectionIdCounter + 1, action |-> action, outcome |-> "ICS03ConnectionOpenInitOK" ] - ELSE - \* if the client does not exist, then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - action |-> action, - outcome |-> "ICS03MissingClient" - ] ICS03_ConnectionOpenTry( chain, @@ -93,19 +90,12 @@ ICS03_ConnectionOpenTry( counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> counterpartyConnectionId ]) IN - LET clients == chain.clients IN - LET connections == chain.connections IN - LET connectionIdCounter == chain.connectionIdCounter IN - LET connectionProofs == chain.connectionProofs IN \* check if client's claimed height is higher than the chain's height IF height > chain.height THEN \* if client's height is too advanced, then set an error outcome - \* TODO: in the ICS03, this error also occurs if - \* "height == chain.height", which is not the case in the - \* Rust implementation [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, action |-> action, outcome |-> "ICS03InvalidConsensusHeight" ] @@ -119,62 +109,80 @@ ICS03_ConnectionOpenTry( \* identifier, it can reuse the identifier created by its own open init. IF previousConnectionId /= ConnectionIdNone THEN \* if so, check if the connection exists - IF ICS03_ConnectionExists(connections, previousConnectionId) THEN - \* if the connection exists, verify that is matches the - \* the parameters provided + IF ~ICS03_ConnectionExists(chain.connections, previousConnectionId) THEN + \* if the connection does not exist, then set an error outcome + [ + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, + action |-> action, + outcome |-> "ICS03ConnectionNotFound" + ] + ELSE + \* if the connection exists, verify that is matches the the + \* parameters provided LET connection == ICS03_GetConnection( - connections, + chain.connections, previousConnectionId ) IN - IF /\ connection.state = "Init" - /\ connection.clientId = clientId - /\ connection.counterpartyClientId = counterpartyClientId - /\ connection.counterpartyConnectionId = counterpartyConnectionId - THEN + LET validConnection == + /\ connection.state = "Init" + /\ connection.clientId = clientId + /\ connection.counterpartyClientId = counterpartyClientId + /\ connection.counterpartyConnectionId = counterpartyConnectionId IN + IF ~validConnection THEN + \* if the existing connection does not match, then set an + \* error outcome + [ + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, + action |-> action, + outcome |-> "ICS03ConnectionMismatch" + ] + ELSE \* verification passed; update the connection state to \* "TryOpen" - LET updatedConnection == [ - state |-> "TryOpen", - clientId |-> clientId, - connectionId |-> previousConnectionId, - counterpartyClientId |-> counterpartyClientId, - counterpartyConnectionId |-> counterpartyConnectionId + LET updatedConnection == [connection EXCEPT + !.state = "TryOpen" ] IN \* return result with updated state [ connections |-> ICS03_SetConnection( - connections, + chain.connections, previousConnectionId, updatedConnection ), \* as the connection identifier has already been \* created, here we do not update the \* `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter, + connectionIdCounter |-> chain.connectionIdCounter, action |-> action, outcome |-> "ICS03ConnectionOpenTryOK" ] - ELSE - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - action |-> action, - outcome |-> "ICS03ConnectionMismatch" - ] - ELSE - \* if the connection does not exist, then set an error outcome + ELSE + \* in this case, `previousConnectionId` was not set; check if the + \* client exists + IF ~ICS02_ClientExists(chain.clients, clientId) THEN + \* if the client does not exist, then set an error outcome [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, action |-> action, - outcome |-> "ICS03ConnectionNotFound" + outcome |-> "ICS03MissingClient" ] - ELSE - \* check if the client exists - IF ICS02_ClientExists(clients, clientId) THEN + ELSE \* check if the client has a consensus state with this height - LET client == ICS02_GetClient(clients, clientId) IN - IF height \in client.heights THEN + LET client == ICS02_GetClient(chain.clients, clientId) IN + LET consensusStateExists == height \in client.heights IN + IF ~consensusStateExists THEN + \* if the client does have a consensus state with this + \* height, then set an error outcome + [ + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, + action |-> action, + outcome |-> "ICS03MissingClientConsensusState" + ] + ELSE \* check if there was an open init at the remote chain LET openInitProofs == { proof \in chain.connectionProofs : @@ -184,59 +192,39 @@ ICS03_ConnectionOpenTry( /\ proof.counterpartyChainId = chainId /\ proof.counterpartyClientId = clientId } IN - IF Cardinality(openInitProofs) > 0 THEN + LET proofExists == Cardinality(openInitProofs) > 0 IN + IF ~proofExists THEN + \* if there wasn't an open init at the remote chain, + \* then set an error outcome + [ + connections |-> chain.connections, + connectionIdCounter |-> chain.connectionIdCounter, + action |-> action, + outcome |-> "ICS03InvalidProof" + ] + ELSE \* verification passed; create connection LET connection == [ state |-> "TryOpen", clientId |-> clientId, \* generate a new connection identifier - connectionId |-> connectionIdCounter, + connectionId |-> chain.connectionIdCounter, counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> counterpartyConnectionId ] IN \* return result with updated state [ connections |-> ICS03_SetConnection( - connections, - connectionIdCounter, + chain.connections, + chain.connectionIdCounter, connection ), \* since a new connection identifier has been \* created, here we update the `connectionIdCounter` - connectionIdCounter |-> connectionIdCounter + 1, + connectionIdCounter |-> chain.connectionIdCounter + 1, action |-> action, outcome |-> "ICS03ConnectionOpenTryOK" ] - ELSE - \* if there wasn't an open init at the remote chain, - \* then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - action |-> action, - outcome |-> "ICS03InvalidProof" - ] - ELSE - \* if the client does have a consensus state with this - \* height, then set an error outcome - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - action |-> action, - outcome |-> "ICS03MissingClientConsensusState" - ] - ELSE - \* if the client does not exist, then set an error outcome - \* TODO: the generation of tests cannot distinguish between an - \* an error here and an error in - \* `ICS03_ConnectionOpenInit`; we can solve this with in - \* history variable, like in the light client tests. - [ - connections |-> connections, - connectionIdCounter |-> connectionIdCounter, - action |-> action, - outcome |-> "ICS03MissingClient" - ] ICS03_ConnectionOpenAck( chain, @@ -254,12 +242,91 @@ ICS03_ConnectionOpenAck( counterpartyChainId |-> counterpartyChainId, counterpartyConnectionId |-> counterpartyConnectionId ]) IN + LET clients == chain.clients IN LET connections == chain.connections IN LET connectionProofs == chain.connectionProofs IN - [ - connections |-> connections, - action |-> action, - outcome |-> "ICS03ConnectionOpenAckOK" - ] + \* check if client's claimed height is higher than the chain's height + IF height > chain.height THEN + \* if client's height is too advanced, then set an error outcome + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03InvalidConsensusHeight" + ] + \* TODO: add `chain_max_history_size` to the model to be able to also + \* return a `ICS03StaleConsensusHeight` error outcome + ELSE + \* check if the connection exists + IF ~ICS03_ConnectionExists(connections, connectionId) THEN + \* if the connection does not exist, then set an error outcome + \* TODO: can't we reuse the same error "ICS03ConnectionNotFound" + \* from conn open try? + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03UninitializedConnection" + ] + ELSE + \* if the connection exists, verify that is either Init or TryOpen; + \* also check that the counterparty connection id matches + LET connection == ICS03_GetConnection(connections, connectionId) IN + LET validConnection == + /\ connection.state \in {"Init", "TryOpen"} + /\ connection.counterpartyConnectionId = counterpartyConnectionId IN + IF ~validConnection THEN + \* if the existing connection does not match, then set an + \* error outcome + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03ConnectionMismatch" + ] + ELSE + \* check if the client has a consensus state with this height + LET client == ICS02_GetClient(clients, connection.clientId) IN + LET consensusStateExists == height \in client.heights IN + IF ~consensusStateExists THEN + \* if the client does have a consensus state with this + \* height, then set an error outcome + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03MissingClientConsensusState" + ] + ELSE + \* check if there was an open try at the remote chain + LET openTryProofs == { + proof \in chain.connectionProofs : + /\ proof.type = "ICS03ConnectionOpenTry" + /\ proof.chainId = connection.counterpartyChainId + /\ proof.clientId = connection.counterpartyClientId + /\ proof.counterpartyChainId = connection.chainId + /\ proof.counterpartyClientId = connection.clientId + } IN + LET proofExists == Cardinality(openTryProofs) > 0 IN + IF ~proofExists THEN + \* if there wasn't an open try at the remote chain, + \* then set an error outcome + [ + connections |-> chain.connections, + action |-> action, + outcome |-> "ICS03InvalidProof" + ] + ELSE + \* verification passed; update the connection state to + \* "Open" + LET updatedConnection == [connection EXCEPT + !.state = "Open" + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionId, + updatedConnection + ), + action |-> action, + outcome |-> "ICS03ConnectionOpenAckOK" + ] =============================================================================== diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index cfe7117c0d..aaf390ae7d 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -28,6 +28,7 @@ # "ICS03MissingClientConsensusStateTest", # "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", + # "ICS03UninitializedConnectionTest", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json new file mode 100644 index 0000000000..00320c78bb --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json @@ -0,0 +1,103 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + }, + "actionOutcome": "ICS03UninitializedConnection", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "clientId": -1, + "connectionId": -1, + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + } +] \ No newline at end of file From ff4fbde0fc6c67698fc94d863ac2674a99cb7709 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 11:26:43 +0100 Subject: [PATCH 081/104] potential bug --- modules/src/ics03_connection/handler/conn_open_ack.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index 73a50e0500..755c32cf83 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -32,6 +32,13 @@ pub(crate) fn process( // Check that if the msg's counterparty connection id is not empty then it matches // the old connection's counterparty. + // TODO: the following looks like a bug in two ways: + // - first, it doesn't make sense to not have a counterparty + // connection id + // - second (assuming that a counterparty connection id is + // is required), when we do the open init, we don't know + // the counterparty connection id; so how could it match + // the one in the message? let counterparty_matches = msg.counterparty_connection_id().is_none() || old_conn_end.counterparty().connection_id() == msg.counterparty_connection_id(); From ebb856975f2fad81ae758a1ace6c0621c885c66a Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 11:31:45 +0100 Subject: [PATCH 082/104] Finish conn open ack --- modules/tests/mbt.rs | 24 ++-- modules/tests/support/model_based/IBC.tla | 2 +- .../support/model_based/IBCDefinitions.tla | 2 +- modules/tests/support/model_based/ICS02.tla | 2 +- modules/tests/support/model_based/ICS03.tla | 6 +- .../tests/support/model_based/gen_tests.py | 26 ++--- .../tests/ICS03ConnectionOpenAckOKTest.json | 109 ++++++------------ 7 files changed, 67 insertions(+), 104 deletions(-) diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 4f3844b480..7494a75eee 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,21 +5,21 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - // "ICS02CreateOKTest", - // "ICS02UpdateOKTest", - // "ICS02ClientNotFoundTest", - // "ICS02HeaderVerificationFailureTest", - // "ICS03ConnectionOpenInitOKTest", - // "ICS03MissingClientTest", - // "ICS03ConnectionOpenTryOKTest", - // "ICS03InvalidConsensusHeightTest", - // "ICS03ConnectionNotFoundTest", - // "ICS03ConnectionMismatchTest", - // "ICS03MissingClientConsensusStateTest", + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", + "ICS03MissingClientConsensusStateTest", // the following test should fail but doesn't because proofs are not yet verified // "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", - // "ICS03UninitializedConnectionTest", + "ICS03UninitializedConnectionTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index bd4e3e7a18..5c220513c0 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -1,6 +1,6 @@ --------------------------------- MODULE IBC ---------------------------------- -EXTENDS Integers, FiniteSets, ICS02, ICS03 +EXTENDS ICS02, ICS03 \* ids of existing chains CONSTANT ChainIds diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index 5a39072a79..fccc40bf5b 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -1,6 +1,6 @@ --------------------------- MODULE IBCDefinitions ----------------------------- -EXTENDS Integers, FiniteSets +EXTENDS Integers, FiniteSets, TLC (********************** TYPE ANNOTATIONS FOR APALACHE ************************) \* operator for type annotations diff --git a/modules/tests/support/model_based/ICS02.tla b/modules/tests/support/model_based/ICS02.tla index 6350b1e399..658cc2f9c1 100644 --- a/modules/tests/support/model_based/ICS02.tla +++ b/modules/tests/support/model_based/ICS02.tla @@ -1,6 +1,6 @@ ------------------------------- MODULE ICS02 ---------------------------------- -EXTENDS Integers, FiniteSets, IBCDefinitions +EXTENDS IBCDefinitions \* retrieves `clientId`'s data ICS02_GetClient(clients, clientId) == diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 95ecc127b2..5c9a6020bb 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -1,6 +1,6 @@ ------------------------------ MODULE ICS03 ----------------------------------- -EXTENDS Integers, FiniteSets, IBCDefinitions, ICS02 +EXTENDS ICS02 \* retrieves `connectionId`'s data ICS03_GetConnection(connections, connectionId) == @@ -272,7 +272,9 @@ ICS03_ConnectionOpenAck( LET connection == ICS03_GetConnection(connections, connectionId) IN LET validConnection == /\ connection.state \in {"Init", "TryOpen"} - /\ connection.counterpartyConnectionId = counterpartyConnectionId IN + \* TODO: the implementation is not checking the following; + \* should it? + /\ connection.counterpartyChainId = counterpartyChainId IN IF ~validConnection THEN \* if the existing connection does not match, then set an \* error outcome diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index aaf390ae7d..8768df698b 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -15,20 +15,20 @@ """ tests = [ - # "ICS02CreateOKTest", - # "ICS02UpdateOKTest", - # "ICS02ClientNotFoundTest", - # "ICS02HeaderVerificationFailureTest", - # "ICS03ConnectionOpenInitOKTest", - # "ICS03MissingClientTest", - # "ICS03ConnectionOpenTryOKTest", - # "ICS03InvalidConsensusHeightTest", - # "ICS03ConnectionNotFoundTest", - # "ICS03ConnectionMismatchTest", - # "ICS03MissingClientConsensusStateTest", - # "ICS03InvalidProofTest", + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", + "ICS03MissingClientConsensusStateTest", + "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", - # "ICS03UninitializedConnectionTest", + "ICS03UninitializedConnectionTest", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json index 3926e07b2f..117807bae2 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json @@ -6,106 +6,67 @@ "actionOutcome": "None", "chains": { "chainA": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 1 + ] } }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - }, - "chainB": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] - } - }, - "connectionIdCounter": 0, - "connectionProofs": [], - "connections": { - "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" - } - }, - "height": 1 - } - } - }, - { - "action": { - "chainId": "chainA", - "clientState": 1, - "connectionId": 0, - "counterpartyChainId": "chainB", - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenAck" - }, - "actionOutcome": "ICS03ConnectionOpenAckOK", - "chains": { - "chainA": { - "clientIdCounter": 0, - "clients": { - "0": { - "heights": [] + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" } - }, - "connectionIdCounter": 0, - "connectionProofs": [], + ], "connections": { "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Init" } }, - "height": 2 + "height": 3 }, "chainB": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 1 + ] } }, - "connectionIdCounter": 0, + "connectionIdCounter": 1, "connectionProofs": [ { "chainId": "chainA", - "clientState": 1, - "connectionId": 0, + "clientId": 0, "counterpartyChainId": "chainB", - "counterpartyConnectionId": 0, - "type": "ICS03ConnectionOpenAck" + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" } ], "connections": { "0": { - "clientId": -1, - "connectionId": -1, - "counterpartyClientId": -1, - "counterpartyConnectionId": -1, - "state": "Uninit" + "clientId": 0, + "connectionId": 0, + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "TryOpen" } }, - "height": 1 + "height": 3 } } } From 5f10217012035988bbbe9d4479b90f92e015d476 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 11:59:22 +0100 Subject: [PATCH 083/104] Add conn open confirm --- modules/tests/support/model_based/IBC.tla | 79 +++++++++++++-- .../support/model_based/IBCDefinitions.tla | 2 + .../tests/support/model_based/IBCTests.tla | 6 ++ modules/tests/support/model_based/ICS03.tla | 97 ++++++++++++++++++- .../tests/support/model_based/gen_tests.py | 1 + 5 files changed, 178 insertions(+), 7 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 5c220513c0..0f28a4bee3 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -88,10 +88,20 @@ ConnectionOpenAckActions == [ counterpartyChainId: ChainIds, counterpartyConnectionId: ConnectionIds ] <: {ActionType} +ConnectionOpenConfirmActions == [ + type: {"ICS03ConnectionOpenConfirm"}, + chainId: ChainIds, + connectionId: ConnectionIds, + \* `clientState` contains simply a height + clientState: Heights, + counterpartyChainId: ChainIds, + counterpartyConnectionId: ConnectionIds +] <: {ActionType} ConnectionActions == ConnectionOpenInitActions \union ConnectionOpenTryActions \union - ConnectionOpenAckActions + ConnectionOpenAckActions \union + ConnectionOpenConfirmActions Actions == NoneActions \union @@ -120,11 +130,14 @@ ActionOutcomes == { "ICS03InvalidProof", \* ICS03_ConnectionOpenAck outcomes: "ICS03ConnectionOpenAckOK", - "ICS03UninitializedConnection" + "ICS03UninitializedConnection", + \* ICS03_ConnectionOpenConfirm outcomes: + "ICS03ConnectionOpenConfirmOK" } \* TODO: the current generation of tests cannot distinguish between a -\* "ICS03ConnectionMismatch" generated in conn open try or one generated -\* in conn open ack; (there are other cases like "ICS03ConnectionMismatch") +\* "ICS03ConnectionMismatch" generated in conn open try, one generated +\* in conn open ack, or one genereted in conn open confirm; +\* (there are other cases like "ICS03InvalidProof") \* we can solve this with in a variable 'history', like in the light \* client tests. @@ -139,9 +152,12 @@ Clients == [ \* data kept per connection Connection == [ state: ConnectionStates, + \* `chainId` is not strictly necessary but it's kept for consistency + chainId: ChainIds \union {ChainIdNone}, clientId: ClientIds \union {ClientIdNone}, - counterpartyClientId: ClientIds \union {ClientIdNone}, connectionId: ConnectionIds \union {ConnectionIdNone}, + counterpartyChainId: ChainIds \union {ChainIdNone}, + counterpartyClientId: ClientIds \union {ClientIdNone}, counterpartyConnectionId: ConnectionIds \union {ConnectionIdNone} ] \* mapping from connection identifier to its data @@ -308,6 +324,34 @@ ConnectionOpenAck( /\ action' = result.action /\ actionOutcome' = result.outcome +ConnectionOpenConfirm( + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId +) == + LET chain == chains[chainId] IN + LET result == ICS03_ConnectionOpenConfirm( + chain, + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId + ) IN + \* update the chain + LET updatedChain == [chain EXCEPT + !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenAckConfirm"), + !.connections = result.connections + ] IN + \* no need to update the counterparty chain with a proof (as in the other + \* connection open handlers) + \* update `chains`, set the `action` and its `actionOutcome` + /\ chains' = [chains EXCEPT ![chainId] = updatedChain] + /\ action' = result.action + /\ actionOutcome' = result.outcome + CreateClientAction(chainId) == \* select a height for the client to be created at \E height \in Heights: @@ -399,6 +443,26 @@ ConnectionOpenAckAction(chainId) == ELSE UNCHANGED vars +ConnectionOpenConfirmAction(chainId) == + \* select a connection id + \E connectionId \in ConnectionIds: + \* select a claimed height for the client + \E height \in Heights: + \* select a counterparty chain id + \E counterpartyChainId \in ChainIds: + \* select a counterparty connection id + \E counterpartyConnectionId \in ConnectionIds: + IF chainId /= counterpartyChainId THEN + ConnectionOpenConfirm( + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId + ) + ELSE + UNCHANGED vars + Init == \* create a client and a connection with none values LET clientNone == [ @@ -406,9 +470,11 @@ Init == ] IN LET connectionNone == [ state |-> "Uninit", + chainId |-> ChainIdNone, clientId |-> ClientIdNone, - counterpartyClientId |-> ClientIdNone, connectionId |-> ConnectionIdNone, + counterpartyChainId |-> ChainIdNone, + counterpartyClientId |-> ClientIdNone, counterpartyConnectionId |-> ConnectionIdNone ] IN \* create an empty chain @@ -435,6 +501,7 @@ Next == \/ ConnectionOpenInitAction(chainId) \/ ConnectionOpenTryAction(chainId) \/ ConnectionOpenAckAction(chainId) + \/ ConnectionOpenConfirmAction(chainId) \/ UNCHANGED vars ELSE \/ UNCHANGED vars diff --git a/modules/tests/support/model_based/IBCDefinitions.tla b/modules/tests/support/model_based/IBCDefinitions.tla index fccc40bf5b..6c1712bd6b 100644 --- a/modules/tests/support/model_based/IBCDefinitions.tla +++ b/modules/tests/support/model_based/IBCDefinitions.tla @@ -27,6 +27,8 @@ AsSetInt(S) == S <: {Int} Max(S) == CHOOSE x \in S: \A y \in S: y <= x (*****************************************************************************) +\* if a chain identifier is not set then it is "-1" +ChainIdNone == "-1" \* if a client identifier is not set then it is -1 ClientIdNone == -1 \* if a connection identifier is not set then it is -1 diff --git a/modules/tests/support/model_based/IBCTests.tla b/modules/tests/support/model_based/IBCTests.tla index 33c93d1b51..52a4978340 100644 --- a/modules/tests/support/model_based/IBCTests.tla +++ b/modules/tests/support/model_based/IBCTests.tla @@ -44,6 +44,9 @@ ICS03ConnectionOpenAckOKTest == ICS03UninitializedConnectionTest == /\ actionOutcome = "ICS03UninitializedConnection" +ICS03ConnectionOpenConfirmOKTest == + /\ actionOutcome = "ICS03ConnectionOpenConfirmOK" + \* ICS02CreateClient tests ICS02CreateOKTestNeg == ~ICS02CreateOKTest @@ -68,4 +71,7 @@ ICS03InvalidProofTestNeg == ~ICS03InvalidProofTest ICS03ConnectionOpenAckOKTestNeg == ~ICS03ConnectionOpenAckOKTest ICS03UninitializedConnectionTestNeg == ~ICS03UninitializedConnectionTest +\* ICS03ConnectionOpenConfirm tests +ICS03ConnectionOpenConfirmOKTestNeg == ~ICS03ConnectionOpenConfirmOKTest + =============================================================================== diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 5c9a6020bb..97cde85db9 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -53,9 +53,12 @@ ICS03_ConnectionOpenInit( \* if it doesn't, create it LET connection == [ state |-> "Init", + chainId |-> chainId, clientId |-> clientId, - counterpartyClientId |-> counterpartyClientId, + \* generate a new connection identifier connectionId |-> chain.connectionIdCounter, + counterpartyChainId |-> counterpartyChainId, + counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> ConnectionIdNone ] IN \* return result with updated state @@ -206,9 +209,11 @@ ICS03_ConnectionOpenTry( \* verification passed; create connection LET connection == [ state |-> "TryOpen", + chainId |-> chainId, clientId |-> clientId, \* generate a new connection identifier connectionId |-> chain.connectionIdCounter, + counterpartyChainId |-> counterpartyChainId, counterpartyClientId |-> counterpartyClientId, counterpartyConnectionId |-> counterpartyConnectionId ] IN @@ -331,4 +336,94 @@ ICS03_ConnectionOpenAck( outcome |-> "ICS03ConnectionOpenAckOK" ] +ICS03_ConnectionOpenConfirm( + chain, + chainId, + connectionId, + height, + counterpartyChainId, + counterpartyConnectionId +) == + LET action == AsAction([ + type |-> "ICS03ConnectionOpenConfirm", + chainId |-> chainId, + connectionId |-> connectionId, + clientState |-> height, + counterpartyChainId |-> counterpartyChainId, + counterpartyConnectionId |-> counterpartyConnectionId + ]) IN + LET clients == chain.clients IN + LET connections == chain.connections IN + LET connectionProofs == chain.connectionProofs IN + \* check if the connection exists + IF ~ICS03_ConnectionExists(connections, connectionId) THEN + \* if the connection does not exist, then set an error outcome + \* TODO: can't we reuse the same error "ICS03ConnectionNotFound" + \* from conn open try? + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03UninitializedConnection" + ] + ELSE + \* if the connection exists, verify that is either Init or TryOpen; + \* also check that the counterparty connection id matches + LET connection == ICS03_GetConnection(connections, connectionId) IN + LET validConnection == connection.state = "TryOpen" IN + IF ~validConnection THEN + \* if the existing connection does not match, then set an + \* error outcome + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03ConnectionMismatch" + ] + ELSE + \* check if the client has a consensus state with this height + LET client == ICS02_GetClient(clients, connection.clientId) IN + LET consensusStateExists == height \in client.heights IN + IF ~consensusStateExists THEN + \* if the client does have a consensus state with this + \* height, then set an error outcome + [ + connections |-> connections, + action |-> action, + outcome |-> "ICS03MissingClientConsensusState" + ] + ELSE + \* check if there was an open ack at the remote chain + LET openAckProofs == { + proof \in chain.connectionProofs : + /\ proof.type = "ICS03ConnectionOpenAck" + /\ proof.chainId = connection.counterpartyChainId + /\ proof.clientId = connection.counterpartyClientId + /\ proof.counterpartyChainId = connection.chainId + /\ proof.counterpartyClientId = connection.clientId + } IN + LET proofExists == Cardinality(openAckProofs) > 0 IN + IF ~proofExists THEN + \* if there wasn't an open ack at the remote chain, + \* then set an error outcome + [ + connections |-> chain.connections, + action |-> action, + outcome |-> "ICS03InvalidProof" + ] + ELSE + \* verification passed; update the connection state to + \* "Open" + LET updatedConnection == [connection EXCEPT + !.state = "Open" + ] IN + \* return result with updated state + [ + connections |-> ICS03_SetConnection( + connections, + connectionId, + updatedConnection + ), + action |-> action, + outcome |-> "ICS03ConnectionOpenConfirmOK" + ] + =============================================================================== diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index 8768df698b..ee3d04d9e2 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -29,6 +29,7 @@ "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", "ICS03UninitializedConnectionTest", + "ICS03ConnectionOpenAckConfirmTest", ] for test in tests: From 5a051af278dc57ca2ba968ac90cd1c054b22a508 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 12:07:20 +0100 Subject: [PATCH 084/104] Fix conn open ack --- modules/tests/support/model_based/ICS03.tla | 5 +++-- modules/tests/support/model_based/gen_tests.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index 97cde85db9..ccbbea0abe 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -309,6 +309,7 @@ ICS03_ConnectionOpenAck( /\ proof.clientId = connection.counterpartyClientId /\ proof.counterpartyChainId = connection.chainId /\ proof.counterpartyClientId = connection.clientId + /\ proof.counterpartyConnectionId = connectionId } IN LET proofExists == Cardinality(openTryProofs) > 0 IN IF ~proofExists THEN @@ -396,9 +397,9 @@ ICS03_ConnectionOpenConfirm( proof \in chain.connectionProofs : /\ proof.type = "ICS03ConnectionOpenAck" /\ proof.chainId = connection.counterpartyChainId - /\ proof.clientId = connection.counterpartyClientId + /\ proof.connectionId = connection.counterpartyConnectionId /\ proof.counterpartyChainId = connection.chainId - /\ proof.counterpartyClientId = connection.clientId + /\ proof.counterpartyConnectionId = connectionId } IN LET proofExists == Cardinality(openAckProofs) > 0 IN IF ~proofExists THEN diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index ee3d04d9e2..876742190c 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -38,5 +38,6 @@ file.write(CFG + "INVARIANT " + test + "Neg") # run tlc-json + print("> generating " + test) os.system("tlc-json IBCTests.tla") os.system("mv counterexample.json tests/" + test + ".json") From 122210bedb2f43469b183012f68e393cee902c1a Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 12:19:32 +0100 Subject: [PATCH 085/104] add conn open ack and conn open confirm failing tests --- modules/tests/executor/mod.rs | 22 + modules/tests/executor/step.rs | 17 + modules/tests/mbt.rs | 25 +- .../tests/support/model_based/gen_tests.py | 2 +- .../tests/ICS03ConnectionOpenAckOKTest.json | 341 ++++++++++++ .../ICS03ConnectionOpenConfirmOKTest.json | 502 ++++++++++++++++++ .../ICS03UninitializedConnectionTest.json | 73 ++- 7 files changed, 966 insertions(+), 16 deletions(-) create mode 100644 modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index fbbb5635cd..667412686d 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -10,6 +10,7 @@ use ibc::ics02_client::msgs::ClientMsg; use ibc::ics03_connection::connection::Counterparty; use ibc::ics03_connection::error::Kind as ICS03ErrorKind; use ibc::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; +use ibc::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; use ibc::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use ibc::ics03_connection::msgs::ConnectionMsg; @@ -321,6 +322,26 @@ impl IBCTestExecutor { ))); ctx.deliver(msg) } + Action::ICS03ConnectionOpenConfirm { + chain_id, + connection_id, + client_state, + counterparty_chain_id: _, + counterparty_connection_id: _, + } => { + // get chain's context + let ctx = self.chain_context_mut(chain_id); + + // create ICS26 message and deliver it + let msg = Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenConfirm( + MsgConnectionOpenConfirm { + connection_id: Self::connection_id(connection_id), + proofs: Self::proofs(client_state), + signer: Self::signer(), + }, + )); + ctx.deliver(msg) + } } } } @@ -386,6 +407,7 @@ impl modelator::TestExecutor for IBCTestExecutor { Self::extract_handler_error_kind::(result), ICS03ErrorKind::UninitializedConnection(_) ), + ActionOutcome::ICS03ConnectionOpenConfirmOK => result.is_ok(), }; // also check the state of chains outcome_matches && self.validate_chains() && self.check_chain_heights(step.chains) diff --git a/modules/tests/executor/step.rs b/modules/tests/executor/step.rs index 9842097bdb..7e0593025c 100644 --- a/modules/tests/executor/step.rs +++ b/modules/tests/executor/step.rs @@ -84,6 +84,22 @@ pub enum Action { #[serde(alias = "counterpartyChainId")] counterparty_chain_id: String, + #[serde(alias = "counterpartyConnectionId")] + counterparty_connection_id: u64, + }, + ICS03ConnectionOpenConfirm { + #[serde(alias = "chainId")] + chain_id: String, + + #[serde(alias = "connectionId")] + connection_id: u64, + + #[serde(alias = "clientState")] + client_state: u64, + + #[serde(alias = "counterpartyChainId")] + counterparty_chain_id: String, + #[serde(alias = "counterpartyConnectionId")] counterparty_connection_id: u64, }, @@ -121,6 +137,7 @@ pub enum ActionOutcome { ICS03InvalidProof, ICS03ConnectionOpenAckOK, ICS03UninitializedConnection, + ICS03ConnectionOpenConfirmOK, } #[derive(Debug, Clone, PartialEq, Deserialize)] diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 7494a75eee..0166899993 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,21 +5,22 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - "ICS02CreateOKTest", - "ICS02UpdateOKTest", - "ICS02ClientNotFoundTest", - "ICS02HeaderVerificationFailureTest", - "ICS03ConnectionOpenInitOKTest", - "ICS03MissingClientTest", - "ICS03ConnectionOpenTryOKTest", - "ICS03InvalidConsensusHeightTest", - "ICS03ConnectionNotFoundTest", - "ICS03ConnectionMismatchTest", - "ICS03MissingClientConsensusStateTest", + // "ICS02CreateOKTest", + // "ICS02UpdateOKTest", + // "ICS02ClientNotFoundTest", + // "ICS02HeaderVerificationFailureTest", + // "ICS03ConnectionOpenInitOKTest", + // "ICS03MissingClientTest", + // "ICS03ConnectionOpenTryOKTest", + // "ICS03InvalidConsensusHeightTest", + // "ICS03ConnectionNotFoundTest", + // "ICS03ConnectionMismatchTest", + // "ICS03MissingClientConsensusStateTest", // the following test should fail but doesn't because proofs are not yet verified // "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", - "ICS03UninitializedConnectionTest", + // "ICS03UninitializedConnectionTest", + "ICS03ConnectionOpenConfirmOKTest", ]; for test in tests { diff --git a/modules/tests/support/model_based/gen_tests.py b/modules/tests/support/model_based/gen_tests.py index 876742190c..7797fb24aa 100755 --- a/modules/tests/support/model_based/gen_tests.py +++ b/modules/tests/support/model_based/gen_tests.py @@ -29,7 +29,7 @@ "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", "ICS03UninitializedConnectionTest", - "ICS03ConnectionOpenAckConfirmTest", + "ICS03ConnectionOpenConfirmOKTest", ] for test in tests: diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json index 117807bae2..f330334ccd 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json @@ -4,6 +4,255 @@ "type": "None" }, "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionOpenTryOK", "chains": { "chainA": { "clientIdCounter": 1, @@ -29,8 +278,10 @@ ], "connections": { "0": { + "chainId": "chainA", "clientId": 0, "connectionId": 0, + "counterpartyChainId": "chainB", "counterpartyClientId": 0, "counterpartyConnectionId": -1, "state": "Init" @@ -59,8 +310,98 @@ ], "connections": { "0": { + "chainId": "chainB", "clientId": 0, "connectionId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "TryOpen" + } + }, + "height": 3 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + }, + "actionOutcome": "ICS03ConnectionOpenAckOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Open" + } + }, + "height": 4 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + { + "chainId": "chainA", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + } + ], + "connections": { + "0": { + "chainId": "chainB", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainA", "counterpartyClientId": 0, "counterpartyConnectionId": 0, "state": "TryOpen" diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json new file mode 100644 index 0000000000..0d012b79e7 --- /dev/null +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json @@ -0,0 +1,502 @@ +[ + { + "action": { + "type": "None" + }, + "actionOutcome": "None", + "chains": { + "chainA": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 3, + "consensusState": 3, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + "actionOutcome": "ICS03ConnectionOpenInitOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientState": 1, + "consensusState": 1, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + }, + "actionOutcome": "ICS03ConnectionOpenTryOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Init" + } + }, + "height": 3 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + } + ], + "connections": { + "0": { + "chainId": "chainB", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "TryOpen" + } + }, + "height": 3 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 3, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + }, + "actionOutcome": "ICS03ConnectionOpenAckOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Open" + } + }, + "height": 4 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + { + "chainId": "chainA", + "clientState": 3, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + } + ], + "connections": { + "0": { + "chainId": "chainB", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "TryOpen" + } + }, + "height": 3 + } + } + }, + { + "action": { + "chainId": "chainB", + "clientState": 1, + "connectionId": 0, + "counterpartyChainId": "chainA", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenConfirm" + }, + "actionOutcome": "ICS03ConnectionOpenConfirmOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainB", + "clientId": 0, + "clientState": 1, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "previousConnectionId": -1, + "type": "ICS03ConnectionOpenTry" + } + ], + "connections": { + "0": { + "chainId": "chainA", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "counterpartyConnectionId": -1, + "state": "Open" + } + }, + "height": 4 + }, + "chainB": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 1 + ] + } + }, + "connectionIdCounter": 1, + "connectionProofs": [ + { + "chainId": "chainA", + "clientId": 0, + "counterpartyChainId": "chainB", + "counterpartyClientId": 0, + "type": "ICS03ConnectionOpenInit" + }, + { + "chainId": "chainA", + "clientState": 3, + "connectionId": 0, + "counterpartyChainId": "chainB", + "counterpartyConnectionId": 0, + "type": "ICS03ConnectionOpenAck" + } + ], + "connections": { + "0": { + "chainId": "chainB", + "clientId": 0, + "connectionId": 0, + "counterpartyChainId": "chainA", + "counterpartyClientId": 0, + "counterpartyConnectionId": 0, + "state": "Open" + } + }, + "height": 3 + } + } + } +] \ No newline at end of file diff --git a/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json index 00320c78bb..666a89222f 100644 --- a/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json +++ b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json @@ -16,8 +16,10 @@ "connectionProofs": [], "connections": { "0": { + "chainId": "-1", "clientId": -1, "connectionId": -1, + "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, "state": "Uninit" @@ -36,8 +38,67 @@ "connectionProofs": [], "connections": { "0": { + "chainId": "-1", "clientId": -1, "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 1 + } + } + }, + { + "action": { + "chainId": "chainA", + "clientState": 3, + "consensusState": 3, + "type": "ICS02CreateClient" + }, + "actionOutcome": "ICS02CreateOK", + "chains": { + "chainA": { + "clientIdCounter": 1, + "clients": { + "0": { + "heights": [ + 3 + ] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", + "counterpartyClientId": -1, + "counterpartyConnectionId": -1, + "state": "Uninit" + } + }, + "height": 2 + }, + "chainB": { + "clientIdCounter": 0, + "clients": { + "0": { + "heights": [] + } + }, + "connectionIdCounter": 0, + "connectionProofs": [], + "connections": { + "0": { + "chainId": "-1", + "clientId": -1, + "connectionId": -1, + "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, "state": "Uninit" @@ -59,24 +120,28 @@ "actionOutcome": "ICS03UninitializedConnection", "chains": { "chainA": { - "clientIdCounter": 0, + "clientIdCounter": 1, "clients": { "0": { - "heights": [] + "heights": [ + 3 + ] } }, "connectionIdCounter": 0, "connectionProofs": [], "connections": { "0": { + "chainId": "-1", "clientId": -1, "connectionId": -1, + "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, "state": "Uninit" } }, - "height": 1 + "height": 2 }, "chainB": { "clientIdCounter": 0, @@ -89,8 +154,10 @@ "connectionProofs": [], "connections": { "0": { + "chainId": "-1", "clientId": -1, "connectionId": -1, + "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, "state": "Uninit" From ac70ba3355c7d30d50c83c54ef4173c18e6dba27 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 12:35:44 +0100 Subject: [PATCH 086/104] updated height on successful conn open confirm --- modules/tests/support/model_based/IBC.tla | 2 +- .../model_based/tests/ICS03ConnectionOpenConfirmOKTest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 0f28a4bee3..09b1dbba94 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -342,7 +342,7 @@ ConnectionOpenConfirm( ) IN \* update the chain LET updatedChain == [chain EXCEPT - !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenAckConfirm"), + !.height = UpdateChainHeight(@, result, "ICS03ConnectionOpenConfirmOK"), !.connections = result.connections ] IN \* no need to update the counterparty chain with a proof (as in the other diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json index 0d012b79e7..72160bd322 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json @@ -495,7 +495,7 @@ "state": "Open" } }, - "height": 3 + "height": 4 } } } From 1d63ca95f9866b406cef5c90663f0ac2cd197aef Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 14:26:41 +0100 Subject: [PATCH 087/104] Allow a conn open ack to succeed --- CHANGELOG.md | 4 +- modules/src/ics02_client/client_def.rs | 4 +- modules/src/ics03_connection/context.rs | 5 +-- modules/src/ics03_connection/error.rs | 2 +- .../ics03_connection/handler/conn_open_ack.rs | 41 +++++++++++++------ .../ics03_connection/handler/conn_open_try.rs | 7 ++-- .../src/ics03_connection/handler/verify.rs | 9 ++-- modules/src/ics07_tendermint/client_def.rs | 2 +- modules/src/mock/client_def.rs | 2 +- modules/src/mock/context.rs | 10 ++--- 10 files changed, 49 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b2a8d154..009b80208e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Consistent identifier handling across ICS 02, 03 and 04 ([#622]) - [ibc-relayer] + - [nothing yet] - [ibc-relayer-cli] - [nothing yet] @@ -28,7 +29,7 @@ ### BUG FIXES - [ibc] - - [nothing yet] + - Fix overflow bug in ICS03 client consensus height verification method ([#685]) - [ibc-relayer] - [nothing yet] @@ -47,6 +48,7 @@ - [ibc-relayer-cli] - [nothing yet] +[#685]: https://github.com/informalsystems/ibc-rs/issues/685 [#689]: https://github.com/informalsystems/ibc-rs/issues/689 ## v0.1.1 diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index d2a64f944c..d4b613daa1 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -73,7 +73,7 @@ pub trait ClientDef: Clone { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, - connection_id: &ConnectionId, + connection_id: Option<&ConnectionId>, expected_connection_end: &ConnectionEnd, ) -> Result<(), Box>; @@ -472,7 +472,7 @@ impl ClientDef for AnyClient { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, - connection_id: &ConnectionId, + connection_id: Option<&ConnectionId>, expected_connection_end: &ConnectionEnd, ) -> Result<(), Box> { match self { diff --git a/modules/src/ics03_connection/context.rs b/modules/src/ics03_connection/context.rs index 37ba52c62b..ba35c6ab5b 100644 --- a/modules/src/ics03_connection/context.rs +++ b/modules/src/ics03_connection/context.rs @@ -22,9 +22,8 @@ pub trait ConnectionReader { /// Returns the current height of the local chain. fn host_current_height(&self) -> Height; - /// Returns the number of consensus state entries that the local chain maintains. The history - /// size determines the pruning window of the host chain. - fn host_chain_history_size(&self) -> usize; + /// Returns the oldest height available on the local chain. + fn host_oldest_height(&self) -> Height; /// Returns the prefix that the local chain uses in the KV store. fn commitment_prefix(&self) -> CommitmentPrefix; diff --git a/modules/src/ics03_connection/error.rs b/modules/src/ics03_connection/error.rs index af1a64ad5e..b9c4e7e773 100644 --- a/modules/src/ics03_connection/error.rs +++ b/modules/src/ics03_connection/error.rs @@ -23,7 +23,7 @@ pub enum Kind { #[error("consensus height claimed by the client on the other party is too advanced: {0} (host chain current height: {1})")] InvalidConsensusHeight(Height, Height), - #[error("consensus height claimed by the client on the other party falls outside of trusting period: {0} (host chain current height: {1})")] + #[error("consensus height claimed by the client on the other party has been pruned: {0} (host chain oldest height: {1})")] StaleConsensusHeight(Height, Height), #[error("identifier error")] diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index 218c4f78b4..0834e23d08 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -30,10 +30,19 @@ pub(crate) fn process( || old_conn_end.state_matches(&State::TryOpen) && old_conn_end.versions().get(0).eq(&Some(msg.version())); - // Check that if the msg's counterparty connection id is not empty then it matches - // the old connection's counterparty. - let counterparty_matches = msg.counterparty_connection_id().is_none() - || old_conn_end.counterparty().connection_id() == msg.counterparty_connection_id(); + // Check that if we have a counterparty connection id, then it + // matches the one in the message + let counterparty_matches = if let Some(counterparty_connection_id) = + old_conn_end.counterparty().connection_id() + { + // it's okay to unwrap as `msg.counterparty_connection_id` + // should always be set + // TODO: `msg.counterparty_connection_id` should simply be a + // `ConnectionId`, not an `Option` + msg.counterparty_connection_id.as_ref().unwrap() == counterparty_connection_id + } else { + true + }; if state_is_consistent && counterparty_matches { Ok(old_conn_end) @@ -111,7 +120,6 @@ mod tests { use crate::ics24_host::identifier::{ChainId, ClientId}; use crate::mock::context::MockContext; use crate::mock::host::HostType; - use crate::Height; #[test] fn conn_open_ack_msg_processing() { @@ -133,11 +141,13 @@ mod tests { // Parametrize the host chain to have a height at least as recent as the // the height of the proofs in the Ack msg. + let latest_height = proof_height.increment(); + let max_history_size = 5; let default_context = MockContext::new( - ChainId::new("mockgaia".to_string(), 1), + ChainId::new("mockgaia".to_string(), latest_height.revision_number), HostType::Mock, - 5, - Height::new(1, msg_ack.proofs().height().increment().revision_height), + max_history_size, + latest_height, ); // A connection end that will exercise the successful path. @@ -183,14 +193,14 @@ mod tests { ctx: default_context .clone() .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), default_conn_end.clone()), + .with_connection(conn_id.clone(), default_conn_end), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: true, error_kind: None, }, Test { name: "Processing fails because the connection does not exist in the context".to_string(), - ctx: MockContext::default(), // Empty context + ctx: default_context.clone(), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: false, error_kind: Some(Kind::UninitializedConnection(conn_id.clone())), @@ -220,10 +230,11 @@ mod tests { ctx: default_context .with_client(&client_id, proof_height) .with_connection(conn_id.clone(), conn_end_cparty), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), + msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), want_pass: false, - error_kind: Some(Kind::ConnectionMismatch(conn_id.clone())) + error_kind: Some(Kind::ConnectionMismatch(conn_id)) }, + /* Test { name: "Processing fails due to MissingLocalConsensusState".to_string(), ctx: MockContext::default() @@ -233,6 +244,7 @@ mod tests { want_pass: false, error_kind: Some(Kind::MissingLocalConsensusState) }, + */ ]; for test in tests { @@ -273,7 +285,10 @@ mod tests { assert_eq!( &expected_kind, e.kind(), - "conn_open_ack: expected error kind mismatches thrown error kind" + "conn_open_ack: failed for test: {}\nexpected error kind: {:?}\nfound: {:?}", + test.name, + expected_kind, + e.kind() ) } } diff --git a/modules/src/ics03_connection/handler/conn_open_try.rs b/modules/src/ics03_connection/handler/conn_open_try.rs index 720e635d04..75bcadaec7 100644 --- a/modules/src/ics03_connection/handler/conn_open_try.rs +++ b/modules/src/ics03_connection/handler/conn_open_try.rs @@ -125,7 +125,6 @@ mod tests { use crate::events::IbcEvent; use crate::ics03_connection::connection::State; - use crate::ics03_connection::context::ConnectionReader; use crate::ics03_connection::handler::{dispatch, ConnectionResult}; use crate::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; @@ -145,13 +144,13 @@ mod tests { } let host_chain_height = Height::new(0, 35); + let max_history_size = 5; let context = MockContext::new( ChainId::new("mockgaia".to_string(), 0), HostType::Mock, - 5, + max_history_size, host_chain_height, ); - let pruning_window = context.host_chain_history_size() as u64; let client_consensus_state_height = 10; let msg_conn_try = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( @@ -167,7 +166,7 @@ mod tests { )) .unwrap(); let pruned_height = host_chain_height - .sub(pruning_window + 1) + .sub(max_history_size as u64 + 1) .unwrap() .revision_height; // The consensus proof targets a missing height (pruned) on destination chain. diff --git a/modules/src/ics03_connection/handler/verify.rs b/modules/src/ics03_connection/handler/verify.rs index c26c52679a..7b9c76a7fd 100644 --- a/modules/src/ics03_connection/handler/verify.rs +++ b/modules/src/ics03_connection/handler/verify.rs @@ -96,7 +96,7 @@ pub fn verify_connection_proof( proof_height, connection_end.counterparty().prefix(), proof, - &connection_end.counterparty().connection_id().unwrap(), + connection_end.counterparty().connection_id(), expected_conn, ) .map_err(|_| Kind::InvalidProof)?) @@ -197,12 +197,9 @@ pub fn check_client_consensus_height( return Err(Kind::InvalidConsensusHeight(claimed_height, ctx.host_current_height()).into()); } - let oldest_available_height = - ctx.host_current_height().revision_height - ctx.host_chain_history_size() as u64; - - if claimed_height.revision_height < oldest_available_height { + if claimed_height < ctx.host_oldest_height() { // Fail if the consensus height is too old (has been pruned). - return Err(Kind::StaleConsensusHeight(claimed_height, ctx.host_current_height()).into()); + return Err(Kind::StaleConsensusHeight(claimed_height, ctx.host_oldest_height()).into()); } // Height check is within normal bounds, check passes. diff --git a/modules/src/ics07_tendermint/client_def.rs b/modules/src/ics07_tendermint/client_def.rs index b11eba1405..fedccc7fe0 100644 --- a/modules/src/ics07_tendermint/client_def.rs +++ b/modules/src/ics07_tendermint/client_def.rs @@ -57,7 +57,7 @@ impl ClientDef for TendermintClient { _height: Height, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, - _connection_id: &ConnectionId, + _connection_id: Option<&ConnectionId>, _expected_connection_end: &ConnectionEnd, ) -> Result<(), Box> { todo!() diff --git a/modules/src/mock/client_def.rs b/modules/src/mock/client_def.rs index e7e13b6b33..ec31ff9caa 100644 --- a/modules/src/mock/client_def.rs +++ b/modules/src/mock/client_def.rs @@ -64,7 +64,7 @@ impl ClientDef for MockClient { _height: Height, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, - _connection_id: &ConnectionId, + _connection_id: Option<&ConnectionId>, _expected_connection_end: &ConnectionEnd, ) -> Result<(), Box> { Ok(()) diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index 33c5a0de22..b685e31d71 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -102,10 +102,10 @@ pub struct MockContext { impl Default for MockContext { fn default() -> Self { Self::new( - ChainId::new("mockgaia".to_string(), 1), + ChainId::new("mockgaia".to_string(), 0), HostType::Mock, 5, - Height::new(1, 5), + Height::new(0, 5), ) } } @@ -450,9 +450,9 @@ impl ConnectionReader for MockContext { self.latest_height } - /// Returns the number of consensus state historical entries for the local chain. - fn host_chain_history_size(&self) -> usize { - self.max_history_size + fn host_oldest_height(&self) -> Height { + // history must be non-empty, so `self.history[0]` is valid + self.history[0].height() } fn commitment_prefix(&self) -> CommitmentPrefix { From b889b7bf5980ddb822f732eb61b2b908a6027c5d Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 14:31:53 +0100 Subject: [PATCH 088/104] Remove invalid test --- .../ics03_connection/handler/conn_open_ack.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index 0834e23d08..a65e63cdc0 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -177,16 +177,6 @@ mod tests { CommitmentPrefix::from(vec![]), // incorrect field )); - // A connection end with correct state & prefix, but incorrect counterparty; exercises - // unsuccessful processing path. - let mut conn_end_cparty = conn_end_open.clone(); - conn_end_cparty.set_state(State::Init); - conn_end_cparty.set_counterparty(Counterparty::new( - client_id.clone(), - None, // incorrect field - CommitmentPrefix::from(b"ibc".to_vec()), - )); - let tests: Vec = vec![ Test { name: "Successful processing of an Ack message".to_string(), @@ -225,15 +215,6 @@ mod tests { want_pass: false, error_kind: Some(Kind::ConsensusStateVerificationFailure(proof_height)) }, - Test { - name: "Processing fails due to mismatching counterparty conn id".to_string(), - ctx: default_context - .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), conn_end_cparty), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), - want_pass: false, - error_kind: Some(Kind::ConnectionMismatch(conn_id)) - }, /* Test { name: "Processing fails due to MissingLocalConsensusState".to_string(), From 52a33907a4a8990f7bdd7656a4c88384dd9b0698 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 14:33:41 +0100 Subject: [PATCH 089/104] enable all tests --- modules/tests/mbt.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 0166899993..53e10bdd5e 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -5,21 +5,21 @@ const TESTS_DIR: &str = "tests/support/model_based/tests"; #[test] fn mbt() { let tests = vec![ - // "ICS02CreateOKTest", - // "ICS02UpdateOKTest", - // "ICS02ClientNotFoundTest", - // "ICS02HeaderVerificationFailureTest", - // "ICS03ConnectionOpenInitOKTest", - // "ICS03MissingClientTest", - // "ICS03ConnectionOpenTryOKTest", - // "ICS03InvalidConsensusHeightTest", - // "ICS03ConnectionNotFoundTest", - // "ICS03ConnectionMismatchTest", - // "ICS03MissingClientConsensusStateTest", + "ICS02CreateOKTest", + "ICS02UpdateOKTest", + "ICS02ClientNotFoundTest", + "ICS02HeaderVerificationFailureTest", + "ICS03ConnectionOpenInitOKTest", + "ICS03MissingClientTest", + "ICS03ConnectionOpenTryOKTest", + "ICS03InvalidConsensusHeightTest", + "ICS03ConnectionNotFoundTest", + "ICS03ConnectionMismatchTest", + "ICS03MissingClientConsensusStateTest", // the following test should fail but doesn't because proofs are not yet verified // "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", - // "ICS03UninitializedConnectionTest", + "ICS03UninitializedConnectionTest", "ICS03ConnectionOpenConfirmOKTest", ]; From a173dcd87d7ef06ac5433f0c9edbbd6c2e135805 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 14:57:38 +0100 Subject: [PATCH 090/104] update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 009b80208e..60ea2a6bdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [ibc] - Fix overflow bug in ICS03 client consensus height verification method ([#685]) + - Allow a conn open ack to succeed in the happy case ([#699]) - [ibc-relayer] - [nothing yet] @@ -49,7 +50,7 @@ - [nothing yet] [#685]: https://github.com/informalsystems/ibc-rs/issues/685 -[#689]: https://github.com/informalsystems/ibc-rs/issues/689 +[#699]: https://github.com/informalsystems/ibc-rs/issues/699 ## v0.1.1 *February 17, 2021* From d25cc7b248aeb7d2a9407614f7abd351add0a851 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 14:58:47 +0100 Subject: [PATCH 091/104] fix CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ea2a6bdb..22822d149a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ - [nothing yet] [#685]: https://github.com/informalsystems/ibc-rs/issues/685 +[#689]: https://github.com/informalsystems/ibc-rs/issues/689 [#699]: https://github.com/informalsystems/ibc-rs/issues/699 ## v0.1.1 From 067fc0c8ca84148fce3bfb7fd1fb784fbec5a455 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 15:02:45 +0100 Subject: [PATCH 092/104] fix CHANGELOG --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8265f46ca6..d4605f5302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,11 @@ - [ibc-relayer] - [nothing yet] -### BUG FIXES -- [ibc] - - Fix overflow bug in ICS03 client consensus height verification method ([#685]) +### IMPROVEMENTS + + - [ibc] + - Follow Rust guidelines naming conventions ([#689]) - [ibc-relayer] - [nothing yet] From 809effbe0fc95cd8d19712ecea92dacfb56a14fa Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 15:11:44 +0100 Subject: [PATCH 093/104] Minimize diff --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4605f5302..d17d7c5c72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,8 @@ ### IMPROVEMENTS - - [ibc] - - Follow Rust guidelines naming conventions ([#689]) +- [ibc] + - Follow Rust guidelines naming conventions ([#689]) - [ibc-relayer] - [nothing yet] From a3e95d31f2fbc2abea5268a80eef4455da245580 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 15:13:12 +0100 Subject: [PATCH 094/104] Minimize diff --- CHANGELOG.md | 2 ++ modules/src/ics02_client/handler/update_client.rs | 5 ----- modules/src/ics24_host/identifier.rs | 1 - modules/tests/mbt.rs | 7 ++++--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d17d7c5c72..22822d149a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - [ibc-relayer] - [nothing yet] +- [ibc-relayer-cli] + - [nothing yet] ### IMPROVEMENTS diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index 011023b37b..625d400c59 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -32,8 +32,6 @@ pub fn process( } = msg; // Read client type from the host chain store. The client should already exist. - // TODO: this first get is not needed; - // the client type can be retrieved using the client_state below let client_type = ctx .client_type(&client_id) .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; @@ -46,15 +44,12 @@ pub fn process( .ok_or_else(|| Kind::ClientNotFound(client_id.clone()))?; let latest_height = client_state.latest_height(); - // TODO: how can the following error happen? - // it feels like it should be a panic, not an error ctx.consensus_state(&client_id, latest_height) .ok_or_else(|| Kind::ConsensusStateNotFound(client_id.clone(), latest_height))?; // Use client_state to validate the new header against the latest consensus_state. // This function will return the new client_state (its latest_height changed) and a // consensus_state obtained from header. These will be later persisted by the keeper. - // TODO: update_state is confusing as it actually doesn't update the state let (new_client_state, new_consensus_state) = client_def .check_header_and_update_state(client_state, header) .map_err(|e| Kind::HeaderVerificationFailure.context(e.to_string()))?; diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index 76d0194a6f..36466f363b 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -130,7 +130,6 @@ impl ClientId { /// assert!(tm_client_id.is_ok()); /// tm_client_id.map(|id| { assert_eq!(&id, "07-tendermint-0") }); /// ``` - /// TODO: unwrap inside as the others pub fn new(ctype: ClientType, counter: u64) -> Result { let prefix = Self::prefix(ctype); let id = format!("{}-{}", prefix, counter); diff --git a/modules/tests/mbt.rs b/modules/tests/mbt.rs index 53e10bdd5e..a97f0ff736 100644 --- a/modules/tests/mbt.rs +++ b/modules/tests/mbt.rs @@ -16,7 +16,8 @@ fn mbt() { "ICS03ConnectionNotFoundTest", "ICS03ConnectionMismatchTest", "ICS03MissingClientConsensusStateTest", - // the following test should fail but doesn't because proofs are not yet verified + // TODO: the following test should fail but doesn't because proofs are + // not yet verified // "ICS03InvalidProofTest", "ICS03ConnectionOpenAckOKTest", "ICS03UninitializedConnectionTest", @@ -27,8 +28,8 @@ fn mbt() { let test = format!("{}/{}.json", TESTS_DIR, test); println!("> running {}", test); let executor = executor::IBCTestExecutor::new(); - // we should be able to just return the `Result` once the following issue - // is fixed: https://github.com/rust-lang/rust/issues/43301 + // we should be able to just return the `Result` once the following + // issue is fixed: https://github.com/rust-lang/rust/issues/43301 if let Err(e) = executor::modelator::test(&test, executor) { panic!("{}", e); } From bf7c81d80858f266b1d0f9d9df2ea64f3cdb416f Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 15:25:36 +0100 Subject: [PATCH 095/104] Update README --- modules/tests/README.md | 30 +++++++++++++----------------- modules/tests/executor/mod.rs | 1 - 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index 670f5b521e..e6eea5566b 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -6,8 +6,9 @@ This directory contains the model-based tests for the IBC modules. They are "mod To instantiate the model, we define in [IBC.cfg](support/model_based/IBC.cfg) the following model constants: - `ChainIds = {"chain-A", "chain-B"}`, indicating that two chains, `chain-A` and `chain-B`, will be created + - `MaxChainHeight = 4`, indicating that each chain will reach at most height 4 - `MaxClientsPerChain = 1`, indicating that at most 1 client per chain will be created - - `MaxClientHeight = 2`, indicating that clients will reach at most height 2 + - `MaxConnectionsPerChain = 1`, indicating that at most 1 connection per chain will be created The [IBC.cfg](support/model_based/IBC.cfg) file also defines two simple invariants: ```tla @@ -16,13 +17,13 @@ INVARIANTS ModelNeverErrors ``` -Then, we can ask [`Apalache`](https://apalache.informal.systems), a model checker for `TLA+`, to check that these invariants hold: +Then, we can ask [`TLC`](https://github.com/tlaplus/tlaplus), a model checker for `TLA+`, to check that these invariants hold: + ```bash -apalache-mc check --inv=ICS02UpdateOKTestNeg IBC.tla +wget https://github.com/tlaplus/tlaplus/releases/download/v1.8.0/tla2tools.jar +java -cp tla2tools.jar tlc2.TLC IBC.tla -tool -modelcheck -config IBC.cfg -workers auto ``` -The above command automatically reads what we have defined in [IBC.cfg](support/model_based/IBC.cfg). - ### The tests Tests are `TLA+` assertions that describe the desired shape of the test (see [IBCTests.tla](support/model_based/IBCTests.tla)). One of the assertions in [IBCTests.tla](support/model_based/IBCTests.tla) is the following: @@ -39,20 +40,15 @@ To generate a test from the `ICS02UpdateOKTest` assertion, we first define an in ICS02UpdateOKTestNeg == ~ICS02UpdateOKTest ``` -Then, we ask `Apalache`, to prove it: - -```bash -apalache-mc check --inv=ICS02UpdateOKTestNeg IBCTests.tla -``` - -(Again, the above command automatically reads what we have defined in [IBCTests.cfg](support/model_based/IBCTests.cfg).) +Then, we ask `TLC`, to prove it. Because the invariant is wrong, `TLC` will find a counterexample showing that it is indeed possible that a client is sucessfully updated to a new height. This counterexample is our test. -Because the invariant is wrong, `Apalache` will find a counterexample showing that it is indeed possible that a client is sucessfully updated to a new height. This counterexample is our test. +The [`gen_tests.py`](support/model_based/gen_tests.py) script can be used to generate the tests. This script assumes the existence of [`tlc-json`](https://github.com/vitorenesduarte/tlc-json), which can be installed with the following commands: -### Current limitations - -The counterexamples currently produced by `Apalache` are not easy to parse and have traditionally required tools like [`jsonatr`](https://github.com/informalsystems/jsonatr). Fortunately, [that will change soon](https://github.com/informalsystems/apalache/issues/530), and `Apalache` will be able to produce counterexamples like those in [support/model_based/tests/](support/model_based/tests/). -These are currently generated manually, but can be easily mapped to Rust (see [step.rs](step.rs)). +```bash +git clone https://github.com/vitorenesduarte/tlc-json +cd tlc-json/ +cargo install --path . +`` ### Running the model-based tests diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 667412686d..892995ea5b 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -363,7 +363,6 @@ impl modelator::TestExecutor for IBCTestExecutor { fn next_step(&mut self, step: Step) -> bool { let result = self.apply(step.action); - println!("{:?}", result); let outcome_matches = match step.action_outcome { ActionOutcome::None => panic!("unexpected action outcome"), ActionOutcome::ICS02CreateOK => result.is_ok(), From 731dcc92077bdedb1daf15c36de9b516076eaaa2 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 15:39:34 +0100 Subject: [PATCH 096/104] Fix clippy --- modules/src/ics03_connection/handler/conn_open_ack.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index a65e63cdc0..fdc2a2bda2 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -208,10 +208,9 @@ mod tests { Test { name: "Processing fails: ConsensusStateVerificationFailure due to empty counterparty prefix".to_string(), ctx: default_context - .clone() .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), conn_end_prefix), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), + .with_connection(conn_id, conn_end_prefix), + msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), want_pass: false, error_kind: Some(Kind::ConsensusStateVerificationFailure(proof_height)) }, From ce23256e93ad09f4cc05790c50bb297ff983ae82 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 16:19:17 +0100 Subject: [PATCH 097/104] update README --- modules/tests/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/tests/README.md b/modules/tests/README.md index e6eea5566b..72deb91c32 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -5,6 +5,7 @@ This directory contains the model-based tests for the IBC modules. They are "model-based" because they are generated from a `TLA+` model of the IBC modules (see [IBC.tla](support/model_based/IBC.tla)). To instantiate the model, we define in [IBC.cfg](support/model_based/IBC.cfg) the following model constants: + - `ChainIds = {"chain-A", "chain-B"}`, indicating that two chains, `chain-A` and `chain-B`, will be created - `MaxChainHeight = 4`, indicating that each chain will reach at most height 4 - `MaxClientsPerChain = 1`, indicating that at most 1 client per chain will be created From 6c7ee61f2dd3585397c5beadd8de3403993e9dab Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 16:19:39 +0100 Subject: [PATCH 098/104] update README --- modules/tests/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index 72deb91c32..a2bc57879b 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -6,10 +6,10 @@ This directory contains the model-based tests for the IBC modules. They are "mod To instantiate the model, we define in [IBC.cfg](support/model_based/IBC.cfg) the following model constants: - - `ChainIds = {"chain-A", "chain-B"}`, indicating that two chains, `chain-A` and `chain-B`, will be created - - `MaxChainHeight = 4`, indicating that each chain will reach at most height 4 - - `MaxClientsPerChain = 1`, indicating that at most 1 client per chain will be created - - `MaxConnectionsPerChain = 1`, indicating that at most 1 connection per chain will be created +- `ChainIds = {"chain-A", "chain-B"}`, indicating that two chains, `chain-A` and `chain-B`, will be created +- `MaxChainHeight = 4`, indicating that each chain will reach at most height 4 +- `MaxClientsPerChain = 1`, indicating that at most 1 client per chain will be created +- `MaxConnectionsPerChain = 1`, indicating that at most 1 connection per chain will be created The [IBC.cfg](support/model_based/IBC.cfg) file also defines two simple invariants: ```tla From 53e2a08b0e0d6f1ef6d8677cc32896bdcb22f0ac Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 17:54:45 +0100 Subject: [PATCH 099/104] Make MsgConnectionOpenAck.counterparty_connection_id not an Option --- .../ics03_connection/handler/conn_open_ack.rs | 18 ++++++--------- .../ics03_connection/msgs/conn_open_ack.rs | 22 +++++++------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/ics03_connection/handler/conn_open_ack.rs index fdc2a2bda2..e4552a7962 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/ics03_connection/handler/conn_open_ack.rs @@ -30,16 +30,12 @@ pub(crate) fn process( || old_conn_end.state_matches(&State::TryOpen) && old_conn_end.versions().get(0).eq(&Some(msg.version())); - // Check that if we have a counterparty connection id, then it - // matches the one in the message + // Check that, if we have a counterparty connection id, then it + // matches the one in the message. let counterparty_matches = if let Some(counterparty_connection_id) = old_conn_end.counterparty().connection_id() { - // it's okay to unwrap as `msg.counterparty_connection_id` - // should always be set - // TODO: `msg.counterparty_connection_id` should simply be a - // `ConnectionId`, not an `Option` - msg.counterparty_connection_id.as_ref().unwrap() == counterparty_connection_id + &msg.counterparty_connection_id == counterparty_connection_id } else { true }; @@ -68,8 +64,8 @@ pub(crate) fn process( Counterparty::new( // The counterparty is the local chain. new_conn_end.client_id().clone(), // The local client identifier. - msg.counterparty_connection_id().cloned(), // This chain's connection id as known on counterparty. - ctx.commitment_prefix(), // Local commitment prefix. + Some(msg.counterparty_connection_id().clone()), // This chain's connection id as known on counterparty. + ctx.commitment_prefix(), // Local commitment prefix. ), vec![msg.version().clone()], new_conn_end.delay_period, @@ -156,7 +152,7 @@ mod tests { client_id.clone(), Counterparty::new( client_id.clone(), - msg_ack.counterparty_connection_id().cloned(), + Some(msg_ack.counterparty_connection_id().clone()), CommitmentPrefix::from(b"ibc".to_vec()), ), vec![msg_ack.version().clone()], @@ -173,7 +169,7 @@ mod tests { conn_end_prefix.set_state(State::Init); conn_end_prefix.set_counterparty(Counterparty::new( client_id.clone(), - msg_ack.counterparty_connection_id().cloned(), + Some(msg_ack.counterparty_connection_id().clone()), CommitmentPrefix::from(vec![]), // incorrect field )); diff --git a/modules/src/ics03_connection/msgs/conn_open_ack.rs b/modules/src/ics03_connection/msgs/conn_open_ack.rs index 1f0d57ac6d..670ed8dbe5 100644 --- a/modules/src/ics03_connection/msgs/conn_open_ack.rs +++ b/modules/src/ics03_connection/msgs/conn_open_ack.rs @@ -1,5 +1,4 @@ use std::convert::{TryFrom, TryInto}; -use std::str::FromStr; use tendermint::account::Id as AccountId; use tendermint_proto::Protobuf; @@ -22,7 +21,7 @@ pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck"; #[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgConnectionOpenAck { pub connection_id: ConnectionId, - pub counterparty_connection_id: Option, + pub counterparty_connection_id: ConnectionId, pub client_state: Option, pub proofs: Proofs, pub version: Version, @@ -36,8 +35,8 @@ impl MsgConnectionOpenAck { } /// Getter for accessing the counterparty's connection identifier from this message. - pub fn counterparty_connection_id(&self) -> Option<&ConnectionId> { - self.counterparty_connection_id.as_ref() + pub fn counterparty_connection_id(&self) -> &ConnectionId { + &self.counterparty_connection_id } /// Getter for accessing the client state. @@ -107,18 +106,15 @@ impl TryFrom for MsgConnectionOpenAck { .filter(|x| !x.is_empty()) .map(CommitmentProofBytes::from); - let counterparty_connection_id = Some(msg.counterparty_connection_id) - .filter(|x| !x.is_empty()) - .map(|v| FromStr::from_str(v.as_str())) - .transpose() - .map_err(|e| Kind::IdentifierError.context(e))?; - Ok(Self { connection_id: msg .connection_id .parse() .map_err(|e| Kind::IdentifierError.context(e))?, - counterparty_connection_id, + counterparty_connection_id: msg + .counterparty_connection_id + .parse() + .map_err(|e| Kind::IdentifierError.context(e))?, client_state: msg .client_state .map(AnyClientState::try_from) @@ -146,9 +142,7 @@ impl From for RawMsgConnectionOpenAck { fn from(ics_msg: MsgConnectionOpenAck) -> Self { RawMsgConnectionOpenAck { connection_id: ics_msg.connection_id.as_str().to_string(), - counterparty_connection_id: ics_msg - .counterparty_connection_id - .map_or_else(|| "".to_string(), |v| v.as_str().to_string()), + counterparty_connection_id: ics_msg.counterparty_connection_id.as_str().to_string(), client_state: ics_msg .client_state .map_or_else(|| None, |v| Some(v.into())), From dda8c6f943612d018b2d8b12563b7f204dd29705 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 18:02:25 +0100 Subject: [PATCH 100/104] Make MsgConnectionOpenAck.counterparty_connection_id not an Option --- relayer/src/connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/connection.rs b/relayer/src/connection.rs index 2b23a3e9a6..7e56bc8abc 100644 --- a/relayer/src/connection.rs +++ b/relayer/src/connection.rs @@ -566,7 +566,7 @@ impl Connection { let new_msg = MsgConnectionOpenAck { connection_id: self.dst_connection_id().clone(), - counterparty_connection_id: Option::from(self.src_connection_id().clone()), + counterparty_connection_id: self.src_connection_id().clone(), client_state, proofs, version: src_connection.versions()[0].clone(), From a8dbfe177e1534ef1ba09f657ec8eaea8df486de Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 18:03:33 +0100 Subject: [PATCH 101/104] Fix test executor --- modules/tests/executor/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/tests/executor/mod.rs b/modules/tests/executor/mod.rs index 892995ea5b..3f37619e98 100644 --- a/modules/tests/executor/mod.rs +++ b/modules/tests/executor/mod.rs @@ -309,10 +309,7 @@ impl IBCTestExecutor { let msg = Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenAck(Box::new( MsgConnectionOpenAck { connection_id: Self::connection_id(connection_id), - // TODO: the following should not be an option - counterparty_connection_id: Some(Self::connection_id( - counterparty_connection_id, - )), + counterparty_connection_id: Self::connection_id(counterparty_connection_id), // TODO: is this ever needed? client_state: None, proofs: Self::proofs(client_state), From 0c5e9e4179840a3e98b4dd92ff3992359d6fa338 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 17:13:05 +0000 Subject: [PATCH 102/104] Update README.md --- modules/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/tests/README.md b/modules/tests/README.md index a2bc57879b..b93b80db03 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -49,7 +49,7 @@ The [`gen_tests.py`](support/model_based/gen_tests.py) script can be used to gen git clone https://github.com/vitorenesduarte/tlc-json cd tlc-json/ cargo install --path . -`` +``` ### Running the model-based tests From eabf89d3e9746f5cc761e0638324f3dadc215457 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Mon, 22 Feb 2021 17:13:41 +0000 Subject: [PATCH 103/104] Update README.md --- modules/tests/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/tests/README.md b/modules/tests/README.md index b93b80db03..d6839c3c60 100644 --- a/modules/tests/README.md +++ b/modules/tests/README.md @@ -56,5 +56,6 @@ cargo install --path . The model-based tests can be run with the following command: ```bash +cd modules/ cargo test --features mocks -- mbt ``` From 6b66f7e45adcc67d26e0395600553c63d2e0caa5 Mon Sep 17 00:00:00 2001 From: Vitor Enes Date: Tue, 23 Feb 2021 15:55:43 +0100 Subject: [PATCH 104/104] Uninit -> Uninitialized --- modules/tests/support/model_based/IBC.tla | 4 ++-- modules/tests/support/model_based/ICS03.tla | 2 +- .../model_based/tests/ICS02ClientNotFoundTest.json | 8 ++++---- .../support/model_based/tests/ICS02CreateOKTest.json | 8 ++++---- .../tests/ICS02HeaderVerificationFailureTest.json | 12 ++++++------ .../support/model_based/tests/ICS02UpdateOKTest.json | 12 ++++++------ .../tests/ICS03ConnectionMismatchTest.json | 12 ++++++------ .../tests/ICS03ConnectionNotFoundTest.json | 12 ++++++------ .../tests/ICS03ConnectionOpenAckOKTest.json | 12 ++++++------ .../tests/ICS03ConnectionOpenConfirmOKTest.json | 12 ++++++------ .../tests/ICS03ConnectionOpenInitOKTest.json | 10 +++++----- .../tests/ICS03ConnectionOpenTryOKTest.json | 12 ++++++------ .../tests/ICS03InvalidConsensusHeightTest.json | 8 ++++---- .../model_based/tests/ICS03InvalidProofTest.json | 12 ++++++------ .../tests/ICS03MissingClientConsensusStateTest.json | 12 ++++++------ .../model_based/tests/ICS03MissingClientTest.json | 8 ++++---- .../tests/ICS03UninitializedConnectionTest.json | 12 ++++++------ 17 files changed, 84 insertions(+), 84 deletions(-) diff --git a/modules/tests/support/model_based/IBC.tla b/modules/tests/support/model_based/IBC.tla index 09b1dbba94..8376f0b89d 100644 --- a/modules/tests/support/model_based/IBC.tla +++ b/modules/tests/support/model_based/IBC.tla @@ -30,7 +30,7 @@ ClientIds == 0..(MaxClientsPerChain - 1) ConnectionIds == 0..(MaxConnectionsPerChain- 1) \* set of possible connection states ConnectionStates == { - "Uninit", + "Uninitialized", "Init", "TryOpen", "Open" @@ -469,7 +469,7 @@ Init == heights |-> AsSetInt({}) ] IN LET connectionNone == [ - state |-> "Uninit", + state |-> "Uninitialized", chainId |-> ChainIdNone, clientId |-> ClientIdNone, connectionId |-> ConnectionIdNone, diff --git a/modules/tests/support/model_based/ICS03.tla b/modules/tests/support/model_based/ICS03.tla index ccbbea0abe..f89d9341ed 100644 --- a/modules/tests/support/model_based/ICS03.tla +++ b/modules/tests/support/model_based/ICS03.tla @@ -8,7 +8,7 @@ ICS03_GetConnection(connections, connectionId) == \* check if `connectionId` exists ICS03_ConnectionExists(connections, connectionId) == - ICS03_GetConnection(connections, connectionId).state /= "Uninit" + ICS03_GetConnection(connections, connectionId).state /= "Uninitialized" \* update `connectionId`'s data ICS03_SetConnection(connections, connectionId, connection) == diff --git a/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json b/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json index 98bb5dea1f..f0908502b3 100644 --- a/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS02ClientNotFoundTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -71,7 +71,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -91,7 +91,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS02CreateOKTest.json b/modules/tests/support/model_based/tests/ICS02CreateOKTest.json index 4c74c17c80..8101454208 100644 --- a/modules/tests/support/model_based/tests/ICS02CreateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02CreateOKTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json index 6b3ca8ac75..5295bc24be 100644 --- a/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json +++ b/modules/tests/support/model_based/tests/ICS02HeaderVerificationFailureTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -126,7 +126,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -146,7 +146,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json index bfb54b7493..aa0b59f950 100644 --- a/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json +++ b/modules/tests/support/model_based/tests/ICS02UpdateOKTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -127,7 +127,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 3 @@ -147,7 +147,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json index 036d601f26..830032c4cc 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionMismatchTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -155,7 +155,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -220,7 +220,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json index b6429c138c..db9ab2f953 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionNotFoundTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -130,7 +130,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -150,7 +150,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json index f330334ccd..80db392a89 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenAckOKTest.json @@ -22,7 +22,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -44,7 +44,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -79,7 +79,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -101,7 +101,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -167,7 +167,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -234,7 +234,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json index 72160bd322..ad9d75ed14 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenConfirmOKTest.json @@ -22,7 +22,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -44,7 +44,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -79,7 +79,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -101,7 +101,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -167,7 +167,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -234,7 +234,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json index 46d17af298..0f8f565ddb 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenInitOKTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -155,7 +155,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json index 6499e39cab..2fe2db8dee 100644 --- a/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json +++ b/modules/tests/support/model_based/tests/ICS03ConnectionOpenTryOKTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -155,7 +155,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -218,7 +218,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 diff --git a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json index a89d61d1fe..9b2b2c84c7 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidConsensusHeightTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -75,7 +75,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -95,7 +95,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json index bea670184a..dd3df3cd39 100644 --- a/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json +++ b/modules/tests/support/model_based/tests/ICS03InvalidProofTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -130,7 +130,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -150,7 +150,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json index 663a59010f..58e8d1c3c5 100644 --- a/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json +++ b/modules/tests/support/model_based/tests/ICS03MissingClientConsensusStateTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -73,7 +73,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -93,7 +93,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -130,7 +130,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -150,7 +150,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json index ab80e084c9..0c865ae8a2 100644 --- a/modules/tests/support/model_based/tests/ICS03MissingClientTest.json +++ b/modules/tests/support/model_based/tests/ICS03MissingClientTest.json @@ -20,7 +20,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -40,7 +40,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -72,7 +72,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -92,7 +92,7 @@ "connectionId": -1, "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 diff --git a/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json index 666a89222f..3dcdd3b2f8 100644 --- a/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json +++ b/modules/tests/support/model_based/tests/ICS03UninitializedConnectionTest.json @@ -22,7 +22,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -44,7 +44,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -79,7 +79,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -101,7 +101,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1 @@ -138,7 +138,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 2 @@ -160,7 +160,7 @@ "counterpartyChainId": "-1", "counterpartyClientId": -1, "counterpartyConnectionId": -1, - "state": "Uninit" + "state": "Uninitialized" } }, "height": 1