Skip to content

Commit

Permalink
Merge branch 'main' into budget_model
Browse files Browse the repository at this point in the history
  • Loading branch information
jayz22 authored Sep 6, 2024
2 parents 6f2b26f + a79b3cf commit b0027b1
Show file tree
Hide file tree
Showing 17 changed files with 173 additions and 71 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- run: rustup update
- uses: stellar/binaries@v24
- uses: stellar/binaries@v29
with:
name: cargo-semver-checks
version: 0.32.0
version: 0.35.0
- run: cargo semver-checks --exclude soroban-simulation

build-and-test:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ wasmparser = "=0.116.1"
[workspace.dependencies.stellar-xdr]
version = "=22.0.0"
git = "https://github.com/stellar/rs-stellar-xdr"
rev = "550743b50cd3ca5a63f03f9d7175b4cfdfd9c4ac"
rev = "39d7dbb0c12bd422ee43a6e2e3277789da4eaac8"
default-features = false

[workspace.dependencies.wasmi]
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ macro_rules! tracy_span {
pub struct Version<'a> {
pub pkg: &'a str,
pub rev: &'a str,
pub interface: u64,
pub interface: xdr::ScEnvMetaEntryInterfaceVersion,
pub xdr: stellar_xdr::Version<'a>,
}

Expand Down
30 changes: 9 additions & 21 deletions soroban-env-common/src/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
//! [Env](crate::Env) interface provided by the host, rather than a cryptic failure
//! due to a runtime host function signature mismatch.
// Currently the only constant is `INTERFACE_VERSION` which is a u64 with a low
// and high component. The low component is a pre-release version which should
// be zero any time you make a real release, and the high component is the
// ledger version / protocol version (the two terms are used interchangably in
// the stellar codebase), which should both match the major release version of
// soroban and the major release version of stellar-core that it's embedded
// within.
// Currently the only constant is `INTERFACE_VERSION` which is a struct
// containing a 32-bit protocol version and 32-bit pre-release version. The
// pre-release version should be zero any time you make a real release, and the
// protocol version is the ledger version / protocol version (the two terms are
// used interchangably in the stellar codebase), which should both match the
// major release version of soroban and the major release version of
// stellar-core that it's embedded within.
//
// Protocol numbers will be checked for ordered compatibility (a host will only
// run contracts built for same-or-older protocol versions than its own) whereas
Expand All @@ -38,6 +38,8 @@
// nonzero pre-release number can be used to force recompiles on interface
// changes.

use crate::xdr::ScEnvMetaEntryInterfaceVersion;

pub const ENV_META_V0_SECTION_NAME: &str = "contractenvmetav0";

// If the "next" feature is enabled, we're building from the "next" xdr
Expand All @@ -60,17 +62,3 @@ soroban_env_macros::generate_env_meta_consts!(
ledger_protocol_version: 22,
pre_release_version: 0,
);

pub const fn make_interface_version(protocol_version: u32, pre_release_version: u32) -> u64 {
((protocol_version as u64) << 32) | (pre_release_version as u64)
}

pub const fn get_ledger_protocol_version(interface_version: u64) -> u32 {
// The ledger protocol version is the high 32 bits of INTERFACE_VERSION
(interface_version >> 32) as u32
}

pub const fn get_pre_release_version(interface_version: u64) -> u32 {
// The pre-release version is the low 32 bits of INTERFACE_VERSION
interface_version as u32
}
2 changes: 1 addition & 1 deletion soroban-env-common/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl core::fmt::Display for SymbolError {
"symbol too long: length {len}, max {MAX_SMALL_CHARS}"
)),
SymbolError::BadChar(char) => f.write_fmt(format_args!(
"symbol bad char: encountered {char}, supported range [a-zA-Z0-9_]"
"symbol bad char: encountered `{char}`, supported range [a-zA-Z0-9_]"
)),
SymbolError::MalformedSmall => f.write_str("malformed small symbol"),
}
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ p256 = {version = "0.13.2", default-features = false, features = ["alloc"]}
[dev-dependencies.stellar-xdr]
version = "=22.0.0"
git = "https://github.com/stellar/rs-stellar-xdr"
rev = "550743b50cd3ca5a63f03f9d7175b4cfdfd9c4ac"
rev = "39d7dbb0c12bd422ee43a6e2e3277789da4eaac8"
default-features = false
features = ["arbitrary"]

Expand Down
2 changes: 1 addition & 1 deletion soroban-env-host/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ impl Host {
&[proto.into()],
));
}
if proto > meta::get_ledger_protocol_version(meta::INTERFACE_VERSION) {
if proto > meta::INTERFACE_VERSION.protocol {
return Err(self.err(
ScErrorType::Context,
ScErrorCode::InternalError,
Expand Down
115 changes: 109 additions & 6 deletions soroban-env-host/src/test/hostile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,8 +751,7 @@ fn test_integer_overflow() -> Result<(), HostError> {

#[test]
fn test_corrupt_custom_section() -> Result<(), HostError> {
use crate::meta::make_interface_version;
use crate::xdr::{Limits, ScEnvMetaEntry, WriteXdr};
use crate::xdr::{Limits, ScEnvMetaEntry, ScEnvMetaEntryInterfaceVersion, WriteXdr};

let host = observe_host!(Host::test_host_with_recording_footprint());
host.enable_debug()?;
Expand Down Expand Up @@ -781,9 +780,12 @@ fn test_corrupt_custom_section() -> Result<(), HostError> {
));

// invalid section name
let xdr = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(make_interface_version(20, 0))
.to_xdr(Limits::none())
.unwrap();
let xdr = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(ScEnvMetaEntryInterfaceVersion {
protocol: 20,
pre_release: 0,
})
.to_xdr(Limits::none())
.unwrap();
let res = host.register_test_contract_wasm_from_source_account(
wasm_util::wasm_module_with_custom_section("contractenvmetav1", &xdr).as_slice(),
generate_account_id(&host),
Expand Down Expand Up @@ -828,7 +830,7 @@ fn test_corrupt_custom_section() -> Result<(), HostError> {
));

// invalid: protocol is current but pre-release version doesn't match env's
let env_pre = meta::get_pre_release_version(meta::INTERFACE_VERSION);
let env_pre = meta::INTERFACE_VERSION.pre_release;
let res = host.register_test_contract_wasm_from_source_account(
wasm_util::wasm_module_with_custom_section(
"contractenvmetav0",
Expand Down Expand Up @@ -1320,3 +1322,104 @@ fn test_stack_depth_stability() {
(ScErrorType::Budget, ScErrorCode::ExceededLimit)
));
}

#[test]
fn test_misc_hostile_wasms() {
// This test loads and runs a bunch of hostile WASM modules
// found in the hostile_inputs subdirectory. It attempts to
// instantiate the contract and then run a 0-ary function in
// the contract called "test".
let mut bad_inputs = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
bad_inputs.push("src/test/hostile_inputs");
eprintln!("loading hostile inputs from {:?}", bad_inputs);
let mut n_wasms = 0;
let mut n_instantiated_ok = 0;
let mut n_instantiated_external_error = 0;
let mut n_instantiated_internal_error = 0;
let mut n_executed_ok = 0;
let mut n_executed_external_error = 0;
let mut n_executed_internal_error = 0;

for entry in std::fs::read_dir(bad_inputs).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.extension().unwrap() == "wasm" {
let host = Host::test_host_with_recording_footprint();
let filename = path.file_name().unwrap().to_str().unwrap().to_string();
let wasm_code = std::fs::read(path).unwrap();
eprintln!("loaded {}-byte wasm {}", wasm_code.len(), filename);
n_wasms += 1;
host.as_budget().reset_unlimited().unwrap();
let addr_res = host.register_test_contract_wasm_from_source_account(
&wasm_code,
generate_account_id(&host),
generate_bytes_array(&host),
);
match addr_res {
Err(e) => {
if e.error.is_code(ScErrorCode::InternalError) {
eprintln!(
"instantiation failed with internal error for {}: {:?}",
filename, e
);
n_instantiated_internal_error += 1;
} else {
eprintln!(
"instantiation failed with external error for {}: {:?}",
filename, e
);
n_instantiated_external_error += 1;
}
continue;
}
Ok(contract_id) => {
n_instantiated_ok += 1;
let call_res = host.call(
contract_id,
Symbol::try_from_small_str("test").unwrap(),
test_vec![&host].into(),
);
if let Err(e) = call_res {
if e.error.is_code(ScErrorCode::InternalError) {
eprintln!(
"execution failed with internal error for {}: {:?}",
filename, e
);
n_executed_internal_error += 1;
} else {
eprintln!(
"execution failed with external error for {}: {:?}",
filename, e
);
n_executed_external_error += 1;
}
} else {
n_executed_ok += 1;
eprintln!("execution succeeded for {}", filename);
}
}
}
}
}
eprintln!("loaded {} hostile Wasm modules", n_wasms);
eprintln!("instantiated {} contracts successfully", n_instantiated_ok);
eprintln!(
"instantiation failed with external error for {} contracts",
n_instantiated_external_error
);
eprintln!(
"instantiation failed with internal error for {} contracts",
n_instantiated_internal_error
);
eprintln!("executed {} contracts successfully", n_executed_ok);
eprintln!(
"execution failed with external error for {} contracts",
n_executed_external_error
);
eprintln!(
"execution failed with internal error for {} contracts",
n_executed_internal_error
);
assert_eq!(n_instantiated_internal_error, 0);
assert_eq!(n_executed_internal_error, 0);
}
Binary file not shown.
Binary file added soroban-env-host/src/test/hostile_inputs/smoke.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion soroban-env-host/src/test/metering_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::testutils::{generate_account_id, generate_bytes_array};
// RUST_TEST_THREADS=1 cargo test --release --package soroban-env-host --lib --features testutils -- test::metering_benchmark --nocapture --ignored

const LEDGER_INFO: LedgerInfo = LedgerInfo {
protocol_version: crate::meta::get_ledger_protocol_version(crate::meta::INTERFACE_VERSION),
protocol_version: crate::meta::INTERFACE_VERSION.protocol,
sequence_number: 1234,
timestamp: 1234,
network_id: [7; 32],
Expand Down
4 changes: 2 additions & 2 deletions soroban-env-host/src/test/protocol_gate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
meta::{get_ledger_protocol_version, INTERFACE_VERSION},
meta::INTERFACE_VERSION,
testutils::{generate_account_id, generate_bytes_array, wasm as wasm_util},
xdr::{ScErrorCode, ScErrorType},
AddressObject, Env, Host, HostError, LedgerInfo, Symbol, Val, WasmiMarshal,
Expand All @@ -9,7 +9,7 @@ use crate::{
fn ledger_protocol_greater_than_env_protocol_should_fail() -> Result<(), HostError> {
let host = Host::test_host_with_recording_footprint();
host.enable_debug()?;
let env_proto = get_ledger_protocol_version(INTERFACE_VERSION);
let env_proto = INTERFACE_VERSION.protocol;

// This test only makes sense if TEST_PROTOCOL is equal to the env version
if env_proto != host.get_ledger_protocol_version()? {
Expand Down
11 changes: 6 additions & 5 deletions soroban-env-host/src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ impl SnapshotSource for MockSnapshotSource {

#[cfg(test)]
pub(crate) fn interface_meta_with_custom_versions(proto: u32, pre: u32) -> Vec<u8> {
use crate::xdr::{Limited, Limits, ScEnvMetaEntry, WriteXdr};
let iv = crate::meta::make_interface_version(proto, pre);
let entry = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(iv);
use crate::xdr::{Limited, Limits, ScEnvMetaEntry, ScEnvMetaEntryInterfaceVersion, WriteXdr};
let entry = ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(ScEnvMetaEntryInterfaceVersion {
protocol: proto,
pre_release: pre,
});
let bytes = Vec::<u8>::new();
let mut w = Limited::new(bytes, Limits::none());
entry.write_xdr(&mut w).unwrap();
Expand All @@ -163,8 +165,7 @@ impl Host {
}

pub fn current_test_protocol() -> u32 {
use crate::meta::{get_ledger_protocol_version, INTERFACE_VERSION};
let max_supported_protocol = get_ledger_protocol_version(INTERFACE_VERSION);
let max_supported_protocol = crate::meta::INTERFACE_VERSION.protocol;
let min_supported_protocol = crate::host::MIN_LEDGER_PROTOCOL_VERSION;
if let Ok(vers) = std::env::var("TEST_PROTOCOL") {
let test_protocol = vers.parse().expect("parsing TEST_PROTOCOL");
Expand Down
26 changes: 16 additions & 10 deletions soroban-env-host/src/vm/parsed_module.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::{
err,
host::metered_clone::MeteredContainer,
meta::{self, get_ledger_protocol_version},
xdr::{ContractCostType, Limited, ReadXdr, ScEnvMetaEntry, ScErrorCode, ScErrorType},
meta,
xdr::{
ContractCostType, Limited, ReadXdr, ScEnvMetaEntry, ScEnvMetaEntryInterfaceVersion,
ScErrorCode, ScErrorType,
},
Host, HostError, DEFAULT_XDR_RW_LIMITS,
};

Expand Down Expand Up @@ -219,18 +222,18 @@ impl ParsedModule {

Self::check_max_args(host, &module)?;
let interface_version = Self::check_meta_section(host, &module)?;
let contract_proto = get_ledger_protocol_version(interface_version);
let contract_proto = interface_version.protocol;

Ok((module, contract_proto))
}

fn check_contract_interface_version(
host: &Host,
interface_version: u64,
interface_version: &ScEnvMetaEntryInterfaceVersion,
) -> Result<(), HostError> {
let want_proto = {
let ledger_proto = host.get_ledger_protocol_version()?;
let env_proto = get_ledger_protocol_version(meta::INTERFACE_VERSION);
let env_proto = meta::INTERFACE_VERSION.protocol;
if ledger_proto <= env_proto {
// ledger proto should be before or equal to env proto
ledger_proto
Expand All @@ -247,9 +250,9 @@ impl ParsedModule {

// Not used when "next" is enabled
#[cfg(not(feature = "next"))]
let got_pre = meta::get_pre_release_version(interface_version);
let got_pre = interface_version.pre_release;

let got_proto = get_ledger_protocol_version(interface_version);
let got_proto = interface_version.protocol;

if got_proto < want_proto {
// Old protocols are finalized, we only support contracts
Expand Down Expand Up @@ -277,7 +280,7 @@ impl ParsedModule {
{
// Current protocol might have a nonzero prerelease number; we will
// allow it only if it matches the current prerelease exactly.
let want_pre = meta::get_pre_release_version(meta::INTERFACE_VERSION);
let want_pre = meta::INTERFACE_VERSION.pre_release;
if want_pre != got_pre {
return Err(err!(
host,
Expand Down Expand Up @@ -321,15 +324,18 @@ impl ParsedModule {
Self::module_custom_section(&self.module, name)
}

fn check_meta_section(host: &Host, m: &Module) -> Result<u64, HostError> {
fn check_meta_section(
host: &Host,
m: &Module,
) -> Result<ScEnvMetaEntryInterfaceVersion, HostError> {
if let Some(env_meta) = Self::module_custom_section(m, meta::ENV_META_V0_SECTION_NAME) {
let mut limits = DEFAULT_XDR_RW_LIMITS;
limits.len = env_meta.len();
let mut cursor = Limited::new(Cursor::new(env_meta), limits);
if let Some(env_meta_entry) = ScEnvMetaEntry::read_xdr_iter(&mut cursor).next() {
let ScEnvMetaEntry::ScEnvMetaKindInterfaceVersion(v) =
host.map_err(env_meta_entry)?;
Self::check_contract_interface_version(host, v)?;
Self::check_contract_interface_version(host, &v)?;
Ok(v)
} else {
Err(host.err(
Expand Down
Loading

0 comments on commit b0027b1

Please sign in to comment.