-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Call a contract #165
Merged
Merged
Call a contract #165
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
9a86802
Revert contracts put_code test to pure code (not using the macro)
ascjones 0e7bc2d
Test contract instantiate
ascjones 92bcd26
Fmt
ascjones e5800f4
Extract put_code and new_client functions
ascjones a958819
Merge branch 'master' into aj-contract-call
ascjones c6906c0
Generate fresh accounts for contract tests to allow reruns without a …
ascjones 477cac9
Fetch and increment nonce to allow concurrent test runs
ascjones f12013e
fmt
ascjones e7c9eb2
Failing contract call test
ascjones 4b5ef63
Fmt and fix compilation
ascjones f6f9c61
Fix error message for contract call
ascjones 635f958
Fix call test
ascjones ae82617
Update contract execution event comment
ascjones 2c85d21
Merge branch 'master' into aj-contract-call
ascjones 3f4ae68
Remove redundant feature flags, now on module
ascjones 779cb18
Update event data comment
ascjones 6684552
Use fetch_add
ascjones 93b4e61
Fmt
ascjones File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,6 +91,7 @@ pub struct CallCall<'a, T: Contracts> { | |
/// Address of the contract. | ||
pub dest: &'a <T as System>::Address, | ||
/// Value to transfer to the contract. | ||
#[codec(compact)] | ||
pub value: <T as Balances>::Balance, | ||
/// Gas limit. | ||
#[codec(compact)] | ||
|
@@ -115,45 +116,162 @@ pub struct InstantiatedEvent<T: Contracts> { | |
pub contract: <T as System>::AccountId, | ||
} | ||
|
||
/// Contract execution event. | ||
/// | ||
/// Emitted upon successful execution of a contract, if any contract events were produced. | ||
#[derive(Clone, Debug, Eq, PartialEq, Event, Decode)] | ||
pub struct ContractExecutionEvent<T: Contracts> { | ||
/// Caller of the contract. | ||
pub caller: <T as System>::AccountId, | ||
/// SCALE encoded contract event data. | ||
pub data: Vec<u8>, | ||
} | ||
|
||
#[cfg(test)] | ||
#[cfg(feature = "integration-tests")] | ||
mod tests { | ||
use sp_keyring::AccountKeyring; | ||
|
||
use super::*; | ||
use crate::{ | ||
balances::*, | ||
system::*, | ||
Client, | ||
ClientBuilder, | ||
ContractsTemplateRuntime, | ||
Error, | ||
ExtrinsicSuccess, | ||
PairSigner, | ||
Signer, | ||
}; | ||
use sp_core::{ | ||
crypto::AccountId32, | ||
sr25519::Pair, | ||
}; | ||
use std::sync::atomic::{ | ||
AtomicU32, | ||
Ordering, | ||
}; | ||
|
||
fn contract_wasm() -> Vec<u8> { | ||
const CONTRACT: &str = r#" | ||
(module | ||
(func (export "call")) | ||
(func (export "deploy")) | ||
) | ||
"#; | ||
wabt::wat2wasm(CONTRACT).expect("invalid wabt") | ||
static STASH_NONCE: std::sync::atomic::AtomicU32 = AtomicU32::new(0); | ||
|
||
struct TestContext { | ||
client: Client<ContractsTemplateRuntime>, | ||
signer: PairSigner<ContractsTemplateRuntime, Pair>, | ||
} | ||
|
||
#[async_std::test] | ||
#[cfg(feature = "integration-tests")] | ||
async fn tx_put_code() { | ||
env_logger::try_init().ok(); | ||
impl TestContext { | ||
async fn init() -> Self { | ||
env_logger::try_init().ok(); | ||
|
||
let client = ClientBuilder::<ContractsTemplateRuntime>::new() | ||
.build() | ||
.await | ||
.expect("Error creating client"); | ||
let mut stash = PairSigner::new(AccountKeyring::Alice.pair()); | ||
let nonce = client | ||
.account(&stash.account_id(), None) | ||
.await | ||
.unwrap() | ||
.nonce; | ||
let local_nonce = STASH_NONCE.fetch_add(1, Ordering::SeqCst); | ||
|
||
stash.set_nonce(nonce + local_nonce); | ||
|
||
let signer = Self::generate_account(&client, &mut stash).await; | ||
|
||
TestContext { client, signer } | ||
} | ||
|
||
/// generate a new keypair for an account, and fund it so it can perform smart contract operations | ||
async fn generate_account( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: consider making this available to other code. |
||
client: &Client<ContractsTemplateRuntime>, | ||
stash: &mut PairSigner<ContractsTemplateRuntime, Pair>, | ||
) -> PairSigner<ContractsTemplateRuntime, Pair> { | ||
use sp_core::Pair as _; | ||
let new_account = Pair::generate().0; | ||
let new_account_id: AccountId32 = new_account.public().into(); | ||
// fund the account | ||
let endowment = 200_000_000_000_000; | ||
let _ = client | ||
.transfer_and_watch(stash, &new_account_id, endowment) | ||
.await | ||
.expect("New account balance transfer failed"); | ||
stash.increment_nonce(); | ||
PairSigner::new(new_account) | ||
} | ||
|
||
let signer = PairSigner::new(AccountKeyring::Alice.pair()); | ||
let client = ClientBuilder::<ContractsTemplateRuntime>::new() | ||
.build() | ||
.await | ||
.unwrap(); | ||
async fn put_code( | ||
&self, | ||
) -> Result<CodeStoredEvent<ContractsTemplateRuntime>, Error> { | ||
const CONTRACT: &str = r#" | ||
(module | ||
(func (export "call")) | ||
(func (export "deploy")) | ||
) | ||
"#; | ||
let code = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); | ||
|
||
let code = contract_wasm(); | ||
let result = client.put_code_and_watch(&signer, &code).await.unwrap(); | ||
let code_stored = result.code_stored().unwrap(); | ||
let result = self.client.put_code_and_watch(&self.signer, &code).await?; | ||
let code_stored = result.code_stored()?.ok_or_else(|| { | ||
Error::Other("Failed to find a CodeStored event".into()) | ||
})?; | ||
log::info!("Code hash: {:?}", code_stored.code_hash); | ||
Ok(code_stored) | ||
} | ||
|
||
async fn instantiate( | ||
dvdplm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
&self, | ||
code_hash: &<ContractsTemplateRuntime as System>::Hash, | ||
data: &[u8], | ||
) -> Result<InstantiatedEvent<ContractsTemplateRuntime>, Error> { | ||
// call instantiate extrinsic | ||
let result = self | ||
.client | ||
.instantiate_and_watch( | ||
&self.signer, | ||
100_000_000_000_000, // endowment | ||
500_000_000, // gas_limit | ||
code_hash, | ||
data, | ||
) | ||
.await?; | ||
|
||
log::info!("Instantiate result: {:?}", result); | ||
let instantiated = result.instantiated()?.ok_or_else(|| { | ||
Error::Other("Failed to find a Instantiated event".into()) | ||
})?; | ||
|
||
Ok(instantiated) | ||
} | ||
|
||
async fn call( | ||
&self, | ||
contract: &<ContractsTemplateRuntime as System>::Address, | ||
input_data: &[u8], | ||
) -> Result<ExtrinsicSuccess<ContractsTemplateRuntime>, Error> { | ||
let result = self | ||
.client | ||
.call_and_watch( | ||
&self.signer, | ||
contract, | ||
0, // value | ||
500_000_000, // gas_limit | ||
input_data, | ||
) | ||
.await?; | ||
log::info!("Call result: {:?}", result); | ||
Ok(result) | ||
} | ||
} | ||
|
||
#[async_std::test] | ||
async fn tx_put_code() { | ||
let ctx = TestContext::init().await; | ||
let code_stored = ctx.put_code().await; | ||
|
||
assert!( | ||
code_stored.is_some(), | ||
code_stored.is_ok(), | ||
format!( | ||
"Error calling put_code and receiving CodeStored Event: {:?}", | ||
code_stored | ||
|
@@ -162,41 +280,29 @@ mod tests { | |
} | ||
|
||
#[async_std::test] | ||
#[cfg(feature = "integration-tests")] | ||
async fn tx_instantiate() { | ||
env_logger::try_init().ok(); | ||
let signer = PairSigner::new(AccountKeyring::Bob.pair()); | ||
let client = ClientBuilder::<ContractsTemplateRuntime>::new() | ||
.build() | ||
.await | ||
.unwrap(); | ||
|
||
// call put_code extrinsic | ||
let code = contract_wasm(); | ||
let result = client.put_code_and_watch(&signer, &code).await.unwrap(); | ||
let code_stored = result.code_stored().unwrap(); | ||
let code_hash = code_stored.unwrap().code_hash; | ||
|
||
log::info!("Code hash: {:?}", code_hash); | ||
|
||
// call instantiate extrinsic | ||
let result = client | ||
.instantiate_and_watch( | ||
&signer, | ||
100_000_000_000_000, // endowment | ||
500_000_000, // gas_limit | ||
&code_hash, | ||
&[], // data | ||
) | ||
.await | ||
.unwrap(); | ||
let ctx = TestContext::init().await; | ||
let code_stored = ctx.put_code().await.unwrap(); | ||
|
||
let instantiated = ctx.instantiate(&code_stored.code_hash, &[]).await; | ||
|
||
assert!( | ||
instantiated.is_ok(), | ||
format!("Error instantiating contract: {:?}", instantiated) | ||
); | ||
} | ||
|
||
#[async_std::test] | ||
async fn tx_call() { | ||
let ctx = TestContext::init().await; | ||
let code_stored = ctx.put_code().await.unwrap(); | ||
|
||
log::info!("Instantiate result: {:?}", result); | ||
let event = result.instantiated().unwrap(); | ||
let instantiated = ctx.instantiate(&code_stored.code_hash, &[]).await.unwrap(); | ||
let executed = ctx.call(&instantiated.contract, &[]).await; | ||
|
||
assert!( | ||
event.is_some(), | ||
format!("Error instantiating contract: {:?}", result) | ||
executed.is_ok(), | ||
format!("Error calling contract: {:?}", executed) | ||
); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is useful enough that it might be worth making it generic over the runtime and put it in a
test-utils.rs
for use in other places.