Skip to content

Commit

Permalink
wallet-contract package
Browse files Browse the repository at this point in the history
  • Loading branch information
staffik committed Nov 30, 2023
1 parent dd80b4c commit dccf038
Show file tree
Hide file tree
Showing 20 changed files with 1,746 additions and 19 deletions.
13 changes: 12 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ near-vm-test-generator = { path = "runtime/near-vm/test-generator" }
near-vm-types = { path = "runtime/near-vm/types" }
near-vm-vm = { path = "runtime/near-vm/vm" }
near-vm-wast = { path = "runtime/near-vm/wast" }
near-wallet-contract = { path = "runtime/near-wallet-contract" }
nix = "0.24"
node-runtime = { path = "runtime/runtime" }
num-bigint = "0.3"
Expand Down
1 change: 0 additions & 1 deletion core/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ strum.workspace = true
thiserror.workspace = true
time.workspace = true
tracing.workspace = true
wat.workspace = true

near-crypto.workspace = true
near-fmt.workspace = true
Expand Down
7 changes: 0 additions & 7 deletions core/primitives/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::version::{

use near_crypto::{ED25519PublicKey, Secp256K1PublicKey};
use near_primitives_core::account::id::{AccountId, AccountType};
use near_vm_runner::ContractCode;

use std::mem::size_of;
use std::ops::Deref;
Expand Down Expand Up @@ -471,12 +470,6 @@ where
Serializable(object)
}

// TODO(eth-implicit) Replace this function (and wat dependency) with a real Wallet Contract implementation.
pub fn wallet_contract_placeholder() -> ContractCode {
let code = wat::parse_str(r#"(module (func (export "main")))"#);
ContractCode::new(code.unwrap().to_vec(), None)
}

/// From `near-account-id` version `1.0.0-alpha.2`, `is_implicit` returns true for ETH-implicit accounts.
/// This function is a wrapper for `is_implicit` method so that we can easily differentiate its behavior
/// based on whether ETH-implicit accounts are enabled.
Expand Down
1 change: 1 addition & 0 deletions integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ near-test-contracts.workspace = true
near-performance-metrics.workspace = true
near-undo-block.workspace = true
near-vm-runner.workspace = true
near-wallet-contract.workspace = true
nearcore.workspace = true
node-runtime.workspace = true
testlib.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ use near_primitives::shard_layout::ShardLayout;
use near_primitives::sharding::ChunkHash;
use near_primitives::transaction::{Action, AddKeyAction, DeployContractAction, SignedTransaction};
use near_primitives::types::{AccountId, BlockHeight};
use near_primitives::utils::{
derive_eth_implicit_account_id, derive_near_implicit_account_id, wallet_contract_placeholder,
};
use near_primitives::utils::{derive_eth_implicit_account_id, derive_near_implicit_account_id};
use near_primitives::version::{ProtocolFeature, ProtocolVersion, PROTOCOL_VERSION};
use near_primitives::views::FinalExecutionStatus;
use near_wallet_contract::wallet_contract;
use nearcore::config::GenesisExt;
use nearcore::test_utils::TestEnvNightshadeSetupExt;
use nearcore::NEAR_BASE;
Expand Down Expand Up @@ -251,7 +250,7 @@ fn test_transaction_from_eth_implicit_account_fail() {
.nightshade_runtimes(&genesis)
.build();
let genesis_block = env.clients[0].chain.get_block_by_height(0).unwrap();
let deposit_for_account_creation = 10u128.pow(23);
let deposit_for_account_creation = 10 * nearcore::NEAR_BASE;
let mut height = 1;
let blocks_number = 5;
let signer1 = InMemorySigner::from_seed("test1".parse().unwrap(), KeyType::ED25519, "test1");
Expand Down Expand Up @@ -324,7 +323,7 @@ fn test_transaction_from_eth_implicit_account_fail() {
assert_eq!(response, expected_tx_error);

// Try to deploy the Wallet Contract again to the ETH-implicit account. Should fail because there is no access key.
let wallet_contract_code = wallet_contract_placeholder().code().to_vec();
let wallet_contract_code = wallet_contract().code().to_vec();
let add_access_key_to_eth_implicit_account_tx = SignedTransaction::from_actions(
nonce,
eth_implicit_account_id.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ fn meta_tx_create_implicit_account(new_account: AccountId) {
node.view_account(&new_account).expect_err("account already exists");

let fee_helper = fee_helper(&node);
let initial_amount = nearcore::NEAR_BASE;
let initial_amount = 10 * nearcore::NEAR_BASE;
let actions = vec![Action::Transfer(TransferAction { deposit: initial_amount })];

let tx_cost = match new_account.get_account_type() {
Expand Down
22 changes: 22 additions & 0 deletions runtime/near-wallet-contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "near-wallet-contract"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
description = "A temporary Wallet Contract placeholder."
repository.workspace = true
license.workspace = true
publish = false

[lints]
workspace = true

[dependencies]
near-vm-runner.workspace = true
wat.workspace = true
wasm-encoder.workspace = true
wasm-smith.workspace = true

[features]
nightly = []
1 change: 1 addition & 0 deletions runtime/near-wallet-contract/LICENSE-APACHE
1 change: 1 addition & 0 deletions runtime/near-wallet-contract/LICENSE-MIT
21 changes: 21 additions & 0 deletions runtime/near-wallet-contract/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
A temporary (placeholder) implementation of the `Wallet Contract`.

See https://github.com/near/NEPs/issues/518.

Must not use in production!

To use the contract you need to make sure that this crate was compiled.
The contract is built via `build.rs` and WASM file is generated to the `./res` directory.
You might want to `touch build.rs` before `cargo build` to force cargo to generate the WASM file.

If you want to use the contract from rust core, add

```toml
[dev-dependencies]
near-wallet-contract = { path = "../near-wallet-contract" }
```

to the Cargo.toml and use `near_wallet_contract::wallet_contract()`.

If you want to use a contract from an integration test, you can read
the wasm file directly from the `./res` directory.
69 changes: 69 additions & 0 deletions runtime/near-wallet-contract/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::process::Command;

type Error = Box<dyn std::error::Error>;

fn main() {
if let Err(err) = try_main() {
eprintln!("{}", err);
std::process::exit(1);
}
}

fn try_main() -> Result<(), Error> {
build_contract("./wallet-contract", &["--features", "latest_protocol"], "wallet_contract")?;
build_contract(
"./wallet-contract",
&["--features", "latest_protocol,nightly"],
"nightly_wallet_contract",
)?;
Ok(())
}

fn build_contract(dir: &str, args: &[&str], output: &str) -> Result<(), Error> {
let target_dir = out_dir();

let mut cmd = cargo_build_cmd(&target_dir);
cmd.args(args);
cmd.current_dir(dir);
check_status(cmd)?;

let src =
target_dir.join(format!("wasm32-unknown-unknown/release/{}.wasm", dir.replace('-', "_")));
std::fs::copy(&src, format!("./res/{}.wasm", output))
.map_err(|err| format!("failed to copy `{}`: {}", src.display(), err))?;
println!("cargo:rerun-if-changed=./{}/src/lib.rs", dir);
println!("cargo:rerun-if-changed=./{}/Cargo.toml", dir);
Ok(())
}

fn cargo_build_cmd(target_dir: &std::path::Path) -> Command {
let mut res = Command::new("cargo");

res.env_remove("CARGO_BUILD_RUSTFLAGS");
res.env_remove("CARGO_ENCODED_RUSTFLAGS");
res.env_remove("RUSTC_WORKSPACE_WRAPPER");

res.env("RUSTFLAGS", "-Dwarnings");
res.env("CARGO_TARGET_DIR", target_dir);

res.args(["build", "--target=wasm32-unknown-unknown", "--release"]);

res
}

fn check_status(mut cmd: Command) -> Result<(), Error> {
cmd.status()
.map_err(|err| format!("command `{cmd:?}` failed to run: {err}"))
.and_then(|status| {
if status.success() {
Ok(())
} else {
Err(format!("command `{cmd:?}` exited with non-zero status: {status:?}"))
}
})
.map_err(Error::from)
}

fn out_dir() -> std::path::PathBuf {
std::env::var("OUT_DIR").unwrap().into()
}
Binary file not shown.
Binary file not shown.
32 changes: 32 additions & 0 deletions runtime/near-wallet-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![doc = include_str!("../README.md")]

use near_vm_runner::ContractCode;
use std::path::Path;

/// Temporary (placeholder) Wallet Contract.
pub fn wallet_contract() -> ContractCode {
read_contract("wallet_contract.wasm")
}

/// Temporary (placeholder) Wallet Contract that has access to all host functions from
/// the nightly protocol.
pub fn nightly_wallet_contract() -> ContractCode {
read_contract("nightly_wallet_contract.wasm")
}

/// Read given wasm file or panic if unable to.
fn read_contract(file_name: &str) -> ContractCode {
let base = Path::new(env!("CARGO_MANIFEST_DIR"));
let path = base.join("res").join(file_name);
let code = match std::fs::read(&path) {
Ok(data) => data,
Err(err) => panic!("{}: {}", path.display(), err),
};
ContractCode::new(code, None)
}

#[test]
fn smoke_test() {
assert!(!wallet_contract().code().is_empty());
assert!(!nightly_wallet_contract().code().is_empty());
}
Loading

0 comments on commit dccf038

Please sign in to comment.