Skip to content

Commit

Permalink
test(subxt-tests): integration test for substrate using subxt
Browse files Browse the repository at this point in the history
Signed-off-by: Raymond Yeh <extraymond@gmail.com>
  • Loading branch information
extraymond committed Jun 18, 2023
1 parent 12e9b97 commit e8109b6
Show file tree
Hide file tree
Showing 29 changed files with 4,810 additions and 1 deletion.
43 changes: 42 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
workflow_dispatch:

# FIXME: currently needed to bypass a transient dependency using nightly feature
env:
RUSTC_BOOTSTRAP: 1

jobs:
repolinter:
name: Repolinter
Expand Down Expand Up @@ -86,7 +90,8 @@ jobs:
- uses: actions/upload-artifact@v3.1.0
with:
name: solang-linux-x86-64
path: ./target/debug/solang
path: ./target/debug/solang


linux-arm:
name: Linux Arm
Expand Down Expand Up @@ -347,6 +352,42 @@ jobs:
if: always()
run: docker kill ${{steps.substrate.outputs.id}}

substrate-subxt:
name: Substrate Integration test with subxt
runs-on: ubuntu-20.04
needs: linux-x86-64
steps:
- name: Checkout sources
uses: actions/checkout@v2
# We can't run substrate as a github actions service, since it requires
# command line arguments. See https://github.com/actions/runner/pull/1152
- name: Start substrate
run: echo id=$(docker run -d -p 9944:9944 paritytech/contracts-ci-linux@sha256:77a885f3c22d38385b017983c942bf7e063ac127bdc0477670d23a38711a2c38 substrate-contracts-node --dev --ws-external) >> $GITHUB_OUTPUT
id: substrate
- uses: actions/download-artifact@master
with:
name: solang-linux-x86-64
path: bin
- run: |
chmod 755 ./bin/solang
echo "$(pwd)/bin" >> $GITHUB_PATH
- name: Install latest rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
default: true
override: true
- run: solang compile --target substrate ../substrate/*.sol -o ./contracts/
working-directory: ./integration/subxt-tests
- run: solang compile --target substrate ../substrate/test/*.sol -o ./contracts/
working-directory: ./integration/subxt-tests
- name: Deploy and test contracts
run: cargo test -- --test-threads=1
working-directory: ./integration/subxt-tests
- name: cleanup
if: always()
run: docker kill ${{steps.substrate.outputs.id}}

vscode:
name: Visual Code Extension
runs-on: solang-ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Cargo.lock
**/*.rs.bk
bundle.ll

.helix/
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rust-analyzer.linkedProjects": [
"./integration/subxt-tests/Cargo.toml"
]
}
12 changes: 12 additions & 0 deletions integration/substrate/createpair.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity ^0.8.0;
import "./UniswapV2Pair.sol";

contract Creator {
address public pair;

constructor() public {
pair = address(new UniswapV2Pair());
}

}

2 changes: 2 additions & 0 deletions integration/subxt-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
contracts/
target/
27 changes: 27 additions & 0 deletions integration/subxt-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
edition = "2021"
name = "subxt-tests"
version = "0.1.0"

[dependencies]
anyhow = "1.0.71"
async-trait = "0.1.68"
sp-core = "20.0.0"
sp-runtime = "23.0.0"
sp-weights = "19.0.0"
pallet-contracts-primitives = "23.0.0"
hex = "0.4.3"
num-bigint = "0.4.3"
once_cell = "1.17.2"
parity-scale-codec = { version = "3.5.0", features = ["derive"] }
rand = "0.8.5"
serde_json = "1.0.96"
sp-keyring = "23.0.0"
subxt = "0.28.0"
tokio = {version = "1.28.2", features = ["rt-multi-thread", "macros", "time"]}
contract-metadata = "3.0.1"
contract-transcode = "3.0.1"

[workspace]
members = []

Binary file added integration/subxt-tests/metadata.scale
Binary file not shown.
135 changes: 135 additions & 0 deletions integration/subxt-tests/src/cases/array_struct_mapping_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use contract_transcode::ContractMessageTranscoder;
use parity_scale_codec::{Decode, Encode};
use sp_core::{hexdisplay::AsBytesRef, U256};

use crate::{Contract, DeployContract, Execution, ReadContract, WriteContract, API};

#[tokio::test]
async fn case() -> anyhow::Result<()> {
let api = API::new().await?;

let mut contract = Contract::new("./contracts/array_struct_mapping_storage.contract")?;

contract
.deploy(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| t.encode::<_, String>("new", []).unwrap(),
)
.await?;

contract
.call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| t.encode::<_, _>("setNumber", ["2147483647"]).unwrap(),
)
.await?;

let b_push = |t: &ContractMessageTranscoder| t.encode::<_, String>("push", []).unwrap();

contract
.call(&api, sp_keyring::AccountKeyring::Alice, 0, &b_push)
.await?;

contract
.call(&api, sp_keyring::AccountKeyring::Alice, 0, &b_push)
.await?;

for array_no in 0..2 {
for i in 0..10 {
contract
.call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode::<_, _>(
"set",
[
format!("{}", array_no),
format!("{}", 102 + i + array_no * 500),
format!("{}", 300331 + i),
],
)
.unwrap()
},
)
.await?;
}
}

for array_no in 0..2 {
for i in 0..10 {
let rs = contract
.try_call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode::<_, _>(
"get",
[
format!("{}", array_no),
format!("{}", 102 + i + array_no * 500),
],
)
.unwrap()
},
)
.await
.and_then(|v| <U256>::decode(&mut v.as_bytes_ref()).map_err(Into::into))?;

assert_eq!(rs, U256::from(300331_u128 + i));
}
}

contract
.call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode::<_, _>("rm", [format!("{}", 0), format!("{}", 104)])
.unwrap()
},
)
.await?;

for i in 0..10 {
let rs = contract
.try_call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode::<_, _>("get", [format!("{}", 0), format!("{}", 102 + i)])
.unwrap()
},
)
.await
.and_then(|v| <U256>::decode(&mut v.as_bytes_ref()).map_err(Into::into))?;

if i != 2 {
assert_eq!(rs, U256::from(300331_u128 + i));
} else {
assert_eq!(rs, U256::zero());
}
}

let rs = contract
.try_call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| t.encode::<_, String>("number", []).unwrap(),
)
.await
.and_then(|v| <i64>::decode(&mut v.as_bytes_ref()).map_err(Into::into))?;

assert_eq!(rs, 2147483647);

Ok(())
}
105 changes: 105 additions & 0 deletions integration/subxt-tests/src/cases/arrays.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::{Contract, DeployContract, Execution, ReadContract, WriteContract, API};
use contract_transcode::{ContractMessageTranscoder, Value};
use hex::FromHex;

use parity_scale_codec::{Decode, Encode};
use rand::{seq::SliceRandom, thread_rng, Rng};
use sp_core::{crypto::AccountId32, hexdisplay::AsBytesRef};

#[ignore]
#[tokio::test]
async fn case() -> anyhow::Result<()> {
let api = API::new().await?;

let mut contract = Contract::new("./contracts/arrays.contract")?;

contract
.deploy(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| t.encode::<_, String>("new", []).unwrap(),
)
.await?;

let mut users = Vec::new();

for i in 0..3 {
let rnd_addr = rand::random::<[u8; 32]>();

let name = format!("name{i}");

let id = u32::from_be_bytes(rand::random::<[u8; 4]>());
let mut perms = Vec::<String>::new();

let mut j: f64 = 0.0;
while j < rand::thread_rng().gen_range(0.0..=3.0) {
j += 1.0;

let p = rand::thread_rng().gen_range(0..8);
perms.push(format!("Perm{}", p + 1));
}

contract
.call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode(
"addUser",
[
id.to_string(),
format!("0x{}", hex::encode(rnd_addr)),
format!("\"{}\"", name.clone()),
format!("[{}]", perms.join(",")),
],
)
.unwrap()
},
)
.await?;

users.push((name, rnd_addr, id, perms));
}

let (name, addr, id, perms) = users.choose(&mut thread_rng()).unwrap();

let output = contract
.try_call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode("getUserById", [format!("\"{id}\"")]).unwrap()
},
)
.await?;

let (name, addr, id, perms) =
<(String, AccountId32, u64, Vec<u8>)>::decode(&mut output.as_bytes_ref())?;

if !perms.is_empty() {
let p = perms.choose(&mut thread_rng()).unwrap();

let output = contract
.try_call(
&api,
sp_keyring::AccountKeyring::Alice,
0,
&|t: &ContractMessageTranscoder| {
t.encode(
"hasPermission",
[format!("\"{id}\""), format!("Perm{}", p + 1)],
)
.unwrap()
},
)
.await?;

let has_permission = <bool>::decode(&mut output.as_bytes_ref())?;
assert!(has_permission);
}

Ok(())
}
Loading

0 comments on commit e8109b6

Please sign in to comment.