From b30843c12cf5c8bb7ae35f7c4f5123e672bd970d Mon Sep 17 00:00:00 2001 From: parazyd Date: Mon, 20 Feb 2023 19:28:45 +0100 Subject: [PATCH] runtime/db: Move the section restriction to the top of functions. --- src/blockchain/contract_store.rs | 4 +- src/runtime/import/db.rs | 791 ++++++++++++++++--------------- src/runtime/vm_runtime.rs | 2 +- 3 files changed, 406 insertions(+), 391 deletions(-) diff --git a/src/blockchain/contract_store.rs b/src/blockchain/contract_store.rs index 75e2325db..9d01db43f 100644 --- a/src/blockchain/contract_store.rs +++ b/src/blockchain/contract_store.rs @@ -104,8 +104,8 @@ impl ContractStateStore { let contract_id_bytes = serialize(contract_id); let ptr = contract_id.hash_state_id(tree_name); - // See if there are existing state trees. If not, just start with an - // empty vector. + // See if there are existing state trees. + // If not, just start with an empty vector. let mut state_pointers: Vec<[u8; 32]> = if self.0.contains_key(&contract_id_bytes)? { let bytes = self.0.get(&contract_id_bytes)?.unwrap(); deserialize(&bytes)? diff --git a/src/runtime/import/db.rs b/src/runtime/import/db.rs index 966b2aae4..94e3958f5 100644 --- a/src/runtime/import/db.rs +++ b/src/runtime/import/db.rs @@ -70,447 +70,462 @@ impl DbHandle { /// Only deploy() can call this. Creates a new database instance for this contract. pub(crate) fn db_init(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i32 { let env = ctx.data(); - match env.contract_section { - ContractSection::Deploy => { - let memory_view = env.memory_view(&ctx); - let db = &env.blockchain.sled_db; - let contracts = &env.blockchain.contracts; - let contract_id = &env.contract_id; - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { - error!(target: "runtime::db::db_init()", "Failed to make slice from ptr"); - return DB_INIT_FAILED - }; - - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_init()", "Failed to read from memory slice: {}", e); - return DB_INIT_FAILED - }; - - let mut buf_reader = Cursor::new(buf); - - let cid: ContractId = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_init()", "Failed to decode ContractId: {}", e); - return DB_INIT_FAILED - } - }; - - let db_name: String = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_init()", "Failed to decode db_name: {}", e); - return DB_INIT_FAILED - } - }; - - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_init()", "Trailing bytes in argument stream"); - return DB_DEL_FAILED - }*/ - - if &cid != contract_id { - error!(target: "runtime::db::db_init()", "Unauthorized ContractId for db_init"); - return CALLER_ACCESS_DENIED - } - - let tree_handle = match contracts.init(db, &cid, &db_name) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_init()", "Failed to init db: {}", e); - return DB_INIT_FAILED - } - }; - - // TODO: Make sure we don't duplicate the DbHandle in the vec. - // It should behave like an ordered set. - // In `lookup()` we also create a `sled::Batch`. This is done for - // some simplicity reasons, and also for possible future changes. - // However, we make sure that unauthorized writes are not available - // from other functions that interface with the databases. - let mut db_handles = env.db_handles.borrow_mut(); - let mut db_batches = env.db_batches.borrow_mut(); - db_handles.push(DbHandle::new(cid, tree_handle)); - db_batches.push(sled::Batch::default()); - (db_handles.len() - 1) as i32 - } - _ => { - error!(target: "runtime::db::db_init()", "db_init called in unauthorized section"); - CALLER_ACCESS_DENIED - } + // Exit as soon as possible + if env.contract_section != ContractSection::Deploy { + error!(target: "runtime::db::db_init()", "db_init called in unauthorized section"); + return CALLER_ACCESS_DENIED } + + let memory_view = env.memory_view(&ctx); + let db = &env.blockchain.sled_db; + let contracts = &env.blockchain.contracts; + let contract_id = &env.contract_id; + + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "runtime::db::db_init()", "Failed to make slice from ptr"); + return DB_INIT_FAILED + }; + + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_init()", "Failed to read from memory slice: {}", e); + return DB_INIT_FAILED + }; + + let mut buf_reader = Cursor::new(buf); + + let cid: ContractId = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_init()", "Failed to decode ContractId: {}", e); + return DB_INIT_FAILED + } + }; + + let db_name: String = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_init()", "Failed to decode db_name: {}", e); + return DB_INIT_FAILED + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_init()", "Trailing bytes in argument stream"); + return DB_DEL_FAILED + }*/ + + if &cid != contract_id { + error!(target: "runtime::db::db_init()", "Unauthorized ContractId for db_init"); + return CALLER_ACCESS_DENIED + } + + let tree_handle = match contracts.init(db, &cid, &db_name) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_init()", "Failed to init db: {}", e); + return DB_INIT_FAILED + } + }; + + // TODO: Make sure we don't duplicate the DbHandle in the vec. + // It should behave like an ordered set. + // In `lookup()` we also create a `sled::Batch`. This is done for + // some simplicity reasons, and also for possible future changes. + // However, we make sure that unauthorized writes are not available + // from other functions that interface with the databases. + let mut db_handles = env.db_handles.borrow_mut(); + let mut db_batches = env.db_batches.borrow_mut(); + db_handles.push(DbHandle::new(cid, tree_handle)); + db_batches.push(sled::Batch::default()); + (db_handles.len() - 1) as i32 } /// Everyone can call this. Lookups up a database handle from its name. pub(crate) fn db_lookup(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i32 { let env = ctx.data(); + match env.contract_section { ContractSection::Deploy | ContractSection::Exec | ContractSection::Update | ContractSection::Metadata => { - let memory_view = env.memory_view(&ctx); - let db = &env.blockchain.sled_db; - let contracts = &env.blockchain.contracts; - - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { - error!(target: "runtime::db::db_lookup()", "Failed to make slice from ptr"); - return DB_LOOKUP_FAILED - }; - - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_lookup()", "Failed to read from memory slice: {}", e); - return DB_LOOKUP_FAILED - }; - - let mut buf_reader = Cursor::new(buf); - - let cid: ContractId = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_lookup()", "Failed to decode ContractId: {}", e); - return DB_LOOKUP_FAILED - } - }; - - let db_name: String = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_lookup()", "Failed to decode db_name: {}", e); - return DB_LOOKUP_FAILED - } - }; - - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_lookup()", "Trailing bytes in argument stream"); - return DB_LOOKUP_FAILED - }*/ - - let tree_handle = match contracts.lookup(db, &cid, &db_name) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_lookup()", "Failed to lookup db: {}", e); - return DB_LOOKUP_FAILED - } - }; - - // TODO: Make sure we don't duplicate the DbHandle in the vec. - // It should behave like an ordered set. - // In `lookup()` we also create a `sled::Batch`. This is done for - // some simplicity reasons, and also for possible future changes. - // However, we make sure that unauthorized writes are not available - // from other functions that interface with the databases. - let mut db_handles = env.db_handles.borrow_mut(); - let mut db_batches = env.db_batches.borrow_mut(); - db_handles.push(DbHandle::new(cid, tree_handle)); - db_batches.push(sled::Batch::default()); - (db_handles.len() - 1) as i32 + // pass } + _ => { error!(target: "runtime::db::db_lookup()", "db_lookup called in unauthorized section"); - CALLER_ACCESS_DENIED + return CALLER_ACCESS_DENIED } } + + let memory_view = env.memory_view(&ctx); + let db = &env.blockchain.sled_db; + let contracts = &env.blockchain.contracts; + + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "runtime::db::db_lookup()", "Failed to make slice from ptr"); + return DB_LOOKUP_FAILED + }; + + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_lookup()", "Failed to read from memory slice: {}", e); + return DB_LOOKUP_FAILED + }; + + let mut buf_reader = Cursor::new(buf); + + let cid: ContractId = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_lookup()", "Failed to decode ContractId: {}", e); + return DB_LOOKUP_FAILED + } + }; + + let db_name: String = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_lookup()", "Failed to decode db_name: {}", e); + return DB_LOOKUP_FAILED + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_lookup()", "Trailing bytes in argument stream"); + return DB_LOOKUP_FAILED + }*/ + + let tree_handle = match contracts.lookup(db, &cid, &db_name) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_lookup()", "Failed to lookup db: {}", e); + return DB_LOOKUP_FAILED + } + }; + + // TODO: Make sure we don't duplicate the DbHandle in the vec. + // It should behave like an ordered set. + // In `lookup()` we also create a `sled::Batch`. This is done for + // some simplicity reasons, and also for possible future changes. + // However, we make sure that unauthorized writes are not available + // from other functions that interface with the databases. + let mut db_handles = env.db_handles.borrow_mut(); + let mut db_batches = env.db_batches.borrow_mut(); + db_handles.push(DbHandle::new(cid, tree_handle)); + db_batches.push(sled::Batch::default()); + (db_handles.len() - 1) as i32 } -/// Only update() can call this. Set a value within the transaction. +/// Set a value within the transaction. pub(crate) fn db_set(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i32 { let env = ctx.data(); - match env.contract_section { - ContractSection::Deploy | ContractSection::Update => { - let memory_view = env.memory_view(&ctx); - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { - error!(target: "runtime::db::db_set()", "Failed to make slice from ptr"); - return DB_SET_FAILED - }; - - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_set()", "Failed to read from memory slice: {}", e); - return DB_SET_FAILED - }; - - let mut buf_reader = Cursor::new(buf); - - // FIXME: There's a type DbHandle=u32, but this should maybe be renamed - let db_handle: u32 = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_set()", "Failed to decode DbHandle: {}", e); - return DB_SET_FAILED - } - }; - let db_handle = db_handle as usize; - - let key: Vec = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_set()", "Failed to decode key vec: {}", e); - return DB_SET_FAILED - } - }; - - let value: Vec = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_set()", "Failed to decode value vec: {}", e); - return DB_SET_FAILED - } - }; - - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_set()", "Trailing bytes in argument stream"); - return DB_DEL_FAILED - }*/ - - let db_handles = env.db_handles.borrow(); - let mut db_batches = env.db_batches.borrow_mut(); - - if db_handles.len() <= db_handle || db_batches.len() <= db_handle { - error!(target: "runtime::db::db_set()", "Requested DbHandle that is out of bounds"); - return DB_SET_FAILED - } - - let handle_idx = db_handle; - let db_handle = &db_handles[handle_idx]; - let db_batch = &mut db_batches[handle_idx]; - - if db_handle.contract_id != env.contract_id { - error!(target: "runtime::db::db_set()", "Unauthorized to write to DbHandle"); - return CALLER_ACCESS_DENIED - } - - db_batch.insert(key, value); - - DB_SUCCESS - } - _ => CALLER_ACCESS_DENIED, + if env.contract_section != ContractSection::Deploy && + env.contract_section != ContractSection::Update + { + error!(target: "runtime::db::db_set()", "db_set called in unauthorized section"); + return CALLER_ACCESS_DENIED } + + let memory_view = env.memory_view(&ctx); + + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "runtime::db::db_set()", "Failed to make slice from ptr"); + return DB_SET_FAILED + }; + + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_set()", "Failed to read from memory slice: {}", e); + return DB_SET_FAILED + }; + + let mut buf_reader = Cursor::new(buf); + + // FIXME: There's a type DbHandle=u32, but this should maybe be renamed + let db_handle: u32 = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_set()", "Failed to decode DbHandle: {}", e); + return DB_SET_FAILED + } + }; + let db_handle = db_handle as usize; + + let key: Vec = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_set()", "Failed to decode key vec: {}", e); + return DB_SET_FAILED + } + }; + + let value: Vec = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_set()", "Failed to decode value vec: {}", e); + return DB_SET_FAILED + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_set()", "Trailing bytes in argument stream"); + return DB_DEL_FAILED + }*/ + + let db_handles = env.db_handles.borrow(); + let mut db_batches = env.db_batches.borrow_mut(); + + if db_handles.len() <= db_handle || db_batches.len() <= db_handle { + error!(target: "runtime::db::db_set()", "Requested DbHandle that is out of bounds"); + return DB_SET_FAILED + } + + let handle_idx = db_handle; + let db_handle = &db_handles[handle_idx]; + let db_batch = &mut db_batches[handle_idx]; + + if db_handle.contract_id != env.contract_id { + error!(target: "runtime::db::db_set()", "Unauthorized to write to DbHandle"); + return CALLER_ACCESS_DENIED + } + + db_batch.insert(key, value); + + DB_SUCCESS } -/// Only update() can call this. Remove a key from the database. +/// Remove a key from the database. pub(crate) fn db_del(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i32 { let env = ctx.data(); - match env.contract_section { - ContractSection::Deploy | ContractSection::Update => { - let memory_view = env.memory_view(&ctx); - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + if env.contract_section != ContractSection::Deploy && + env.contract_section != ContractSection::Update + { + error!(target: "runtime::db::db_del()", "db_del called in unauthorized section"); + return CALLER_ACCESS_DENIED + } + + let memory_view = env.memory_view(&ctx); + + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { error!(target: "runtime::db::db_del()", "Failed to make slice from ptr"); return DB_DEL_FAILED }; - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_del()", "Failed to read from memory slice: {}", e); - return DB_DEL_FAILED - }; + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_del()", "Failed to read from memory slice: {}", e); + return DB_DEL_FAILED + }; - let mut buf_reader = Cursor::new(buf); + let mut buf_reader = Cursor::new(buf); - // FIXME: There's a type DbHandle=u32, but this should maybe be renamed - let db_handle: u32 = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_del()", "Failed to decode DbHandle: {}", e); - return DB_DEL_FAILED - } - }; - let db_handle = db_handle as usize; - - let key: Vec = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_del()", "Failed to decode key vec: {}", e); - return DB_DEL_FAILED - } - }; - - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_del()", "Trailing bytes in argument stream"); - return DB_DEL_FAILED - }*/ - - let db_handles = env.db_handles.borrow(); - let mut db_batches = env.db_batches.borrow_mut(); - - if db_handles.len() <= db_handle || db_batches.len() <= db_handle { - error!(target: "runtime::db::db_del()", "Requested DbHandle that is out of bounds"); - return DB_DEL_FAILED - } - - let handle_idx = db_handle; - let db_handle = &db_handles[handle_idx]; - let db_batch = &mut db_batches[handle_idx]; - - if db_handle.contract_id != env.contract_id { - error!(target: "runtime::db::db_del()", "Unauthorized to write to DbHandle"); - return CALLER_ACCESS_DENIED - } - - db_batch.remove(key); - - DB_SUCCESS + // FIXME: There's a type DbHandle=u32, but this should maybe be renamed + let db_handle: u32 = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_del()", "Failed to decode DbHandle: {}", e); + return DB_DEL_FAILED } - _ => CALLER_ACCESS_DENIED, + }; + let db_handle = db_handle as usize; + + let key: Vec = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_del()", "Failed to decode key vec: {}", e); + return DB_DEL_FAILED + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_del()", "Trailing bytes in argument stream"); + return DB_DEL_FAILED + }*/ + + let db_handles = env.db_handles.borrow(); + let mut db_batches = env.db_batches.borrow_mut(); + + if db_handles.len() <= db_handle || db_batches.len() <= db_handle { + error!(target: "runtime::db::db_del()", "Requested DbHandle that is out of bounds"); + return DB_DEL_FAILED } + + let handle_idx = db_handle; + let db_handle = &db_handles[handle_idx]; + let db_batch = &mut db_batches[handle_idx]; + + if db_handle.contract_id != env.contract_id { + error!(target: "runtime::db::db_del()", "Unauthorized to write to DbHandle"); + return CALLER_ACCESS_DENIED + } + + db_batch.remove(key); + + DB_SUCCESS } -/// Everyone can call this. Will read a key from the key-value store. +/// Will read a key from the key-value store. pub(crate) fn db_get(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i64 { let env = ctx.data(); - match env.contract_section { - ContractSection::Deploy | ContractSection::Exec | ContractSection::Metadata => { - let memory_view = env.memory_view(&ctx); - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { - error!(target: "runtime::db::db_get()", "Failed to make slice from ptr"); - return DB_GET_FAILED.into() - }; - - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_get()", "Failed to read from memory slice: {}", e); - return DB_GET_FAILED.into() - }; - - let mut buf_reader = Cursor::new(buf); - - // FIXME: There's a type DbHandle=u32, but this should maybe be renamed - let db_handle: u32 = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_get()", "Failed to decode DbHandle: {}", e); - return DB_GET_FAILED.into() - } - }; - let db_handle = db_handle as usize; - - let key: Vec = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_get()", "Failed to decode key from vec: {}", e); - return DB_GET_FAILED.into() - } - }; - - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_get()", "Trailing bytes in argument stream"); - return DB_GET_FAILED.into() - }*/ - - let db_handles = env.db_handles.borrow(); - - if db_handles.len() <= db_handle { - error!(target: "runtime::db::db_get()", "Requested DbHandle that is out of bounds"); - return DB_GET_FAILED.into() - } - - let handle_idx = db_handle; - let db_handle = &db_handles[handle_idx]; - - let ret = match db_handle.get(&key) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_get()", "Internal error getting from tree: {}", e); - return DB_GET_FAILED.into() - } - }; - - let Some(return_data) = ret else { - debug!(target: "runtime::db::db_get()", "returned empty vec"); - return -127 - }; - - // Copy Vec to the VM - let mut objects = env.objects.borrow_mut(); - objects.push(return_data); - (objects.len() - 1) as i64 - } - _ => CALLER_ACCESS_DENIED.into(), + if env.contract_section != ContractSection::Deploy && + env.contract_section != ContractSection::Exec && + env.contract_section != ContractSection::Metadata + { + error!(target: "runtime::db::db_get()", "db_get called in unauthorized section"); + return CALLER_ACCESS_DENIED.into() } + + let memory_view = env.memory_view(&ctx); + + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "runtime::db::db_get()", "Failed to make slice from ptr"); + return DB_GET_FAILED.into() + }; + + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_get()", "Failed to read from memory slice: {}", e); + return DB_GET_FAILED.into() + }; + + let mut buf_reader = Cursor::new(buf); + + // FIXME: There's a type DbHandle=u32, but this should maybe be renamed + let db_handle: u32 = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_get()", "Failed to decode DbHandle: {}", e); + return DB_GET_FAILED.into() + } + }; + let db_handle = db_handle as usize; + + let key: Vec = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_get()", "Failed to decode key from vec: {}", e); + return DB_GET_FAILED.into() + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_get()", "Trailing bytes in argument stream"); + return DB_GET_FAILED.into() + }*/ + + let db_handles = env.db_handles.borrow(); + + if db_handles.len() <= db_handle { + error!(target: "runtime::db::db_get()", "Requested DbHandle that is out of bounds"); + return DB_GET_FAILED.into() + } + + let handle_idx = db_handle; + let db_handle = &db_handles[handle_idx]; + + let ret = match db_handle.get(&key) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_get()", "Internal error getting from tree: {}", e); + return DB_GET_FAILED.into() + } + }; + + let Some(return_data) = ret else { + debug!(target: "runtime::db::db_get()", "returned empty vec"); + return -127 + }; + + // Copy Vec to the VM + let mut objects = env.objects.borrow_mut(); + objects.push(return_data); + (objects.len() - 1) as i64 } /// Everyone can call this. Will check if a given db contains given key. pub(crate) fn db_contains_key(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i32 { let env = ctx.data(); - match env.contract_section { - ContractSection::Deploy | - ContractSection::Exec | - ContractSection::Update | - ContractSection::Metadata => { - let memory_view = env.memory_view(&ctx); - let Ok(mem_slice) = ptr.slice(&memory_view, len) else { - error!(target: "runtime::db::db_contains_key()", "Failed to make slice from ptr"); - return DB_CONTAINS_KEY_FAILED - }; + if env.contract_section != ContractSection::Deploy && + env.contract_section != ContractSection::Exec && + env.contract_section != ContractSection::Update && + env.contract_section != ContractSection::Metadata + { + error!(target: "runtime::db::db_contains_key()", "db_contains_key called in unauthorized section"); + return CALLER_ACCESS_DENIED + } - let mut buf = vec![0_u8; len as usize]; - if let Err(e) = mem_slice.read_slice(&mut buf) { - error!(target: "runtime::db::db_contains_key()", "Failed to read from memory slice: {}", e); - return DB_CONTAINS_KEY_FAILED - }; + let memory_view = env.memory_view(&ctx); - let mut buf_reader = Cursor::new(buf); + let Ok(mem_slice) = ptr.slice(&memory_view, len) else { + error!(target: "runtime::db::db_contains_key()", "Failed to make slice from ptr"); + return DB_CONTAINS_KEY_FAILED + }; - // FIXME: There's a type DbHandle=u32, but this should maybe be renamed - let db_handle: u32 = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_contains_key()", "Failed to decode DbHandle: {}", e); - return DB_CONTAINS_KEY_FAILED - } - }; - let db_handle = db_handle as usize; + let mut buf = vec![0_u8; len as usize]; + if let Err(e) = mem_slice.read_slice(&mut buf) { + error!(target: "runtime::db::db_contains_key()", "Failed to read from memory slice: {}", e); + return DB_CONTAINS_KEY_FAILED + }; - let key: Vec = match Decodable::decode(&mut buf_reader) { - Ok(v) => v, - Err(e) => { - error!(target: "runtime::db::db_contains_key()", "Failed to decode key vec: {}", e); - return DB_CONTAINS_KEY_FAILED - } - }; + let mut buf_reader = Cursor::new(buf); - // Disabled until cursor_remaining feature is available on master. - // Then enable #![feature(cursor_remaining)] in src/lib.rs - /*if !buf_reader.is_empty() { - error!(target: "runtime::db::db_contains_key()", "Trailing bytes in argument stream"); - return DB_CONTAINS_KEY_FAILED - }*/ - - let db_handles = env.db_handles.borrow(); - - if db_handles.len() <= db_handle { - error!(target: "runtime::db::db_contains_key()", "Requested DbHandle that is out of bounds"); - return DB_CONTAINS_KEY_FAILED - } - - let handle_idx = db_handle; - let db_handle = &db_handles[handle_idx]; - - match db_handle.contains_key(&key) { - Ok(v) => i32::from(v), // <- 0=false, 1=true - Err(e) => { - error!(target: "runtime::db::db_contains_key()", "sled.tree.contains_key failed: {}", e); - DB_CONTAINS_KEY_FAILED - } - } + // FIXME: There's a type DbHandle=u32, but this should maybe be renamed + let db_handle: u32 = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_contains_key()", "Failed to decode DbHandle: {}", e); + return DB_CONTAINS_KEY_FAILED + } + }; + let db_handle = db_handle as usize; + + let key: Vec = match Decodable::decode(&mut buf_reader) { + Ok(v) => v, + Err(e) => { + error!(target: "runtime::db::db_contains_key()", "Failed to decode key vec: {}", e); + return DB_CONTAINS_KEY_FAILED + } + }; + + // Disabled until cursor_remaining feature is available on master. + // Then enable #![feature(cursor_remaining)] in src/lib.rs + /*if !buf_reader.is_empty() { + error!(target: "runtime::db::db_contains_key()", "Trailing bytes in argument stream"); + return DB_CONTAINS_KEY_FAILED + }*/ + + let db_handles = env.db_handles.borrow(); + + if db_handles.len() <= db_handle { + error!(target: "runtime::db::db_contains_key()", "Requested DbHandle that is out of bounds"); + return DB_CONTAINS_KEY_FAILED + } + + let handle_idx = db_handle; + let db_handle = &db_handles[handle_idx]; + + match db_handle.contains_key(&key) { + Ok(v) => i32::from(v), // <- 0=false, 1=true + Err(e) => { + error!(target: "runtime::db::db_contains_key()", "sled.tree.contains_key failed: {}", e); + DB_CONTAINS_KEY_FAILED } - _ => CALLER_ACCESS_DENIED, } } diff --git a/src/runtime/vm_runtime.rs b/src/runtime/vm_runtime.rs index 4c2dfbd7c..48d0bd7b8 100644 --- a/src/runtime/vm_runtime.rs +++ b/src/runtime/vm_runtime.rs @@ -43,7 +43,7 @@ const MEMORY: &str = "memory"; /// Gas limit for a contract const GAS_LIMIT: u64 = 200000000; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub enum ContractSection { /// Setup function of a contract Deploy,