Skip to content

Commit cc52b41

Browse files
committed
WIP adding cross_contract_calls test
1 parent 99a9c03 commit cc52b41

File tree

7 files changed

+246
-0
lines changed

7 files changed

+246
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Ignore build artifacts from the local tests sub-crate.
2+
/target/
3+
4+
# Ignore backup files creates by cargo fmt.
5+
**/*.rs.bk
6+
7+
# Remove Cargo.lock when creating an executable, leave it for libraries
8+
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
9+
Cargo.lock
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "cross-contract-calls"
3+
version = "5.0.0-rc"
4+
authors = ["Parity Technologies <[email protected]>"]
5+
edition = "2021"
6+
publish = false
7+
8+
[dependencies]
9+
ink = { path = "../../crates/ink", default-features = false }
10+
11+
# Note: We **need** to specify the `ink-as-dependency` feature.
12+
#
13+
# If we don't we will end up with linking errors!
14+
other-contract = { path = "other-contract", default-features = false, features = ["ink-as-dependency"] }
15+
16+
[dev-dependencies]
17+
ink_e2e = { path = "../../crates/e2e" }
18+
19+
[lib]
20+
path = "lib.rs"
21+
22+
[features]
23+
default = ["std"]
24+
std = [
25+
"ink/std",
26+
27+
# Note: The metadata generation step requires `std`. If we don't specify this the metadata
28+
# generation for our contract will fail!
29+
"other-contract/std",
30+
]
31+
ink-as-dependency = []
32+
e2e-tests = []
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use super::incrementer::*;
2+
use ink_e2e::ContractsBackend;
3+
4+
type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
5+
6+
#[ink_e2e::test]
7+
async fn migration_works<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
8+
// Given
9+
let mut constructor = IncrementerRef::new();
10+
let contract = client
11+
.instantiate("incrementer", &ink_e2e::alice(), &mut constructor)
12+
.submit()
13+
.await
14+
.expect("instantiate failed");
15+
let mut call = contract.call::<Incrementer>();
16+
17+
let get = call.get();
18+
let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await;
19+
assert_eq!(get_res.return_value(), 0);
20+
21+
let inc = call.inc();
22+
let _inc_result = client
23+
.call(&ink_e2e::alice(), &inc)
24+
.submit()
25+
.await
26+
.expect("`inc` failed");
27+
28+
let get = call.get();
29+
let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await;
30+
let pre_migration_value = get_res.return_value();
31+
assert_eq!(pre_migration_value, 1);
32+
33+
// Upload the code for the contract to be updated to after the migration.
34+
let new_code_hash = client
35+
.upload("updated-incrementer", &ink_e2e::alice())
36+
.submit()
37+
.await
38+
.expect("uploading `updated-incrementer` failed")
39+
.code_hash;
40+
let new_code_hash = new_code_hash.as_ref().try_into().unwrap();
41+
42+
// Upload the code for the migration contract.
43+
let migration_contract = client
44+
.upload("migration", &ink_e2e::alice())
45+
.submit()
46+
.await
47+
.expect("uploading `migration` failed");
48+
let migration_code_hash = migration_contract.code_hash.as_ref().try_into().unwrap();
49+
50+
// When
51+
52+
// Set the code hash to the migration contract
53+
let set_code = call.set_code(migration_code_hash);
54+
let _set_code_result = client
55+
.call(&ink_e2e::alice(), &set_code)
56+
.submit()
57+
.await
58+
.expect("`set_code` failed");
59+
60+
// Call the migration contract with a new value for `inc_by` and the code hash
61+
// of the updated contract.
62+
const NEW_INC_BY: u8 = 4;
63+
let migrate = contract
64+
.call::<migration::incrementer::Incrementer>()
65+
.migrate(NEW_INC_BY, new_code_hash);
66+
67+
let _migration_result = client
68+
.call(&ink_e2e::alice(), &migrate)
69+
.submit()
70+
.await
71+
.expect("`migrate` failed");
72+
73+
// Then
74+
let inc = contract
75+
.call::<updated_incrementer::incrementer::Incrementer>()
76+
.inc();
77+
78+
let _inc_result = client
79+
.call(&ink_e2e::alice(), &inc)
80+
.submit()
81+
.await
82+
.expect("`inc` failed");
83+
84+
let get = call.get();
85+
let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await;
86+
87+
// Remember, we updated our incrementer contract to increment by `4`.
88+
assert_eq!(
89+
get_res.return_value(),
90+
pre_migration_value + NEW_INC_BY as u32
91+
);
92+
93+
Ok(())
94+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![cfg_attr(not(feature = "std"), no_std, no_main)]
2+
3+
#[ink::contract]
4+
mod cross_contract_calls {
5+
/// We import the generated `ContractRef` of our other contract.
6+
///
7+
/// Note that the other contract must have re-exported it (`pub use
8+
/// OtherContractRef`) for us to have access to it.
9+
use other_contract::OtherContractRef;
10+
11+
#[ink(storage)]
12+
pub struct CrossContractCalls {
13+
/// We specify that our contract will store a reference to the `OtherContract`.
14+
other_contract: AccountId,
15+
}
16+
17+
impl CrossContractCalls {
18+
/// In order to use the `OtherContract` we first need to **instantiate** it.
19+
///
20+
/// To do this we will use the uploaded `code_hash` of `OtherContract`.
21+
#[ink(constructor)]
22+
pub fn new(other_contract: AccountId) -> Self {
23+
// todo: need to add instantiate_v2 methods...
24+
let other_contract = OtherContractRef::new(true)
25+
.code_hash(other_contract_code_hash)
26+
.endowment(0)
27+
.salt_bytes([0xDE, 0xAD, 0xBE, 0xEF])
28+
.instantiate();
29+
30+
Self { other_contract }
31+
}
32+
33+
/// Using the `ContractRef` we can call all the messages of the `OtherContract` as
34+
/// if they were normal Rust methods (because at the end of the day, they
35+
/// are!).
36+
#[ink(message)]
37+
pub fn flip_and_get(&mut self) -> bool {
38+
// todo: add calls to `call_v2`
39+
self.other_contract.flip();
40+
self.other_contract.get()
41+
}
42+
}
43+
}
44+
45+
#[cfg(all(test, feature = "e2e-tests"))]
46+
mod e2e_tests;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Ignore build artifacts from the local tests sub-crate.
2+
/target/
3+
4+
# Ignore backup files creates by cargo fmt.
5+
**/*.rs.bk
6+
7+
# Remove Cargo.lock when creating an executable, leave it for libraries
8+
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
9+
Cargo.lock
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "other-contract"
3+
version = "5.0.0-rc"
4+
authors = ["Parity Technologies <[email protected]>"]
5+
edition = "2021"
6+
publish = false
7+
8+
[dependencies]
9+
ink = { path = "../../../crates/ink", default-features = false }
10+
11+
[dev-dependencies]
12+
ink_e2e = { path = "../../../crates/e2e" }
13+
14+
[lib]
15+
path = "lib.rs"
16+
17+
[features]
18+
default = ["std"]
19+
std = [
20+
"ink/std",
21+
]
22+
ink-as-dependency = []
23+
e2e-tests = []
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![cfg_attr(not(feature = "std"), no_std, no_main)]
2+
3+
/// Re-export the `ContractRef` generated by the ink! codegen.
4+
///
5+
/// This let's other crates which pull this contract in as a dependency to interact
6+
/// with this contract in a type-safe way.
7+
pub use self::other_contract::OtherContractRef;
8+
9+
#[ink::contract]
10+
mod other_contract {
11+
12+
#[ink(storage)]
13+
pub struct OtherContract {
14+
value: bool,
15+
}
16+
17+
impl OtherContract {
18+
#[ink(constructor)]
19+
pub fn new(init_value: bool) -> Self {
20+
Self { value: init_value }
21+
}
22+
23+
#[ink(message)]
24+
pub fn flip(&mut self) {
25+
self.value = !self.value;
26+
}
27+
28+
#[ink(message)]
29+
pub fn get(&self) -> bool {
30+
self.value
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)