diff --git a/sputnikdao-factory2/res/sputnikdao_factory2.wasm b/sputnikdao-factory2/res/sputnikdao_factory2.wasm index ca72d4a81..222869d15 100755 Binary files a/sputnikdao-factory2/res/sputnikdao_factory2.wasm and b/sputnikdao-factory2/res/sputnikdao_factory2.wasm differ diff --git a/sputnikdao-factory2/src/factory_manager.rs b/sputnikdao-factory2/src/factory_manager.rs index 9dd01a750..d5e762a91 100644 --- a/sputnikdao-factory2/src/factory_manager.rs +++ b/sputnikdao-factory2/src/factory_manager.rs @@ -4,7 +4,7 @@ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::json_types::Base58CryptoHash; use near_sdk::serde_json; -use near_sdk::{env, sys, AccountId, Balance, CryptoHash, Gas}; +use near_sdk::{env, AccountId, Balance, CryptoHash, Gas}; /// Gas spent on the call & account creation. const CREATE_CALL_GAS: Gas = Gas(75_000_000_000_000); @@ -25,28 +25,17 @@ pub struct FactoryManager {} impl FactoryManager { /// Store contract from input. pub fn store_contract(&self) { - unsafe { - // Load input into register 0. - sys::input(0); - // Compute sha256 hash of register 0 and store in register 1. - sys::sha256(u64::MAX as _, 0 as _, 1); - // Check if such blob is already stored. - assert_eq!( - sys::storage_has_key(u64::MAX as _, 1 as _), - 0, - "ERR_ALREADY_EXISTS" - ); - // Store key-value pair. The key is represented by register 1 and the value by register 0. - sys::storage_write(u64::MAX as _, 1 as _, u64::MAX as _, 0 as _, 2); - // Load register 1 into blob_hash. - let blob_hash = [0u8; 32]; - sys::read_register(1, blob_hash.as_ptr() as _); - // Return from function value of register 1. - let blob_hash_str = serde_json::to_string(&Base58CryptoHash::from(blob_hash)) - .unwrap() - .into_bytes(); - sys::value_return(blob_hash_str.len() as _, blob_hash_str.as_ptr() as _); - } + let input = env::input().expect("ERR_NO_INPUT"); + let sha256_hash = env::sha256(&input); + assert!(!env::storage_has_key(&sha256_hash), "ERR_ALREADY_EXISTS"); + env::storage_write(&sha256_hash, &input); + + let mut blob_hash = [0u8; 32]; + blob_hash.copy_from_slice(&sha256_hash); + let blob_hash_str = serde_json::to_string(&Base58CryptoHash::from(blob_hash)) + .unwrap() + .into_bytes(); + env::value_return(&blob_hash_str); } /// Delete code from the contract. @@ -58,14 +47,12 @@ impl FactoryManager { /// Get code for given hash. pub fn get_code(&self, code_hash: Base58CryptoHash) { let code_hash: CryptoHash = code_hash.into(); - unsafe { - // Check that such contract exists. - assert!(env::storage_has_key(&code_hash), "Contract doesn't exist"); - // Load the hash from storage. - sys::storage_read(code_hash.len() as _, code_hash.as_ptr() as _, 0); - // Return as value. - sys::value_return(u64::MAX as _, 0 as _); - } + // Check that such contract exists. + assert!(env::storage_has_key(&code_hash), "Contract doesn't exist"); + // Load the hash from storage. + let code = env::storage_read(&code_hash).unwrap(); + // Return as value. + env::value_return(&code); } /// Forces update on the given contract. @@ -77,27 +64,21 @@ impl FactoryManager { method_name: &str, ) { let code_hash: CryptoHash = code_hash.into(); - let account_id = account_id.as_bytes().to_vec(); - unsafe { - // Check that such contract exists. - assert!(env::storage_has_key(&code_hash), "Contract doesn't exist"); - // Load the hash from storage. - sys::storage_read(code_hash.len() as _, code_hash.as_ptr() as _, 0); - // Create a promise toward given account. - let promise_id = - sys::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _); - // Call `update` method, which should also handle migrations. - sys::promise_batch_action_function_call( - promise_id, - method_name.len() as _, - method_name.as_ptr() as _, - u64::MAX as _, - 0, - &NO_DEPOSIT as *const u128 as _, - (env::prepaid_gas() - env::used_gas() - GAS_UPDATE_LEFTOVER).0, - ); - sys::promise_return(promise_id); - } + // Check that such contract exists. + assert!(env::storage_has_key(&code_hash), "Contract doesn't exist"); + // Load the hash from storage. + let code = env::storage_read(&code_hash).expect("ERR_NO_HASH"); + // Create a promise toward given account. + let promise_id = env::promise_batch_create(&account_id); + // Call `update` method, which should also handle migrations. + env::promise_batch_action_function_call( + promise_id, + method_name, + &code, + NO_DEPOSIT, + env::prepaid_gas() - env::used_gas() - GAS_UPDATE_LEFTOVER, + ); + env::promise_return(promise_id); } /// Create given contract with args and callback factory. @@ -112,49 +93,36 @@ impl FactoryManager { ) { let code_hash: CryptoHash = code_hash.into(); let attached_deposit = env::attached_deposit(); - let factory_account_id = env::current_account_id().as_bytes().to_vec(); - let account_id = account_id.as_bytes().to_vec(); - unsafe { - // Check that such contract exists. - assert_eq!( - sys::storage_has_key(code_hash.len() as _, code_hash.as_ptr() as _), - 1, - "Contract doesn't exist" - ); - // Load input (wasm code) into register 0. - sys::storage_read(code_hash.len() as _, code_hash.as_ptr() as _, 0); - // schedule a Promise tx to account_id - let promise_id = - sys::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _); - // create account first. - sys::promise_batch_action_create_account(promise_id); - // transfer attached deposit. - sys::promise_batch_action_transfer(promise_id, &attached_deposit as *const u128 as _); - // deploy contract (code is taken from register 0). - sys::promise_batch_action_deploy_contract(promise_id, u64::MAX as _, 0); - // call `new` with given arguments. - sys::promise_batch_action_function_call( - promise_id, - new_method.len() as _, - new_method.as_ptr() as _, - args.len() as _, - args.as_ptr() as _, - &NO_DEPOSIT as *const u128 as _, - CREATE_CALL_GAS.0, - ); - // attach callback to the factory. - let _ = sys::promise_then( - promise_id, - factory_account_id.len() as _, - factory_account_id.as_ptr() as _, - callback_method.len() as _, - callback_method.as_ptr() as _, - callback_args.len() as _, - callback_args.as_ptr() as _, - &NO_DEPOSIT as *const u128 as _, - ON_CREATE_CALL_GAS.0, - ); - sys::promise_return(promise_id); - } + let factory_account_id = env::current_account_id(); + // Check that such contract exists. + assert!(env::storage_has_key(&code_hash), "Contract doesn't exist"); + // Load input (wasm code). + let code = env::storage_read(&code_hash).expect("ERR_NO_HASH"); + // Schedule a Promise tx to account_id + let promise_id = env::promise_batch_create(&account_id); + // Create account first. + env::promise_batch_action_create_account(promise_id); + // Transfer attached deposit. + env::promise_batch_action_transfer(promise_id, attached_deposit); + // Deploy contract. + env::promise_batch_action_deploy_contract(promise_id, &code); + // call `new` with given arguments. + env::promise_batch_action_function_call( + promise_id, + new_method, + args, + NO_DEPOSIT, + CREATE_CALL_GAS, + ); + // attach callback to the factory. + let _ = env::promise_then( + promise_id, + factory_account_id, + callback_method, + callback_args, + NO_DEPOSIT, + ON_CREATE_CALL_GAS, + ); + env::promise_return(promise_id); } } diff --git a/sputnikdao2/res/sputnikdao2.wasm b/sputnikdao2/res/sputnikdao2.wasm index 61e4ccea0..3fa95e943 100755 Binary files a/sputnikdao2/res/sputnikdao2.wasm and b/sputnikdao2/res/sputnikdao2.wasm differ diff --git a/sputnikdao2/src/lib.rs b/sputnikdao2/src/lib.rs index feb38f205..4b0e2da08 100644 --- a/sputnikdao2/src/lib.rs +++ b/sputnikdao2/src/lib.rs @@ -3,7 +3,7 @@ use near_sdk::collections::{LazyOption, LookupMap}; use near_sdk::json_types::{Base58CryptoHash, U128}; use near_sdk::serde::{Deserialize, Serialize}; use near_sdk::{ - env, ext_contract, near_bindgen, sys, AccountId, Balance, BorshStorageKey, CryptoHash, + env, ext_contract, near_bindgen, AccountId, Balance, BorshStorageKey, CryptoHash, PanicOnDefault, Promise, PromiseResult, }; @@ -147,39 +147,29 @@ impl Contract { pub extern "C" fn store_blob() { env::setup_panic_hook(); let mut contract: Contract = env::state_read().expect("ERR_CONTRACT_IS_NOT_INITIALIZED"); - unsafe { - // Load input into register 0. - sys::input(0); - // Compute sha256 hash of register 0 and store in 1. - sys::sha256(u64::MAX as _, 0 as _, 1); - // Check if such blob already stored. - assert_eq!( - sys::storage_has_key(u64::MAX as _, 1 as _), - 0, - "ERR_ALREADY_EXISTS" - ); - // Get length of the input argument and check that enough $NEAR has been attached. - let blob_len = sys::register_len(0); - let storage_cost = ((blob_len + 32) as u128) * env::storage_byte_cost(); - assert!( - env::attached_deposit() >= storage_cost, - "ERR_NOT_ENOUGH_DEPOSIT:{}", - storage_cost - ); - // Store value of register 0 into key = register 1. - sys::storage_write(u64::MAX as _, 1 as _, u64::MAX as _, 0 as _, 2); - // Load register 1 into blob_hash and save into LookupMap. - let blob_hash = [0u8; 32]; - sys::read_register(1, blob_hash.as_ptr() as _); - contract - .blobs - .insert(&blob_hash, &env::predecessor_account_id()); - // Return from function value of register 1. - let blob_hash_str = near_sdk::serde_json::to_string(&Base58CryptoHash::from(blob_hash)) - .unwrap() - .into_bytes(); - sys::value_return(blob_hash_str.len() as _, blob_hash_str.as_ptr() as _); - } + let input = env::input().expect("ERR_NO_INPUT"); + let sha256_hash = env::sha256(&input); + assert!(!env::storage_has_key(&sha256_hash), "ERR_ALREADY_EXISTS"); + + let blob_len = input.len(); + let storage_cost = ((blob_len + 32) as u128) * env::storage_byte_cost(); + assert!( + env::attached_deposit() >= storage_cost, + "ERR_NOT_ENOUGH_DEPOSIT:{}", + storage_cost + ); + + env::storage_write(&sha256_hash, &input); + let mut blob_hash = [0u8; 32]; + blob_hash.copy_from_slice(&sha256_hash); + contract + .blobs + .insert(&blob_hash, &env::predecessor_account_id()); + let blob_hash_str = near_sdk::serde_json::to_string(&Base58CryptoHash::from(blob_hash)) + .unwrap() + .into_bytes(); + + env::value_return(&blob_hash_str); env::state_write(&contract); } diff --git a/sputnikdao2/src/upgrade.rs b/sputnikdao2/src/upgrade.rs index ed24b965b..c11652b13 100644 --- a/sputnikdao2/src/upgrade.rs +++ b/sputnikdao2/src/upgrade.rs @@ -7,7 +7,6 @@ use crate::*; const FACTORY_KEY: &[u8; 7] = b"FACTORY"; const ERR_MUST_BE_SELF_OR_FACTORY: &str = "ERR_MUST_BE_SELF_OR_FACTORY"; -const SELF_MIGRATE_METHOD_NAME: &[u8; 7] = b"migrate"; const UPDATE_GAS_LEFTOVER: Gas = Gas(5_000_000_000_000); const FACTORY_UPDATE_GAS_LEFTOVER: Gas = Gas(15_000_000_000_000); const NO_DEPOSIT: Balance = 0; @@ -61,6 +60,7 @@ pub(crate) fn internal_set_factory_info(factory_info: &FactoryInfo) { #[no_mangle] pub fn update() { env::setup_panic_hook(); + let factory_info = internal_get_factory_info(); let current_id = env::current_account_id(); assert!( @@ -70,34 +70,31 @@ pub fn update() { "{}", ERR_MUST_BE_SELF_OR_FACTORY ); + let is_callback = env::predecessor_account_id() == current_id; - unsafe { - // Load code into register 0 result from the input argument if factory call or from promise if callback. - if is_callback { - sys::promise_result(0, 0); - } else { - sys::input(0); - } - // Update current contract with code from register 0. - let promise_id = sys::promise_batch_create( - current_id.as_bytes().len() as _, - current_id.as_bytes().as_ptr() as _, - ); - // Deploy the contract code. - sys::promise_batch_action_deploy_contract(promise_id, u64::MAX as _, 0); - // Call promise to migrate the state. - // Batched together to fail upgrade if migration fails. - sys::promise_batch_action_function_call( - promise_id, - SELF_MIGRATE_METHOD_NAME.len() as _, - SELF_MIGRATE_METHOD_NAME.as_ptr() as _, - 0, - 0, - &NO_DEPOSIT as *const u128 as _, - (env::prepaid_gas() - env::used_gas() - UPDATE_GAS_LEFTOVER).0, - ); - sys::promise_return(promise_id); - } + let input; + if is_callback { + input = match env::promise_result(0) { + PromiseResult::Successful(data) => data, + _ => env::panic_str("ERR_NO_RESULT"), + }; + } else { + input = env::input().expect("ERR_NO_INPUT"); + }; + + let promise_id = env::promise_batch_create(¤t_id); + // Deploy the contract code. + env::promise_batch_action_deploy_contract(promise_id, &input); + // Call promise to migrate the state. + // Batched together to fail upgrade if migration fails. + env::promise_batch_action_function_call( + promise_id, + "migrate", + &[], + NO_DEPOSIT, + env::prepaid_gas() - env::used_gas() - UPDATE_GAS_LEFTOVER, + ); + env::promise_return(promise_id); } pub(crate) fn upgrade_using_factory(code_hash: Base58CryptoHash) { @@ -118,51 +115,24 @@ pub(crate) fn upgrade_using_factory(code_hash: Base58CryptoHash) { } #[allow(dead_code)] -/// Self upgrade, optimizes gas by not loading into memory the code. pub(crate) fn upgrade_self(hash: &[u8]) { let current_id = env::current_account_id(); - let method_name = "migrate".as_bytes().to_vec(); let attached_gas = env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE_SELF_DEPLOY; - unsafe { - // Load input (wasm code) into register 0. - sys::storage_read(hash.len() as _, hash.as_ptr() as _, 0); - // schedule a Promise tx to this same contract - let promise_id = sys::promise_batch_create( - current_id.as_bytes().len() as _, - current_id.as_bytes().as_ptr() as _, - ); - // 1st item in the Tx: "deploy contract" (code is taken from register 0) - sys::promise_batch_action_deploy_contract(promise_id, u64::MAX as _, 0); - // 2nd item in the Tx: call this_contract.migrate() with remaining gas - sys::promise_batch_action_function_call( - promise_id, - method_name.len() as _, - method_name.as_ptr() as _, - 0 as _, - 0 as _, - 0 as _, - attached_gas.0, - ); - } + let input = env::storage_read(hash).expect("ERR_NO_HASH"); + let promise_id = env::promise_batch_create(¤t_id); + env::promise_batch_action_deploy_contract(promise_id, &input); + env::promise_batch_action_function_call(promise_id, "migrate", &[], NO_DEPOSIT, attached_gas); } pub(crate) fn upgrade_remote(receiver_id: &AccountId, method_name: &str, hash: &[u8]) { - unsafe { - // Load input into register 0. - sys::storage_read(hash.len() as _, hash.as_ptr() as _, 0); - let promise_id = sys::promise_batch_create( - receiver_id.as_bytes().len() as _, - receiver_id.as_bytes().as_ptr() as _, - ); - let attached_gas = env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE_REMOTE_DEPLOY; - sys::promise_batch_action_function_call( - promise_id, - method_name.len() as _, - method_name.as_ptr() as _, - u64::MAX as _, - 0 as _, - 0 as _, - attached_gas.0, - ); - } + let input = env::storage_read(hash).expect("ERR_NO_HASH"); + let promise_id = env::promise_batch_create(receiver_id); + let attached_gas = env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE_REMOTE_DEPLOY; + env::promise_batch_action_function_call( + promise_id, + method_name, + &input, + NO_DEPOSIT, + attached_gas, + ); }