Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions prdoc/pr_10919.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
title: Add revive substrate runtime-api integration tests for call & instantiate
doc:
- audience: Runtime Dev
description: |-
## Summary
- Add integration tests for revive runtime API
- Test Fibonacci contract deployment and execution via substrate APIs

## Changes
- Add test for Fibonacci contract call via runtime API
- Add test to verify large Fibonacci values run out of gas as expected
- Update dev-node runtime configuration for testing

## Test plan
- Run new integration tests
- Verify runtime API correctly handles contract deployment
- Verify gas limits are enforced correctly
crates:
- name: revive-dev-runtime
bump: patch
- name: pallet-revive-eth-rpc
bump: patch
16 changes: 13 additions & 3 deletions substrate/frame/revive/dev-node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ pub mod currency {
pub mod genesis_config_presets {
use super::*;
use crate::{
currency::DOLLARS, sp_keyring::Sr25519Keyring, Balance, BalancesConfig,
currency::DOLLARS, sp_keyring::Sr25519Keyring, Balance, BalancesConfig, ReviveConfig,
RuntimeGenesisConfig, SudoConfig,
};

use alloc::{vec, vec::Vec};
use pallet_revive::is_eth_derived;
use serde_json::Value;

pub const ENDOWMENT: Balance = 10_000_000_000_001 * DOLLARS;
Expand Down Expand Up @@ -103,14 +104,23 @@ pub mod genesis_config_presets {

/// Returns a development genesis config preset.
pub fn development_config_genesis() -> Value {
let endowed_accounts = well_known_accounts();
frame_support::build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: well_known_accounts()
.into_iter()
balances: endowed_accounts
.iter()
.cloned()
.map(|id| (id, ENDOWMENT))
.collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.to_account_id()) },
revive: ReviveConfig {
mapped_accounts: endowed_accounts
.iter()
.filter(|x| !is_eth_derived(x))
.cloned()
.collect(),
},
})
}

Expand Down
103 changes: 103 additions & 0 deletions substrate/frame/revive/rpc/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ async fn run_all_eth_rpc_tests() -> anyhow::Result<()> {
}

run_tests!(
test_fibonacci_call_via_runtime_api,
test_transfer,
test_deploy_and_call,
test_runtime_api_dry_run_addr_works,
Expand Down Expand Up @@ -790,3 +791,105 @@ async fn test_runtime_pallets_address_upload_code(client: Arc<WsClient>) -> anyh

Ok(())
}

/// Test that deploys and calls the Fibonacci contract via Substrate APIs works
async fn test_fibonacci_call_via_runtime_api() -> anyhow::Result<()> {
use pallet_revive::precompiles::alloy::sol_types::SolCall;
use pallet_revive_fixtures::Fibonacci;

let (bytes, _) = pallet_revive_fixtures::compile_module_with_type(
"Fibonacci",
pallet_revive_fixtures::FixtureType::Solc,
)?;

let node_client =
OnlineClient::<SrcChainConfig>::from_url(SharedResources::node_rpc_url()).await?;
let signer = subxt_signer::sr25519::dev::alice();
let origin: [u8; 32] = signer.public_key().0;

// Deploy the Fibonacci contract via Substrate API
log::trace!(target: LOG_TARGET, "Deploying Fibonacci contract via Substrate API");
let dry_run_result = node_client
.runtime_api()
.at_latest()
.await?
.call(subxt_client::apis().revive_api().instantiate(
subxt::utils::AccountId32(origin),
0u128, // value
None, // gas_limit
None, // storage_deposit_limit
subxt_client::src_chain::runtime_types::pallet_revive::primitives::Code::Upload(
bytes.clone(),
),
vec![], // data (constructor args)
None, // salt
))
.await;

assert!(dry_run_result.is_ok(), "Dry-run instantiate failed: {dry_run_result:?}");
let dry_run = dry_run_result.unwrap();
let instantiate_result = dry_run.result.expect("Dry-run should succeed");

log::trace!(
target: LOG_TARGET,
"Dry-run succeeded: address: {:?}, gas_consumed: {:?}, weight_required: {:?}",
instantiate_result.addr,
dry_run.gas_consumed,
dry_run.weight_required
);

// Now submit the actual instantiate extrinsic
let events = node_client
.tx()
.sign_and_submit_then_watch_default(
&subxt_client::tx().revive().instantiate_with_code(
0u128, // value
dry_run.weight_required, // weight_limit from dry-run
u128::MAX, // storage_deposit_limit
bytes, // code
vec![], // data
None, // salt
),
&subxt_signer::sr25519::dev::alice(),
)
.await?
.wait_for_finalized_success()
.await?;

// Extract the contract address from the Instantiated event
let instantiated_event = events
.find_first::<subxt_client::revive::events::Instantiated>()?
.expect("Instantiated event should be present");

let contract_address = instantiated_event.contract;
log::trace!(target: LOG_TARGET, "Contract deployed via Substrate at: {contract_address:?}");

// Verify that the dry-run predicted address matches the actual deployed address
assert_eq!(
instantiate_result.addr, contract_address,
"Dry-run predicted address should match actual deployed address"
);

// Call the deployed contract using runtime API
let call_data = Fibonacci::fibCall { n: 3u64 }.abi_encode();
let call_payload = subxt_client::apis().revive_api().call(
subxt::utils::AccountId32(origin),
contract_address,
0u128, // value
None, // gas_limit
None, // storage_deposit_limit
call_data,
);

let result = node_client.runtime_api().at_latest().await?.call(call_payload).await;

assert!(result.is_ok(), "Contract call failed: {result:?}");
let call_result = result.unwrap();
let exec_result = call_result.result.expect("fib(3) should succeed");

let decoded = Fibonacci::fibCall::abi_decode_returns(&exec_result.data)
.expect("Failed to decode return value");
assert_eq!(decoded, 2u64, "fib(3) should return 2");

Ok(())
}
Loading