Przeglądaj źródła

runtime: review and update ACL perms for fns

zero 2 lat temu
rodzic
commit
b42cb611c5

+ 2 - 2
src/contract/dao/src/entrypoint/mod.rs

@@ -143,7 +143,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
 /// for verifying signatures and ZK proofs. The payload given here are all the
 /// contract calls in the transaction.
 fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = DaoFunction::try_from(self_.data[0])?;
@@ -162,7 +162,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
 /// This function verifies a state transition and produces a state update
 /// if everything is successful.
 fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = DaoFunction::try_from(self_.data[0])?;

+ 3 - 3
src/contract/dao/src/entrypoint/propose.rs

@@ -85,7 +85,7 @@ pub(crate) fn dao_propose_get_metadata(
     }
 
     // ANCHOR: dao-blockwindow-example-usage
-    let current_day = blockwindow(wasm::util::get_verifying_block_height());
+    let current_day = blockwindow(wasm::util::get_verifying_block_height()?);
     // ANCHOR_END: dao-blockwindow-example-usage
 
     let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
@@ -154,8 +154,8 @@ pub(crate) fn dao_propose_process_instruction(
         let tx_hash = TransactionHash(tx_hash_data);
         // Get block_height where tx_hash was confirmed
         let (tx_height, _) = wasm::util::get_tx_location(&tx_hash)?;
-        let current_height = wasm::util::get_verifying_block_height();
-        if current_height - tx_height > PROPOSAL_SNAPSHOT_CUTOFF_LIMIT {
+        let current_height = wasm::util::get_verifying_block_height()?;
+        if current_height - tx_height as u32 > PROPOSAL_SNAPSHOT_CUTOFF_LIMIT {
             msg!("[Dao::Propose] Error: Snapshot is too old. Current height: {}, snapshot height: {}",
                  current_height, tx_height);
             return Err(DaoError::SnapshotTooOld.into())

+ 1 - 1
src/contract/dao/src/entrypoint/vote.rs

@@ -89,7 +89,7 @@ pub(crate) fn dao_vote_get_metadata(
         ));
     }
 
-    let current_day = blockwindow(wasm::util::get_verifying_block_height());
+    let current_day = blockwindow(wasm::util::get_verifying_block_height()?);
 
     let yes_vote_commit_coords = params.yes_vote_commit.to_affine().coordinates().unwrap();
     let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap();

+ 3 - 3
src/contract/dao/src/lib.rs

@@ -90,7 +90,7 @@ pub const DAO_CONTRACT_ZKAS_DAO_AUTH_MONEY_TRANSFER_NS: &str = "AuthMoneyTransfe
 pub const DAO_CONTRACT_ZKAS_DAO_AUTH_MONEY_TRANSFER_ENC_COIN_NS: &str = "AuthMoneyTransferEncCoin";
 
 /// Not allowed to make proposals using snapshots with block heights older than this depth
-pub const PROPOSAL_SNAPSHOT_CUTOFF_LIMIT: u64 = 100;
+pub const PROPOSAL_SNAPSHOT_CUTOFF_LIMIT: u32 = 100;
 
 // ANCHOR: dao-blockwindow
 const BLOCK_TIME: u64 = 90;
@@ -98,8 +98,8 @@ const SECS_IN_HOUR: u64 = 60 * 60;
 const WINDOW_TIME_HR: u64 = 4;
 
 /// Blockwindow from blockheight. Used for time limit on DAO proposals.
-pub fn blockwindow(height: u64) -> u64 {
-    let timestamp_secs = height * BLOCK_TIME;
+pub fn blockwindow(height: u32) -> u64 {
+    let timestamp_secs = height as u64 * BLOCK_TIME;
     timestamp_secs / (WINDOW_TIME_HR * SECS_IN_HOUR)
 }
 // ANCHOR_END: dao-blockwindow

+ 2 - 2
src/contract/deployooor/src/entrypoint.rs

@@ -68,7 +68,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
 /// for verifying signatures and zk proofs. The payload given here are all the
 /// contract calls in the transaction.
 fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = DeployFunction::try_from(self_.data[0])?;
@@ -84,7 +84,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
 /// This function verifies a state transition and produces a state update
 /// if everything is successful.
 fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = DeployFunction::try_from(self_.data[0])?;

+ 3 - 3
src/contract/money/src/entrypoint.rs

@@ -125,7 +125,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
 
     let tx_hash = wasm::util::get_tx_hash()?;
     // The max outputs for a tx in BTC is 2501
-    let call_idx = wasm::util::get_call_index() as u16;
+    let call_idx = wasm::util::get_call_index()? as u16;
     let mut roots_value_data = Vec::with_capacity(32 + 2);
     tx_hash.encode(&mut roots_value_data)?;
     call_idx.encode(&mut roots_value_data)?;
@@ -209,7 +209,7 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
 /// for verifying signatures and zk proofs. The payload given here are all the
 /// contract calls in the transaction.
 fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = MoneyFunction::try_from(self_.data[0])?;
@@ -240,7 +240,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
 /// if everything is successful. This step should happen **after** the host
 /// has successfully verified the metadata from `get_metadata()`.
 fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let call_idx = wasm::util::get_call_index();
+    let call_idx = wasm::util::get_call_index()?;
     let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
     let self_ = &calls[call_idx as usize].data;
     let func = MoneyFunction::try_from(self_.data[0])?;

+ 1 - 1
src/contract/money/src/entrypoint/genesis_mint_v1.rs

@@ -80,7 +80,7 @@ pub(crate) fn money_genesis_mint_process_instruction_v1(
     let params: MoneyGenesisMintParamsV1 = deserialize(&self_.data[1..])?;
 
     // Verify this contract call is verified against genesis block(0).
-    let verifying_block_height = wasm::util::get_verifying_block_height();
+    let verifying_block_height = wasm::util::get_verifying_block_height()?;
     if verifying_block_height != 0 {
         msg!(
             "[GenesisMintV1] Error: Call is executed for block {}, not genesis",

+ 3 - 3
src/contract/money/src/entrypoint/pow_reward_v1.rs

@@ -81,7 +81,7 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
     let params: MoneyPoWRewardParamsV1 = deserialize(&self_.data[1..])?;
 
     // Verify this contract call is not verified against genesis block
-    let verifying_block_height = wasm::util::get_verifying_block_height();
+    let verifying_block_height = wasm::util::get_verifying_block_height()?;
     if verifying_block_height == 0 {
         msg!("[PoWRewardV1] Error: Call is executed for genesis block");
         return Err(MoneyError::PoWRewardCallOnGenesisBlock.into())
@@ -93,7 +93,7 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
         return Err(MoneyError::PoWRewardRetrieveLastBlockHeightError.into())
     };
     let last_block_height: u64 = deserialize(&last_block_height)?;
-    if verifying_block_height != last_block_height + 1 {
+    if verifying_block_height != last_block_height as u32 + 1 {
         msg!(
             "[PoWRewardV1] Error: Call is executed for block height {}, not next one: {}",
             verifying_block_height,
@@ -109,7 +109,7 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
     }
 
     // Verify reward value matches the expected one for this block height
-    let expected_reward = expected_reward(verifying_block_height);
+    let expected_reward = expected_reward(verifying_block_height as u64);
     if params.input.value != expected_reward {
         msg!(
             "[PoWRewardV1] Error: Reward value({}) is not the block height({}) expected one: {}",

+ 1 - 1
src/contract/test-harness/src/dao_propose.rs

@@ -121,7 +121,7 @@ impl TestHarness {
             },
         ];
 
-        let creation_day = blockwindow(block_height);
+        let creation_day = blockwindow(block_height as u32);
         let proposal = DaoProposal {
             auth_calls,
             creation_day,

+ 1 - 1
src/contract/test-harness/src/dao_vote.rs

@@ -81,7 +81,7 @@ impl TestHarness {
             signature_secret,
         };
 
-        let current_day = blockwindow(block_height);
+        let current_day = blockwindow(block_height as u32);
         let call = DaoVoteCall {
             money_null_smt: wallet.money_null_smt_snapshot.as_ref().unwrap(),
             inputs: vec![input],

+ 17 - 3
src/runtime/import/db.rs

@@ -51,6 +51,8 @@ impl DbHandle {
 ///
 /// This function should **only** be allowed in `ContractSection::Deploy`, as that
 /// is called when a contract is being (re)deployed and databases have to be created.
+///
+/// Permissions: deploy
 pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
@@ -198,6 +200,8 @@ pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u
 /// Otherwise, returns an error value.
 ///
 /// This function can be called from any [`ContractSection`].
+///
+/// Permissions: deploy, metadata, exec, update
 pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
@@ -207,8 +211,8 @@ pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len:
         env,
         &[
             ContractSection::Deploy,
-            ContractSection::Exec,
             ContractSection::Metadata,
+            ContractSection::Exec,
             ContractSection::Update,
         ],
     ) {
@@ -325,6 +329,8 @@ pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len:
 ///
 /// This function can be called only from the Deploy or Update [`ContractSection`].
 /// Returns `SUCCESS` on success, otherwise returns an error value.
+///
+/// Permissions: deploy, update
 pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
@@ -455,6 +461,8 @@ pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u3
 ///
 /// This function can be called only from the Deploy or Update [`ContractSection`].
 /// Returns `SUCCESS` on success, otherwise returns an error value.
+///
+/// Permissions: deploy, update
 pub(crate) fn db_del(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
@@ -567,12 +575,14 @@ pub(crate) fn db_del(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u3
 ///
 /// On success, returns the length of the `objects` Vector in the environment.
 /// Otherwise, returns an error code.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
     if let Err(e) =
-        acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
     {
         error!(
             target: "runtime::db::db_get",
@@ -702,12 +712,14 @@ pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u3
 /// Returns `1` if the key is found.
 /// Returns `0` if the key is not found and there are no errors.
 /// Otherwise, returns an error code.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn db_contains_key(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
     if let Err(e) =
-        acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
     {
         error!(
             target: "runtime::db::db_contains_key",
@@ -808,6 +820,8 @@ pub(crate) fn db_contains_key(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, pt
 ///
 /// This function can only be called from the Deploy [`ContractSection`].
 /// Returns `SUCCESS` on success, otherwise returns an error code.
+///
+/// Permissions: deploy
 pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;

+ 2 - 0
src/runtime/import/merkle.rs

@@ -35,6 +35,8 @@ use crate::runtime::vm_runtime::{ContractSection, Env};
 /// Returns `0` on success; otherwise, returns an error-code corresponding to a
 /// [`ContractError`] (defined in the SDK).
 /// See also the method `merkle_add` in `sdk/src/merkle.rs`.
+///
+/// Permissions: update
 pub(crate) fn merkle_add(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;

+ 102 - 10
src/runtime/import/util.rs

@@ -55,6 +55,8 @@ pub(crate) fn drk_log(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
 ///
 /// Returns `SUCCESS` on success, otherwise returns an error code corresponding
 /// to a [`ContractError`].
+///
+/// Permissions: metadata, exec
 pub(crate) fn set_return_data(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = &env.contract_id;
@@ -89,10 +91,21 @@ pub(crate) fn set_return_data(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, le
 ///
 /// Returns an index corresponding to the new object's index in the objects
 /// store. (This index is equal to the last index in the store.)
+///
+/// Permissions:
 pub(crate) fn put_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
+    // Enforce function ACL
+    if let Err(e) = acl_allow(env, &[]) {
+        error!(
+            target: "runtime::util::put_object_bytes()",
+            "[WASM] [{}] put_object_bytes(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
+
     // Subtract used gas. Here we count the length read from the memory slice.
     env.subtract_gas(&mut store, len as u64);
 
@@ -141,11 +154,24 @@ pub(crate) fn put_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, l
 /// The object's data is written to `ptr`.
 ///
 /// Returns `SUCCESS` on success and an error code otherwise.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, idx: u32) -> i64 {
     // Get the slice, where we will read the size of the buffer
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
+    // Enforce function ACL
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
+        error!(
+            target: "runtime::util::get_object_bytes()",
+            "[WASM] [{}] get_object_bytes(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
+
     // Get the object from env
     let objects = env.objects.borrow();
     if idx as usize >= objects.len() {
@@ -189,11 +215,24 @@ pub(crate) fn get_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, i
 
 /// Returns the size (number of bytes) of an object in the object store
 /// specified by index `idx`.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_object_size(mut ctx: FunctionEnvMut<Env>, idx: u32) -> i64 {
     // Get the slice, where we will read the size of the buffer
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
+    // Enforce function ACL
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
+        error!(
+            target: "runtime::util::get_object_size()",
+            "[WASM] [{}] get_object_size(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
+
     // Get the object from env
     let objects = env.objects.borrow();
     if idx as usize >= objects.len() {
@@ -220,27 +259,43 @@ pub(crate) fn get_object_size(mut ctx: FunctionEnvMut<Env>, idx: u32) -> i64 {
 }
 
 /// Will return current runtime configured verifying block height number
-pub(crate) fn get_verifying_block_height(mut ctx: FunctionEnvMut<Env>) -> u64 {
+///
+/// Permissions: deploy, metadata, exec
+pub(crate) fn get_verifying_block_height(mut ctx: FunctionEnvMut<Env>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
+    let cid = env.contract_id;
+
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
+        error!(
+            target: "runtime::util::get_verifying_block_height",
+            "[WASM] [{}] get_verifying_block_height(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
 
     // Subtract used gas. Here we count the size of the object.
     // u64 is 8 bytes.
     env.subtract_gas(&mut store, 8);
 
-    env.verifying_block_height
+    assert!(env.verifying_block_height <= i64::MAX as u64);
+    env.verifying_block_height as i64
 }
 
 /// Will return current runtime configured transaction hash
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_tx_hash(mut ctx: FunctionEnvMut<Env>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
     if let Err(e) =
-        acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
     {
         error!(
-            target: "runtime::util::get_tx",
-            "[WASM] [{}] get_tx(): Called in unauthorized section: {}", cid, e,
+            target: "runtime::util::get_tx_hash",
+            "[WASM] [{}] get_tx_hash(): Called in unauthorized section: {}", cid, e,
         );
         return darkfi_sdk::error::CALLER_ACCESS_DENIED
     }
@@ -256,22 +311,47 @@ pub(crate) fn get_tx_hash(mut ctx: FunctionEnvMut<Env>) -> i64 {
 }
 
 /// Will return current runtime configured verifying block height number
-pub(crate) fn get_call_index(mut ctx: FunctionEnvMut<Env>) -> u32 {
+///
+/// Permissions: deploy, metadata, exec
+pub(crate) fn get_call_index(mut ctx: FunctionEnvMut<Env>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
+    let cid = env.contract_id;
+
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
+        error!(
+            target: "runtime::util::get_call_index",
+            "[WASM] [{}] get_call_index(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
 
     // Subtract used gas. Here we count the size of the object.
     // u32 is 4 bytes.
     env.subtract_gas(&mut store, 4);
 
-    env.call_idx
+    env.call_idx as i64
 }
 
 /// Will return current blockchain timestamp,
 /// defined as the last block's timestamp.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_blockchain_time(mut ctx: FunctionEnvMut<Env>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = &env.contract_id;
 
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
+        error!(
+            target: "runtime::util::get_blockchain_time",
+            "[WASM] [{}] get_blockchain_time(): Called in unauthorized section: {}", cid, e,
+        );
+        return darkfi_sdk::error::CALLER_ACCESS_DENIED
+    }
+
     // Grab current last block
     let timestamp = match env.blockchain.lock().unwrap().last_block_timestamp() {
         Ok(b) => b,
@@ -307,12 +387,16 @@ pub(crate) fn get_blockchain_time(mut ctx: FunctionEnvMut<Env>) -> i64 {
 ///
 /// On success, returns the index of the new object in the object store.
 /// Otherwise, returns an error code.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_last_block_height(mut ctx: FunctionEnvMut<Env>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = &env.contract_id;
 
     // Enforce function ACL
-    if let Err(e) = acl_allow(env, &[ContractSection::Exec]) {
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
         error!(
             target: "runtime::util::get_last_block_height",
             "[WASM] [{}] get_last_block_height(): Called in unauthorized section: {}", cid, e,
@@ -356,11 +440,15 @@ pub(crate) fn get_last_block_height(mut ctx: FunctionEnvMut<Env>) -> i64 {
 ///
 /// On success, returns the length of the transaction bytes vector in the environment.
 /// Otherwise, returns an error code.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_tx(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
-    if let Err(e) = acl_allow(env, &[ContractSection::Exec, ContractSection::Metadata]) {
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
         error!(
             target: "runtime::util::get_tx",
             "[WASM] [{}] get_tx(): Called in unauthorized section: {}", cid, e,
@@ -460,11 +548,15 @@ pub(crate) fn get_tx(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>) -> i64 {
 ///
 /// On success, returns the length of the transaction location bytes vector in
 /// the environment. Otherwise, returns an error code.
+///
+/// Permissions: deploy, metadata, exec
 pub(crate) fn get_tx_location(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>) -> i64 {
     let (env, mut store) = ctx.data_and_store_mut();
     let cid = env.contract_id;
 
-    if let Err(e) = acl_allow(env, &[ContractSection::Exec, ContractSection::Metadata]) {
+    if let Err(e) =
+        acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
+    {
         error!(
             target: "runtime::util::get_tx_location",
             "[WASM] [{}] get_tx_location(): Called in unauthorized section: {}", cid, e,

+ 19 - 13
src/sdk/src/wasm/util.rs

@@ -83,14 +83,25 @@ pub(crate) fn parse_ret(ret: i64) -> GenericResult<Option<Vec<u8>>> {
     Ok(Some(buf))
 }
 
+fn parse_retval_u32(ret: i64) -> GenericResult<u32> {
+    if ret < 0 {
+        return Err(ContractError::from(ret))
+    }
+    assert!(ret >= 0);
+    // This should always be possible
+    let obj = ret as u32;
+    Ok(obj)
+}
+
 /// Everyone can call this. Will return runtime configured
 /// verifying block height.
 ///
 /// ```
 /// block_height = get_verifying_block_height();
 /// ```
-pub fn get_verifying_block_height() -> u64 {
-    unsafe { get_verifying_block_height_() }
+pub fn get_verifying_block_height() -> GenericResult<u32> {
+    let ret = unsafe { get_verifying_block_height_() };
+    parse_retval_u32(ret)
 }
 
 /// Only deploy(), metadata() and exec() can call this. Will return runtime configured
@@ -101,13 +112,7 @@ pub fn get_verifying_block_height() -> u64 {
 /// ```
 pub fn get_tx_hash() -> GenericResult<TransactionHash> {
     let ret = unsafe { get_tx_hash_() };
-    if ret < 0 {
-        return Err(ContractError::from(ret))
-    }
-    assert!(ret >= 0);
-    // This should always be possible
-    let obj = ret as u32;
-
+    let obj = parse_retval_u32(ret)?;
     let mut tx_hash_data = [0u8; 32];
     assert_eq!(get_object_size(obj), 32);
     get_object_bytes(&mut tx_hash_data, obj);
@@ -120,8 +125,9 @@ pub fn get_tx_hash() -> GenericResult<TransactionHash> {
 /// ```
 /// call_idx = get_call_index();
 /// ```
-pub fn get_call_index() -> u32 {
-    unsafe { get_call_index_() }
+pub fn get_call_index() -> GenericResult<u32> {
+    let ret = unsafe { get_call_index_() };
+    parse_retval_u32(ret)
 }
 
 /// Everyone can call this. Will return current blockchain timestamp.
@@ -181,9 +187,9 @@ extern "C" {
     fn get_object_bytes_(ptr: *const u8, len: u32) -> i64;
     fn get_object_size_(len: u32) -> i64;
 
-    fn get_verifying_block_height_() -> u64;
+    fn get_verifying_block_height_() -> i64;
     fn get_tx_hash_() -> i64;
-    fn get_call_index_() -> u32;
+    fn get_call_index_() -> i64;
     fn get_blockchain_time_() -> i64;
     fn get_last_block_height_() -> i64;
     fn get_tx_(ptr: *const u8) -> i64;