Skip to content

Commit

Permalink
Merge pull request #2129 from CosmWasm/aw/read-version-inside-parsedwasm
Browse files Browse the repository at this point in the history
Parse the contract state version from the custom section
  • Loading branch information
aumetra authored Apr 25, 2024
2 parents ab31374 + 693610f commit 97b4efa
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ and this project adheres to
([#2120])
- cosmwasm-derive: Add `state_version` attribute for `migrate` entrypoints
([#2124])
- cosmwasm-vm: Read the state version from Wasm modules and return them as part
of `AnalyzeReport` ([#2129])

[#1983]: https://github.com/CosmWasm/cosmwasm/pull/1983
[#2057]: https://github.com/CosmWasm/cosmwasm/pull/2057
Expand All @@ -47,6 +49,7 @@ and this project adheres to
[#2107]: https://github.com/CosmWasm/cosmwasm/pull/2107
[#2120]: https://github.com/CosmWasm/cosmwasm/pull/2120
[#2124]: https://github.com/CosmWasm/cosmwasm/pull/2124
[#2129]: https://github.com/CosmWasm/cosmwasm/pull/2129

### Changed

Expand Down
12 changes: 11 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions packages/vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ hex-literal = "0.4.1"
rand = "0.8"
tempfile = "3.1.0"
wat = "1.0"
wasm-encoder = "0.205.0"
clap = "4"
leb128 = "0.2"
target-lexicon = "0.12"
Expand Down
28 changes: 28 additions & 0 deletions packages/vm/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub struct Cache<A: BackendApi, S: Storage, Q: Querier> {
}

#[derive(PartialEq, Eq, Debug)]
#[non_exhaustive]
pub struct AnalysisReport {
/// `true` if and only if all [`REQUIRED_IBC_EXPORTS`] exist as exported functions.
/// This does not guarantee they are functional or even have the correct signatures.
Expand All @@ -132,6 +133,8 @@ pub struct AnalysisReport {
pub entrypoints: BTreeSet<Entrypoint>,
/// The set of capabilities the contract requires.
pub required_capabilities: BTreeSet<String>,
/// The contract state version exported set by the contract developer
pub contract_state_version: Option<u64>,
}

impl<A, S, Q> Cache<A, S, Q>
Expand Down Expand Up @@ -320,6 +323,7 @@ where
required_capabilities: required_capabilities_from_module(&module)
.into_iter()
.collect(),
contract_state_version: module.contract_state_version,
})
}

Expand Down Expand Up @@ -582,8 +586,10 @@ mod tests {
use crate::capabilities::capabilities_from_csv;
use crate::testing::{mock_backend, mock_env, mock_info, MockApi, MockQuerier, MockStorage};
use cosmwasm_std::{coins, Empty};
use std::borrow::Cow;
use std::fs::{create_dir_all, remove_dir_all};
use tempfile::TempDir;
use wasm_encoder::ComponentSection;

const TESTING_GAS_LIMIT: u64 = 500_000_000; // ~0.5ms
const TESTING_MEMORY_LIMIT: Size = Size::mebi(16);
Expand Down Expand Up @@ -1410,6 +1416,7 @@ mod tests {
E::Query
]),
required_capabilities: BTreeSet::new(),
contract_state_version: None,
}
);

Expand All @@ -1427,6 +1434,7 @@ mod tests {
"iterator".to_string(),
"stargate".to_string()
]),
contract_state_version: None,
}
);

Expand All @@ -1438,6 +1446,26 @@ mod tests {
has_ibc_entry_points: false,
entrypoints: BTreeSet::new(),
required_capabilities: BTreeSet::from(["iterator".to_string()]),
contract_state_version: None,
}
);

let mut wasm_with_version = EMPTY_CONTRACT.to_vec();
let custom_section = wasm_encoder::CustomSection {
name: Cow::Borrowed("cw_state_version"),
data: Cow::Borrowed(b"21"),
};
custom_section.append_to_component(&mut wasm_with_version);

let checksum4 = cache.save_wasm(&wasm_with_version).unwrap();
let report4 = cache.analyze(&checksum4).unwrap();
assert_eq!(
report4,
AnalysisReport {
has_ibc_entry_points: false,
entrypoints: BTreeSet::new(),
required_capabilities: BTreeSet::from(["iterator".to_string()]),
contract_state_version: Some(21),
}
);
}
Expand Down
37 changes: 36 additions & 1 deletion packages/vm/src/parsed_wasm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt, mem};
use std::{fmt, mem, str};

use wasmer::wasmparser::{
BinaryReaderError, CompositeType, Export, FuncToValidate, FunctionBody, Import, MemoryType,
Expand Down Expand Up @@ -66,6 +66,8 @@ pub struct ParsedWasm<'a> {
pub total_func_params: usize,
/// Collections of functions that are potentially pending validation
pub func_validator: FunctionValidator<'a>,
/// Contract state version as defined in a custom section
pub contract_state_version: Option<u64>,
}

impl<'a> ParsedWasm<'a> {
Expand Down Expand Up @@ -108,6 +110,7 @@ impl<'a> ParsedWasm<'a> {
max_func_results: 0,
total_func_params: 0,
func_validator: FunctionValidator::Pending(OpaqueDebug::default()),
contract_state_version: None,
};

for p in Parser::new(0).parse_all(wasm) {
Expand Down Expand Up @@ -179,6 +182,17 @@ impl<'a> ParsedWasm<'a> {
Payload::ExportSection(e) => {
this.exports = e.into_iter().collect::<Result<Vec<_>, _>>()?;
}
Payload::CustomSection(reader) if reader.name() == "cw_state_version" => {
// This is supposed to be valid UTF-8
let raw_version = str::from_utf8(reader.data())
.map_err(|err| VmError::static_validation_err(err.to_string()))?;

this.contract_state_version = Some(
raw_version
.parse::<u64>()
.map_err(|err| VmError::static_validation_err(err.to_string()))?,
);
}
_ => {} // ignore everything else
}
}
Expand Down Expand Up @@ -214,3 +228,24 @@ impl<'a> ParsedWasm<'a> {
}
}
}

#[cfg(test)]
mod test {
use super::ParsedWasm;

#[test]
fn read_state_version() {
let wasm_data =
wat::parse_str(r#"( module ( @custom "cw_state_version" "42" ) )"#).unwrap();
let parsed = ParsedWasm::parse(&wasm_data).unwrap();

assert_eq!(parsed.contract_state_version, Some(42));
}

#[test]
fn read_state_version_fails() {
let wasm_data =
wat::parse_str(r#"( module ( @custom "cw_state_version" "not a number" ) )"#).unwrap();
assert!(ParsedWasm::parse(&wasm_data).is_err());
}
}

0 comments on commit 97b4efa

Please sign in to comment.