diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 651d1e177..7b9d6b96e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -321,7 +321,7 @@ jobs: # We can't run substrate node as a github actions service, since it requires # command line arguments. See https://github.com/actions/runner/pull/1152 - name: Start substrate contracts node - run: echo id=$(docker run -d -p 9944:9944 ghcr.io/hyperledger/solang-substrate-ci:e41a9c0 substrate-contracts-node --dev --ws-external) >> $GITHUB_OUTPUT + run: echo id=$(docker run -d -p 9944:9944 ghcr.io/hyperledger/solang-substrate-ci:054bef6 substrate-contracts-node --dev --rpc-external) >> $GITHUB_OUTPUT id: substrate - uses: actions/setup-node@v3 with: @@ -358,7 +358,7 @@ jobs: # We can't run substrate node 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 ghcr.io/hyperledger/solang-substrate-ci:e41a9c0 substrate-contracts-node --dev --ws-external) >> $GITHUB_OUTPUT + run: echo id=$(docker run -d -p 9944:9944 ghcr.io/hyperledger/solang-substrate-ci:054bef6 substrate-contracts-node --dev --rpc-external) >> $GITHUB_OUTPUT id: substrate - uses: actions/download-artifact@master with: diff --git a/integration/polkadot/UniswapV2ERC20.spec.ts b/integration/polkadot/UniswapV2ERC20.spec.ts index 9466f3ba9..ae98bc298 100644 --- a/integration/polkadot/UniswapV2ERC20.spec.ts +++ b/integration/polkadot/UniswapV2ERC20.spec.ts @@ -70,7 +70,7 @@ describe('Deploy UniswapV2ERC20 contract and test', () => { }) it('transfer', async () => { - let gasLimit = await weight(conn, token, "approve", [dave.address, TEST_AMOUNT]); + let gasLimit = await weight(conn, token, "transfer", [dave.address, TEST_AMOUNT]); let tx = token.tx.transfer({ gasLimit }, dave.address, TEST_AMOUNT); await transaction(tx, alice); @@ -90,7 +90,15 @@ describe('Deploy UniswapV2ERC20 contract and test', () => { let tx = token.tx.approve({ gasLimit }, dave.address, TEST_AMOUNT); await transaction(tx, alice); - tx = token.tx.transferFrom({ gasLimit }, alice.address, dave.address, TEST_AMOUNT); + const dryRun = await conn.call.contractsApi.call( + dave.address, + token.address, + 0, + null, + null, + token.abi.findMessage("transferFrom").toU8a([alice.address, dave.address, TEST_AMOUNT]) + ); + tx = token.tx.transferFrom({ gasLimit: dryRun.gasRequired }, alice.address, dave.address, TEST_AMOUNT); await transaction(tx, dave); const { output: allowance } = await query(conn, alice, token, "allowance", [alice.address, dave.address]); @@ -106,7 +114,15 @@ describe('Deploy UniswapV2ERC20 contract and test', () => { let tx = token.tx.approve({ gasLimit }, dave.address, MAX_UINT256); await transaction(tx, alice); - tx = token.tx.transferFrom({ gasLimit }, alice.address, dave.address, TEST_AMOUNT); + const dryRun = await conn.call.contractsApi.call( + dave.address, + token.address, + 0, + null, + null, + token.abi.findMessage("transferFrom").toU8a([alice.address, dave.address, TEST_AMOUNT]) + ); + tx = token.tx.transferFrom({ gasLimit: dryRun.gasRequired }, alice.address, dave.address, TEST_AMOUNT); await transaction(tx, dave); const { output: allowance } = await query(conn, alice, token, "allowance", [alice.address, dave.address]); diff --git a/integration/polkadot/array_struct_mapping_storage.spec.ts b/integration/polkadot/array_struct_mapping_storage.spec.ts index 7a9c45654..cd0f23f66 100644 --- a/integration/polkadot/array_struct_mapping_storage.spec.ts +++ b/integration/polkadot/array_struct_mapping_storage.spec.ts @@ -20,10 +20,12 @@ describe('Deploy array_struct_mapping_storage contract and test', () => { await transaction(tx, alice); // let's add two elements to our array + gasLimit = await weight(conn, contract, "push", []); tx = contract.tx.push({ gasLimit }); await transaction(tx, alice); + gasLimit = await weight(conn, contract, "push", []); tx = contract.tx.push({ gasLimit }); await transaction(tx, alice); @@ -31,7 +33,10 @@ describe('Deploy array_struct_mapping_storage contract and test', () => { // set some values for (let array_no = 0; array_no < 2; array_no += 1) { for (let i = 0; i < 10; i += 1) { - tx = contract.tx.set({ gasLimit }, array_no, 102 + i + array_no * 500, 300331 + i); + let index = 102 + i + array_no * 500; + let val = 300331 + i; + gasLimit = await weight(conn, contract, "set", [array_no, index, val]); + tx = contract.tx.set({ gasLimit }, array_no, index, val); await transaction(tx, alice); } @@ -49,6 +54,7 @@ describe('Deploy array_struct_mapping_storage contract and test', () => { } // delete one and try again + gasLimit = await weight(conn, contract, "rm", [0, 104]); tx = contract.tx.rm({ gasLimit }, 0, 104); await transaction(tx, alice); diff --git a/integration/polkadot/asserts.spec.ts b/integration/polkadot/asserts.spec.ts index 6626a8933..8918e1cfc 100644 --- a/integration/polkadot/asserts.spec.ts +++ b/integration/polkadot/asserts.spec.ts @@ -38,8 +38,8 @@ describe('Deploy asserts contract and test', () => { throw new Error("should not succeed"); }, (res) => res); - // Error 24 is ContractReverted - expect(res2.dispatchError.toHuman()).toEqual({ "Module": { "error": "0x18000000", "index": "8" } }); + // Error 25 is ContractReverted + expect(res2.dispatchError.toHuman()).toEqual({ "Module": { "error": "0x19000000", "index": "8" } }); let res3 = await query(conn, alice, contract, "var"); diff --git a/integration/polkadot/balances.spec.ts b/integration/polkadot/balances.spec.ts index c25f09850..068f2a15a 100644 --- a/integration/polkadot/balances.spec.ts +++ b/integration/polkadot/balances.spec.ts @@ -30,7 +30,7 @@ describe('Deploy balances contract and test', () => { expect(contractRpcBal?.toString()).toBe(contractQueryBalBefore.toString()); - let gasLimit = await weight(conn, contract, "payMe"); + let gasLimit = await weight(conn, contract, "payMe", undefined, 1000000n); let tx = contract.tx.payMe({ gasLimit, value: 1000000n }); await transaction(tx, alice); @@ -41,6 +41,7 @@ describe('Deploy balances contract and test', () => { let { data: { free: daveBal1 } } = await conn.query.system.account(dave.address); + gasLimit = await weight(conn, contract, "transfer", [dave.address, 20000]); let tx1 = contract.tx.transfer({ gasLimit }, dave.address, 20000); await transaction(tx1, alice); @@ -49,6 +50,7 @@ describe('Deploy balances contract and test', () => { expect(daveBal2.toBigInt()).toEqual(daveBal1.toBigInt() + 20000n); + gasLimit = await weight(conn, contract, "transfer", [dave.address, 10000]); let tx2 = contract.tx.send({ gasLimit }, dave.address, 10000); await transaction(tx2, alice); diff --git a/integration/polkadot/builtins2.spec.ts b/integration/polkadot/builtins2.spec.ts index dfba8e81b..4c9cb9dd4 100644 --- a/integration/polkadot/builtins2.spec.ts +++ b/integration/polkadot/builtins2.spec.ts @@ -40,6 +40,7 @@ describe('Deploy builtins2 contract and test', () => { // Gas metering is based on execution time: // Expect each call to burn between 10000..1000000 more gas than the previous iteration. for (let i = 1; i < 100; i++) { + gasLimit = await weight(conn, contract, "burnGas", [i]); let { output: gas_left } = await query(conn, alice, contract, "burnGas", [i], undefined, convertWeight(gasLimit).v2Weight); let gas = BigInt(gas_left!.toString()); expect(gasLimit.toJSON().refTime).toBeGreaterThan(gas); diff --git a/integration/polkadot/call_flags.spec.ts b/integration/polkadot/call_flags.spec.ts index 7ab82fc37..33fed0ad0 100644 --- a/integration/polkadot/call_flags.spec.ts +++ b/integration/polkadot/call_flags.spec.ts @@ -54,9 +54,9 @@ describe('Deploy the CallFlags contract and tests for various call flag combinat const flags = [CallFlags.TAIL_CALL]; const answer = await query(conn, alice, contract, "echo", [contract.address, foo, voyager, flags]); const { index, error } = answer.result.asErr.asModule; - // Module 8 error 0x14 is ReentranceDenied in the contracts pallet + // Module 8 error 0x15 is ReentranceDenied in the contracts pallet expect(index.toJSON()).toStrictEqual(8); - expect(error.toJSON()).toStrictEqual("0x14000000"); + expect(error.toJSON()).toStrictEqual("0x15000000"); }); it('fails with the input forwarding flag', async function () { diff --git a/integration/polkadot/package.json b/integration/polkadot/package.json index 20247307e..1da07ef6f 100644 --- a/integration/polkadot/package.json +++ b/integration/polkadot/package.json @@ -6,7 +6,7 @@ "scripts": { "test": "tsc; ts-mocha -t 20000 --exit *.spec.ts", "build": "./build.sh", - "build-ink": "docker run --rm -v $(pwd)/ink/caller:/opt/contract ghcr.io/hyperledger/solang-substrate-ci:e41a9c0 cargo contract build --release --manifest-path /opt/contract/Cargo.toml" + "build-ink": "docker run --rm -v $(pwd)/ink/caller:/opt/contract ghcr.io/hyperledger/solang-substrate-ci:054bef6 cargo contract build --release --manifest-path /opt/contract/Cargo.toml" }, "contributors": [ { @@ -30,11 +30,11 @@ "typescript": "^4.7" }, "dependencies": { - "@polkadot/api": "^10.6", - "@polkadot/api-contract": "^10.6", - "@polkadot/keyring": "^12.1", - "@polkadot/types": "^10.6", - "@polkadot/util-crypto": "^12.1", + "@polkadot/api": "^10.9", + "@polkadot/api-contract": "^10.9", + "@polkadot/keyring": "^12.3", + "@polkadot/types": "^10.9", + "@polkadot/util-crypto": "^12.3", "websnark": "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d", "snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", "circomlib": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc", diff --git a/integration/subxt-tests/Cargo.toml b/integration/subxt-tests/Cargo.toml index 36994262a..836871e5d 100644 --- a/integration/subxt-tests/Cargo.toml +++ b/integration/subxt-tests/Cargo.toml @@ -7,18 +7,18 @@ license = "Apache-2.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" +sp-core = "21.0.0" +sp-runtime = "24.0.0" +sp-weights = "20.0.0" +pallet-contracts-primitives = "24.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" +sp-keyring = "24.0.0" +subxt = { version = "0.31.0", features = ["substrate-compat"] } tokio = {version = "1.28.2", features = ["rt-multi-thread", "macros", "time"]} contract-metadata = "3.0.1" contract-transcode = "3.0.1" diff --git a/integration/subxt-tests/metadata.scale b/integration/subxt-tests/metadata.scale index 54620b975..6d96d2677 100644 Binary files a/integration/subxt-tests/metadata.scale and b/integration/subxt-tests/metadata.scale differ diff --git a/integration/subxt-tests/src/cases/asserts.rs b/integration/subxt-tests/src/cases/asserts.rs index ce57f52f9..71b24e758 100644 --- a/integration/subxt-tests/src/cases/asserts.rs +++ b/integration/subxt-tests/src/cases/asserts.rs @@ -5,7 +5,7 @@ use contract_transcode::ContractMessageTranscoder; use hex::FromHex; use parity_scale_codec::{Decode, Encode}; use sp_core::hexdisplay::AsBytesRef; -use subxt::metadata::ErrorMetadata; +use subxt::error::MetadataError; use crate::API; @@ -55,8 +55,11 @@ async fn case() -> anyhow::Result<()> { 0, &|t: &ContractMessageTranscoder| t.encode::<_, String>("test_assert_rpc", []).unwrap(), ) - .await; - assert!(res.unwrap_err().to_string().contains("ContractReverted")); + .await + .unwrap_err(); + assert!(res + .to_string() + .contains("ModuleError { index: 8, error: [25, 0, 0, 0] }")); // state should not change after failed operation let rv = contract diff --git a/integration/subxt-tests/src/cases/flipper.rs b/integration/subxt-tests/src/cases/flipper.rs index c8ab21d1b..fbfd255a1 100644 --- a/integration/subxt-tests/src/cases/flipper.rs +++ b/integration/subxt-tests/src/cases/flipper.rs @@ -59,6 +59,5 @@ async fn case() -> anyhow::Result<()> { .and_then(|v| ::decode(&mut v.as_bytes_ref()).map_err(Into::into))?; assert!(!updated); - Ok(()) } diff --git a/integration/subxt-tests/src/cases/primitives.rs b/integration/subxt-tests/src/cases/primitives.rs index 6df770fd6..1a7ba26c7 100644 --- a/integration/subxt-tests/src/cases/primitives.rs +++ b/integration/subxt-tests/src/cases/primitives.rs @@ -8,7 +8,7 @@ use num_bigint::{BigInt, BigUint, Sign}; use parity_scale_codec::{Decode, Encode, Input}; use sp_core::{crypto::AccountId32, hexdisplay::AsBytesRef, keccak_256, KeccakHasher, H256, U256}; use sp_runtime::{assert_eq_error_rate, scale_info::TypeInfo}; -use subxt::ext::sp_runtime::{traits::One, MultiAddress}; +use sp_runtime::{traits::One, MultiAddress}; use crate::{Contract, DeployContract, Execution, ReadContract, WriteContract, API}; diff --git a/integration/subxt-tests/src/lib.rs b/integration/subxt-tests/src/lib.rs index 037ea2421..b861b36be 100644 --- a/integration/subxt-tests/src/lib.rs +++ b/integration/subxt-tests/src/lib.rs @@ -7,19 +7,23 @@ use contract_transcode::ContractMessageTranscoder; -use node::runtime_types::pallet_contracts::wasm::Determinism; +use node::runtime_types::{ + contracts_node_runtime::RuntimeEvent, + frame_system::EventRecord, + pallet_contracts::wasm::Determinism, + sp_weights::weight_v2::{self, Weight}, +}; use pallet_contracts_primitives::{ ContractExecResult, ContractResult, ExecReturnValue, GetStorageResult, }; use parity_scale_codec::{Decode, Encode}; use sp_core::{crypto::AccountId32, hexdisplay::AsBytesRef, Bytes}; -use sp_weights::Weight; +use sp_runtime::{DispatchError, ModuleError}; use subxt::{ blocks::ExtrinsicEvents as TxEvents, - ext::sp_runtime::DispatchError, tx::PairSigner, - utils::{MultiAddress, Static}, + utils::{MultiAddress, Static, H256}, Config, OnlineClient, PolkadotConfig, }; @@ -30,13 +34,7 @@ use tokio::time::timeout; mod cases; // metadata file obtained from the latest substrate-contracts-node -#[subxt::subxt( - runtime_metadata_path = "./metadata.scale", - substitute_type( - type = "sp_weights::weight_v2::Weight", - with = "::subxt::utils::Static<::sp_weights::Weight>" - ) -)] +#[subxt::subxt(runtime_metadata_path = "./metadata.scale")] pub mod node {} pub type API = OnlineClient; @@ -175,12 +173,6 @@ impl Execution for WriteContract { .ok() .flatten() }) { - if let node::runtime_types::sp_runtime::DispatchError::Module(e) = &e.dispatch_error { - if let Ok(details) = api.metadata().error(e.index, e.error[0]) { - return Err(anyhow::anyhow!("{details:?}")); - } - } - return Err(anyhow::anyhow!("{e:?}")); } @@ -268,7 +260,10 @@ async fn raw_instantiate_and_upload( let payload = node::tx().contracts().instantiate_with_code( value, - Static::from(sp_weights::Weight::from(gas_limit)), + Weight { + ref_time: gas_limit, + proof_size: 1000000, + }, storage_deposit_limit.map(Into::into), code, data, @@ -329,7 +324,10 @@ async fn raw_call( let payload = node::tx().contracts().call( MultiAddress::Id(<_ as Decode>::decode(&mut dest.encode().as_bytes_ref())?), value, - Static::from(sp_weights::Weight::from(gas_limit)), + Weight { + ref_time: gas_limit, + proof_size: 1000000, + }, storage_deposit_limit.map(Into::into), data, ); @@ -355,12 +353,14 @@ async fn query_call( ) -> anyhow::Result { let rv = api .rpc() - .state_call( + .state_call::( "ContractsApi_get_storage", Some((contract_address, key).encode().as_bytes_ref()), None, ) - .await?; + .await? + .unwrap() + .unwrap(); ::decode(&mut rv.as_bytes_ref()).map_err(|e| anyhow::anyhow!("{e:?}")) } @@ -371,25 +371,30 @@ async fn read_call( contract_address: AccountId32, value: u128, selector: Vec, -) -> anyhow::Result> { +) -> anyhow::Result< + ContractResult, u128, EventRecord>, +> { let req = CallRequest { origin: ::decode(&mut caller.encode().as_bytes_ref())?, dest: <_ as Decode>::decode(&mut contract_address.encode().as_bytes_ref())?, value, - gas_limit: Some(Weight::from(GAS_LIMIT)), + gas_limit: Some(Weight { + ref_time: GAS_LIMIT, + proof_size: 100000, + }), storage_deposit_limit: None, input_data: selector, }; let rv = api .rpc() - .state_call("ContractsApi_call", Some(req.encode().as_bytes_ref()), None) + .state_call::>>( + "ContractsApi_call", + Some(req.encode().as_bytes_ref()), + None, + ) .await?; - let rv = ContractResult::, u128>::decode( - &mut rv.as_bytes_ref(), - )?; - Ok(rv) }