Compare commits

...

6 Commits

Author SHA1 Message Date
Cyrill Leutwiler 4cce4a729e pre-release v0.1.0-dev.5 (#110) 2024-10-31 15:22:34 +01:00
Cyrill Leutwiler 9267a2af02 use the long revive version string in the contract metadata (#109) 2024-10-31 14:52:06 +01:00
Cyrill Leutwiler 173ace72cb solidity: rename the revive metadata (#106)
Rename the revive metadata fields and includes the commit hash and LLVM version in the revive version (similar to what solc does).

Signed-off-by: xermicus <cyrill@parity.io>
2024-10-31 13:00:35 +01:00
Cyrill Leutwiler 37ab2b6782 declare immutable globals during in declare (#108)
Signed-off-by: xermicus <cyrill@parity.io>
2024-10-31 12:07:39 +01:00
Cyrill Leutwiler 43d2ef3ce9 implement the code size opcodes (#107) 2024-10-31 11:46:47 +01:00
Cyrill Leutwiler 68564f9866 display the git revision version information (#105)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-10-30 14:28:00 +01:00
20 changed files with 629 additions and 504 deletions
+28
View File
@@ -0,0 +1,28 @@
# Changelog
## Unreleased
## v0.1.0-dev.5
This is development pre-release.
# Added
- Implement the `CODESIZE` and `EXTCODESIZE` opcodes.
# Changed
- Include the full revive version in the contract metadata.
# Fixed
## v0.1.0-dev-4
This is development pre-release.
# Added
- Support the `ORIGIN` opcode.
# Changed
- Update polkavm to `v0.14.0`.
- Enable the `a`, `fast-unaligned-access` and `xtheadcondmov` LLVM target features, decreasing the code size for some contracts.
# Fixed
Generated
+369 -369
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"]
[workspace.package]
version = "0.1.0"
version = "0.1.0-dev.5"
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>",
@@ -14,18 +14,18 @@ repository = "https://github.com/paritytech/revive"
rust-version = "1.80.0"
[workspace.dependencies]
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
revive-common = { version = "0.1.0", path = "crates/common" }
revive-differential = { version = "0.1.0", path = "crates/differential" }
revive-integration = { version = "0.1.0", path = "crates/integration" }
revive-linker = { version = "0.1.0", path = "crates/linker" }
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0", path = "crates/runner" }
revive-solidity = { version = "0.1.0", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0", path = "crates/stdlib" }
revive-benchmarks = { version = "0.1.0-dev.5", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.5", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.5", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.5", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.5", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.5", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.5", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.5", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.5", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.5", path = "crates/runner" }
revive-solidity = { version = "0.1.0-dev.5", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.5", path = "crates/stdlib" }
hex = "0.4"
petgraph = "0.6"
@@ -67,7 +67,7 @@ log = { version = "0.4" }
# polkadot-sdk and friends
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.1", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "db40a66db71e8e7fe943dda5cd0e28078efa2a19" }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "2b6b69641ccff4d7aa9c32051bbb2f1e775ef8cc" }
# llvm
[workspace.dependencies.inkwell]
+11
View File
@@ -0,0 +1,11 @@
# Release checklist
Prior to the first stable release we neither have formal release processes nor do we follow a fixed release schedule.
To create a new pre-release:
1. Merge a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly
2. Push a release tag to `main`
3. Manually trigger the `Build revive-debian` action
4. Create a __pre-release__ from the tag and manually upload the build artifact generated by the action
5. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
+3 -5
View File
@@ -105,9 +105,7 @@ contract ERC20Tester {
ERC20 token = new ERC20();
assert(token.decimals() == 18);
// use call directly when code_size is implemented on pallet-revive
address(token).call(abi.encodeWithSignature("mint(uint256)", 300));
token.mint(300);
assert(token.balanceOf(address(this)) == 300);
token.transfer(BOB, 100);
assert(token.balanceOf(address(this)) == 200);
@@ -119,7 +117,7 @@ contract ERC20Tester {
assert(token.balanceOf(BOB) == 200);
assert(token.balanceOf(address(this)) == 100);
address(token).call(abi.encodeWithSignature("burn(uint256)", 100));
token.burn(100);
assert(token.balanceOf(address(this)) == 0);
}
}
}
+108 -24
View File
@@ -321,6 +321,114 @@ fn ext_code_hash() {
.run();
}
#[test]
fn ext_code_size() {
let alice = Address::from(ALICE.0);
let own_address = alice.create(0);
let baseline_address = alice.create2([0u8; 32], keccak256(Contract::baseline().pvm_runtime));
let own_code_size = U256::from(
Contract::ext_code_size(Default::default())
.pvm_runtime
.len(),
);
let baseline_code_size = U256::from(Contract::baseline().pvm_runtime.len());
Specs {
actions: vec![
// Instantiate the test contract
instantiate("contracts/ExtCode.sol", "ExtCode").remove(0),
// Instantiate the baseline contract
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Solidity {
path: Some("contracts/Baseline.sol".into()),
contract: "Baseline".to_string(),
solc_optimizer: None,
pipeline: None,
},
data: vec![],
salt: OptionalHex::from([0; 32]),
},
// Alice is not a contract and returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(alice).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Unknown address returns a code size of 0
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(Address::from([0xff; 20])).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from([0u8; 32].to_vec()),
gas_consumed: None,
}),
// Own address via extcodesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(own_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Own address via codesize returns own code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::code_size().calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(own_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
// Baseline address returns the baseline code size
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: 0,
gas_limit: None,
storage_deposit_limit: None,
data: Contract::ext_code_size(baseline_address).calldata,
},
VerifyCall(VerifyCallExpectation {
success: true,
output: OptionalHex::from(baseline_code_size.to_be_bytes::<32>().to_vec()),
gas_consumed: None,
}),
],
..Default::default()
}
.run();
}
/*
// These test were implement for the mock-runtime and need to be ported yet.
@@ -349,28 +457,4 @@ fn create2_failure() {
assert_eq!(output.flags, ReturnFlags::Revert);
}
#[test]
fn ext_code_size() {
let contract = Contract::ext_code_size(Transaction::default_address());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::from(contract.pvm_runtime.len());
assert_eq!(received, expected);
let contract = Contract::ext_code_size(Default::default());
let (_, output) = assert_success(&contract, false);
let received = U256::from_be_slice(&output.data);
let expected = U256::ZERO;
assert_eq!(received, expected);
}
#[test]
fn code_size() {
let contract = Contract::code_size();
let (_, output) = assert_success(&contract, false);
let expected = U256::from(contract.pvm_runtime.len());
let received = U256::from_be_slice(&output.data);
assert_eq!(expected, received);
}
*/
@@ -27,18 +27,6 @@ impl Entry {
where
D: Dependency + Clone,
{
context.declare_global(
revive_runtime_api::immutable_data::GLOBAL_IMMUTABLE_DATA_POINTER,
context.word_type().array_type(0),
AddressSpace::Stack,
);
context.declare_global(
revive_runtime_api::immutable_data::GLOBAL_IMMUTABLE_DATA_SIZE,
context.xlen_type(),
AddressSpace::Stack,
);
let calldata_type = context.array_type(context.byte_type(), Self::MAX_CALLDATA_SIZE);
context.set_global(
crate::polkavm::GLOBAL_CALLDATA_POINTER,
@@ -195,6 +183,18 @@ where
Some(inkwell::module::Linkage::External),
)?;
context.declare_global(
revive_runtime_api::immutable_data::GLOBAL_IMMUTABLE_DATA_POINTER,
context.word_type().array_type(0),
AddressSpace::Stack,
);
context.declare_global(
revive_runtime_api::immutable_data::GLOBAL_IMMUTABLE_DATA_SIZE,
context.xlen_type(),
AddressSpace::Stack,
);
Ok(())
}
+14 -30
View File
@@ -1,7 +1,5 @@
//! Translates the external code operations.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
@@ -14,37 +12,23 @@ pub fn size<'ctx, D>(
where
D: Dependency + Clone,
{
let address_pointer = match address {
Some(address) => {
let address_pointer = context.build_alloca(context.word_type(), "value");
context.build_store(address_pointer, address)?;
address_pointer
}
None => context.sentinel_pointer(),
let address = match address {
Some(address) => address,
None => super::context::address(context)?.into_int_value(),
};
let address_pointer_casted = context.builder().build_ptr_to_int(
address_pointer.value,
context.xlen_type(),
"address_pointer",
)?;
let value = context
.build_runtime_call(
revive_runtime_api::polkavm_imports::CODE_SIZE,
&[address_pointer_casted.into()],
)
.unwrap_or_else(|| {
panic!(
"{} should return a value",
revive_runtime_api::polkavm_imports::CODE_SIZE
)
})
.into_int_value();
let address_pointer = context.build_address_argument_store(address)?;
let output_pointer = context.build_alloca_at_entry(context.word_type(), "output_pointer");
Ok(context
.builder()
.build_int_z_extend(value, context.word_type(), "extcodesize")?
.as_basic_value_enum())
context.build_runtime_call(
revive_runtime_api::polkavm_imports::CODE_SIZE,
&[
address_pointer.to_int(context).into(),
output_pointer.to_int(context).into(),
],
);
context.build_load(output_pointer, "code_size")
}
/// Translates the `extcodehash` instruction.
+1 -1
View File
@@ -78,7 +78,7 @@ POLKAVM_IMPORT(void, caller, uint32_t)
POLKAVM_IMPORT(void, chain_id, uint32_t)
POLKAVM_IMPORT(uint32_t, code_size, uint32_t)
POLKAVM_IMPORT(uint32_t, code_size, uint32_t, uint32_t)
POLKAVM_IMPORT(void, code_hash, uint32_t, uint32_t)
+9
View File
@@ -0,0 +1,9 @@
fn main() {
let git_rev = std::process::Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.map(|out| String::from_utf8(out.stdout).unwrap_or_default())
.unwrap_or("unknown".to_owned());
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", git_rev.trim());
}
+4 -8
View File
@@ -8,6 +8,7 @@ use std::path::Path;
use crate::solc::combined_json::CombinedJson;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion;
use self::contract::Contract;
@@ -40,11 +41,7 @@ impl Build {
}
/// Writes all contracts assembly and bytecode to the combined JSON.
pub fn write_to_combined_json(
self,
combined_json: &mut CombinedJson,
resolc_version: &semver::Version,
) -> anyhow::Result<()> {
pub fn write_to_combined_json(self, combined_json: &mut CombinedJson) -> anyhow::Result<()> {
for (path, contract) in self.contracts.into_iter() {
let combined_json_contract = combined_json
.contracts
@@ -61,7 +58,7 @@ impl Build {
contract.write_to_combined_json(combined_json_contract)?;
}
combined_json.zk_version = Some(resolc_version.to_string());
combined_json.revive_version = Some(ResolcVersion::default().long);
Ok(())
}
@@ -71,7 +68,6 @@ impl Build {
mut self,
standard_json: &mut StandardJsonOutput,
solc_version: &SolcVersion,
resolc_version: &semver::Version,
) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() {
Some(contracts) => contracts,
@@ -90,7 +86,7 @@ impl Build {
standard_json.version = Some(solc_version.default.to_string());
standard_json.long_version = Some(solc_version.long.to_owned());
standard_json.zk_version = Some(resolc_version.to_string());
standard_json.revive_version = Some(ResolcVersion::default().long);
Ok(())
}
+5 -10
View File
@@ -7,6 +7,7 @@ pub(crate) mod missing_libraries;
pub(crate) mod process;
pub(crate) mod project;
pub(crate) mod solc;
pub(crate) mod version;
pub(crate) mod warning;
pub(crate) mod yul;
@@ -38,6 +39,7 @@ pub use self::solc::standard_json::output::contract::Contract as SolcStandardJso
pub use self::solc::standard_json::output::Output as SolcStandardJsonOutput;
pub use self::solc::version::Version as SolcVersion;
pub use self::solc::Compiler as SolcCompiler;
pub use self::version::Version as ResolcVersion;
pub use self::warning::Warning;
pub mod test_utils;
@@ -197,7 +199,6 @@ pub fn standard_json(
) -> anyhow::Result<()> {
let solc_version = solc.version()?;
let solc_pipeline = SolcPipeline::new(&solc_version, force_evmla);
let resolc_version = semver::Version::parse(env!("CARGO_PKG_VERSION")).expect("Always valid");
let solc_input = SolcStandardJsonInput::try_from_stdin(solc_pipeline)?;
let source_code_files = solc_input
@@ -244,14 +245,10 @@ pub fn standard_json(
if detect_missing_libraries {
let missing_libraries = project.get_missing_libraries();
missing_libraries.write_to_standard_json(
&mut solc_output,
&solc_version,
&resolc_version,
)?;
missing_libraries.write_to_standard_json(&mut solc_output, &solc_version)?;
} else {
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?;
build.write_to_standard_json(&mut solc_output, &solc_version, &resolc_version)?;
build.write_to_standard_json(&mut solc_output, &solc_version)?;
}
serde_json::to_writer(std::io::stdout(), &solc_output)?;
std::process::exit(0);
@@ -278,8 +275,6 @@ pub fn combined_json(
output_directory: Option<PathBuf>,
overwrite: bool,
) -> anyhow::Result<()> {
let resolc_version = semver::Version::parse(env!("CARGO_PKG_VERSION")).expect("Always valid");
let build = standard_output(
input_files,
libraries,
@@ -298,7 +293,7 @@ pub fn combined_json(
)?;
let mut combined_json = solc.combined_json(input_files, format.as_str())?;
build.write_to_combined_json(&mut combined_json, &resolc_version)?;
build.write_to_combined_json(&mut combined_json)?;
match output_directory {
Some(output_directory) => {
+2 -2
View File
@@ -5,6 +5,7 @@ use std::collections::HashSet;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion;
/// The missing Solidity libraries.
pub struct MissingLibraries {
@@ -23,7 +24,6 @@ impl MissingLibraries {
mut self,
standard_json: &mut StandardJsonOutput,
solc_version: &SolcVersion,
resolc_version: &semver::Version,
) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() {
Some(contracts) => contracts,
@@ -43,7 +43,7 @@ impl MissingLibraries {
standard_json.version = Some(solc_version.default.to_string());
standard_json.long_version = Some(solc_version.long.to_owned());
standard_json.zk_version = Some(resolc_version.to_string());
standard_json.revive_version = Some(ResolcVersion::default().long);
Ok(())
}
@@ -2,6 +2,8 @@
use serde::Serialize;
use crate::ResolcVersion;
/// The Solidity contract metadata.
/// Is used to append the metadata hash to the contract bytecode.
#[derive(Debug, Serialize)]
@@ -9,11 +11,11 @@ pub struct Metadata {
/// The `solc` metadata.
pub solc_metadata: serde_json::Value,
/// The `solc` version.
pub solc_version: semver::Version,
/// The zkVM `solc` edition.
pub solc_zkvm_edition: Option<semver::Version>,
pub solc_version: String,
/// The pallet revive edition.
pub revive_pallet_version: Option<semver::Version>,
/// The PolkaVM compiler version.
pub zk_version: semver::Version,
pub revive_version: String,
/// The PolkaVM compiler optimizer settings.
pub optimizer_settings: revive_llvm_context::OptimizerSettings,
}
@@ -22,16 +24,15 @@ impl Metadata {
/// A shortcut constructor.
pub fn new(
solc_metadata: serde_json::Value,
solc_version: semver::Version,
solc_zkvm_edition: Option<semver::Version>,
zk_version: semver::Version,
solc_version: String,
revive_pallet_version: Option<semver::Version>,
optimizer_settings: revive_llvm_context::OptimizerSettings,
) -> Self {
Self {
solc_metadata,
solc_version,
solc_zkvm_edition,
zk_version,
revive_pallet_version,
revive_version: ResolcVersion::default().long,
optimizer_settings,
}
}
+1 -2
View File
@@ -89,9 +89,8 @@ impl Contract {
let metadata = Metadata::new(
self.metadata_json.take(),
version.default.clone(),
version.long.clone(),
version.l2_revision.clone(),
semver::Version::parse(env!("CARGO_PKG_VERSION")).expect("Always valid"),
optimizer.settings().to_owned(),
);
let metadata_json = serde_json::to_value(&metadata).expect("Always valid");
+2 -3
View File
@@ -31,10 +31,9 @@ fn main_inner() -> anyhow::Result<()> {
if arguments.version {
println!(
"{} v{} (LLVM build {:?})",
"{} version {}",
env!("CARGO_PKG_DESCRIPTION"),
env!("CARGO_PKG_VERSION"),
inkwell::support::get_llvm_version()
revive_solidity::ResolcVersion::default().long
);
return Ok(());
}
@@ -28,7 +28,7 @@ pub struct CombinedJson {
pub version: String,
/// The `resolc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub zk_version: Option<String>,
pub revive_version: Option<String>,
}
impl CombinedJson {
@@ -45,7 +45,7 @@ pub struct Output {
pub long_version: Option<String>,
/// The `resolc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub zk_version: Option<String>,
pub revive_version: Option<String>,
}
impl Output {
+4 -13
View File
@@ -3,7 +3,6 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Mutex;
use once_cell::sync::Lazy;
@@ -106,11 +105,7 @@ pub fn build_solidity_with_options(
let project = output.try_to_project(sources, libraries, pipeline, &solc_version, None)?;
let build: crate::Build = project.compile(optimizer_settings, false, None)?;
build.write_to_standard_json(
&mut output,
&solc_version,
&semver::Version::from_str(env!("CARGO_PKG_VERSION"))?,
)?;
build.write_to_standard_json(&mut output, &solc_version)?;
Ok(output)
}
@@ -202,11 +197,7 @@ pub fn build_solidity_and_detect_missing_libraries(
let project = output.try_to_project(sources, libraries, pipeline, &solc_version, None)?;
let missing_libraries = project.get_missing_libraries();
missing_libraries.write_to_standard_json(
&mut output,
&solc.version()?,
&semver::Version::from_str(env!("CARGO_PKG_VERSION"))?,
)?;
missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?;
Ok(output)
}
@@ -232,14 +223,14 @@ pub fn check_solidity_warning(
warning_substring: &str,
libraries: BTreeMap<String, BTreeMap<String, String>>,
pipeline: SolcPipeline,
skip_for_zkvm_edition: bool,
skip_for_revive_edition: bool,
suppressed_warnings: Option<Vec<Warning>>,
) -> anyhow::Result<bool> {
check_dependencies();
let mut solc = SolcCompiler::new(SolcCompiler::DEFAULT_EXECUTABLE_NAME.to_owned())?;
let solc_version = solc.version()?;
if skip_for_zkvm_edition && solc_version.l2_revision.is_some() {
if skip_for_revive_edition && solc_version.l2_revision.is_some() {
return Ok(true);
}
+30
View File
@@ -0,0 +1,30 @@
//! The resolc compiler version.
use serde::Deserialize;
use serde::Serialize;
/// The resolc compiler version.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Version {
/// The long version string.
pub long: String,
/// The short `semver`.
pub default: semver::Version,
/// The LLVM version string.
pub llvm: semver::Version,
}
impl Default for Version {
fn default() -> Self {
let default = semver::Version::parse(env!("CARGO_PKG_VERSION")).expect("Always valid");
let commit = env!("GIT_COMMIT_HASH");
let (llvm_major, llvm_minor, llvm_patch) = inkwell::support::get_llvm_version();
let llvm = semver::Version::new(llvm_major as u64, llvm_minor as u64, llvm_patch as u64);
Self {
long: format!("{default}+commit.{commit}.llvm-{llvm}"),
default,
llvm,
}
}
}