Skip to content

Commit

Permalink
Add contract compression. (#44)
Browse files Browse the repository at this point in the history
* Add contract compression.

* Move things around

* Update readme.
  • Loading branch information
saeed-zil authored Mar 13, 2024
1 parent e891f63 commit f140e12
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 9 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ Ok(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })
Contract address: ZilAddress("0xC50C93831F6eAB4e4F011076dca6e887288cc872")
```
Instead of `deploy`, you can use `deploy_compressed` if you like to deploy a compressed version of the contract.
### Getting contract states
Our contract has `owner`, an immutable state, and `welcome_msg`, a mutable one. We can get these states by calling the corresponding functions:
```rust,ignore
Expand Down
12 changes: 11 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,17 @@ impl<T: Middleware> {contract_name}<T> {{
{contract_deployment_params_for_init}
]);
Ok(Self::new(factory.deploy_from_file(&std::path::PathBuf::from({contract_path:?}), init, None).await?))
Ok(Self::new(factory.deploy_from_file(&std::path::PathBuf::from({contract_path:?}), init, None, false).await?))
}}
pub async fn deploy_compressed(client: Arc<T> {contract_deployment_params}) -> Result<Self, Error> {{
let factory = ContractFactory::new(client.clone());
let init = Init(vec![
ScillaVariable::new("_scilla_version".to_string(), "Uint32".to_string(), "0".to_value()),
{contract_deployment_params_for_init}
]);
Ok(Self::new(factory.deploy_from_file(&std::path::PathBuf::from({contract_path:?}), init, None, true).await?))
}}
pub fn address(&self) -> &ZilAddress {{
Expand Down
15 changes: 12 additions & 3 deletions src/contract/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
Error,
};

use super::{BaseContract, Init};
use super::{compress_contract, BaseContract, Init};

pub struct Factory<T: Middleware> {
client: Arc<T>,
Expand All @@ -32,6 +32,7 @@ impl<T: Middleware> Factory<T> {
/// * `overridden_params`: `overridden_params` is an optional parameter of type `TransactionParams`. It
/// allows you to override the default transaction parameters when deploying the contract. If you don't
/// want to override any parameters, you can pass `None` as the value for this parameter.
/// * `do_contract_compression`: Set it to true if you want your contract gets compressed before deployment.
///
/// Returns:
///
Expand All @@ -58,7 +59,7 @@ impl<T: Middleware> Factory<T> {
///
/// let factory = ContractFactory::new(provider.into());
/// let init = Init(vec![ScillaVariable::new_from_str("_scilla_version", "Uint32", "0")]);
/// let contract = factory.deploy_from_file(&PathBuf::from("./tests/contracts/Timestamp.scilla"), init, None).await?;
/// let contract = factory.deploy_from_file(&PathBuf::from("./tests/contracts/Timestamp.scilla"), init, None, false).await?;
/// println!("addr: {:?}", contract);
/// Ok(())
/// }
Expand All @@ -68,8 +69,16 @@ impl<T: Middleware> Factory<T> {
path: &Path,
init: Init,
overridden_params: Option<TransactionParams>,
do_contract_compression: bool,
) -> Result<BaseContract<T>, Error> {
let contract_code = std::fs::read_to_string(path)?;
let contract_code = {
let code = std::fs::read_to_string(path)?;
if do_contract_compression {
compress_contract(&code)?
} else {
code
}
};
self.deploy_str(contract_code, init, overridden_params).await
}

Expand Down
85 changes: 85 additions & 0 deletions src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ async fn main() -> anyhow::Result<()> {
}
```
Instead of `deploy`, you can use `deploy_compressed` if you like to deploy a compressed version of the contract.
Alternatively, If the contract is already deployed and you have its address, it's possible to create a new instance of the target contract by calling `attach` function:
```
use std::sync::Arc;
Expand Down Expand Up @@ -253,6 +255,7 @@ pub mod transition_call;
use std::{ops::Deref, str::FromStr, sync::Arc};

pub use factory::Factory as ContractFactory;
use regex::Regex;
pub use scilla_value::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value as JsonValue;
Expand Down Expand Up @@ -351,4 +354,86 @@ impl<T: Middleware> BaseContract<T> {
}
}

pub fn compress_contract(code: &str) -> Result<String, Error> {
let remove_comments_regex = Regex::new(r"\(\*.*?\*\)")?;
let replace_whitespace_regex = Regex::new(r"(?m)(^[ \t]*\r?\n)|([ \t]+$)")?;
let code = remove_comments_regex.replace_all(code, "");
let code = replace_whitespace_regex.replace_all(&code, "").to_string();
Ok(code)
}

#[cfg(test)]
mod tests {
use crate::contract::compress_contract;

#[test]
fn compression_1_works() {
let code = r#"(***************************************************)
(* The contract definition *)
(***************************************************)
contract HelloWorld
(owner: ByStr20)"#;
let compressed = compress_contract(code).unwrap();
assert_eq!(
&compressed,
r#"contract HelloWorld
(owner: ByStr20)"#
);
}

#[test]
fn compression_2_works() {
let code = r#"(*something*)contract HelloWorld
(owner: ByStr20)"#;
let compressed = compress_contract(code).unwrap();
assert_eq!(
&compressed,
r#"contract HelloWorld
(owner: ByStr20)"#
);
}

#[test]
fn compression_3_works() {
let code = r#"contract HelloWorld (* a dummy comment*)
(owner: ByStr20)"#;
let compressed = compress_contract(code).unwrap();
assert_eq!(
&compressed,
r#"contract HelloWorld
(owner: ByStr20)"#
);
}

#[test]
fn compression_4_works() {
let code = r#"contract WithComment (*contract name*)
()
(*fields*)
field welcome_msg : String = "" (*welcome*) (*another comment*) "#;
let compressed = compress_contract(code).unwrap();
assert_eq!(
&compressed,
r#"contract WithComment
()
field welcome_msg : String = """#
);
}
}

/*
it("#4", async function () {
const code = `contract WithComment (*contract name*)
()
(*fields*)
field welcome_msg : String = "" (*welcome*) (*another comment*) `;
const compressed = compressContract(code);
expect(compressed).to.be.eq(`contract WithComment
()
field welcome_msg : String = ""`);
});
});
*/

include!(concat!(env!("OUT_DIR"), "/scilla_contracts.rs"));
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,7 @@ pub enum Error {

#[error(transparent)]
KeystoreError(#[from] eth_keystore::KeystoreError),

#[error(transparent)]
RegexError(#[from] regex::Error),
}
13 changes: 8 additions & 5 deletions tests/deploy_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ async fn deploy_contract_without_constructor_parameter(ctx: &TestContext) -> Res

let init = Init(vec![ScillaVariable::new_from_str("_scilla_version", "Uint32", "0")]);

let contract = factory.deploy_from_file(&ctx.timestamp_contract(), init, None).await.unwrap();
let contract = factory
.deploy_from_file(&ctx.timestamp_contract(), init, None, false)
.await
.unwrap();

println!("addr: {:?}", contract);
Ok(())
Expand All @@ -49,7 +52,7 @@ async fn deploy_contract_with_constructor_parameter(ctx: &TestContext) -> Result
]);

let contract = factory
.deploy_from_file(&ctx.hello_world_contract(), init, None)
.deploy_from_file(&ctx.hello_world_contract(), init, None, false)
.await
.unwrap();

Expand Down Expand Up @@ -86,7 +89,7 @@ async fn call_a_param_less_transition(ctx: &TestContext) -> Result<()> {
]);

let contract = factory
.deploy_from_file(&ctx.hello_world_contract(), init, None)
.deploy_from_file(&ctx.hello_world_contract(), init, None, false)
.await
.unwrap();

Expand All @@ -109,7 +112,7 @@ async fn call_transition_with_single_string_param(ctx: &TestContext) -> Result<(
]);

let contract = factory
.deploy_from_file(&ctx.hello_world_contract(), init, None)
.deploy_from_file(&ctx.hello_world_contract(), init, None, false)
.await
.unwrap();

Expand Down Expand Up @@ -138,7 +141,7 @@ async fn call_a_param_less_transition_though_the_rust_binding(ctx: &TestContext)
]);

let contract = factory
.deploy_from_file(&ctx.hello_world_contract(), init, None)
.deploy_from_file(&ctx.hello_world_contract(), init, None, false)
.await
.unwrap();

Expand Down

0 comments on commit f140e12

Please sign in to comment.