Skip to content

Commit 177faf8

Browse files
committed
refactor: redesign storage key handling by removing KeyEncoding and simplifying ContractEnv initialization
1 parent b5e0250 commit 177faf8

13 files changed

Lines changed: 41 additions & 161 deletions

File tree

core/src/args.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,7 @@ mod tests {
216216
let none: Maybe<u32> = Maybe::None;
217217

218218
let ctx = MockContractContext::new();
219-
let env = ContractEnv::new(
220-
crate::contract_env::KeyEncoding::Legacy,
221-
Rc::new(RefCell::new(ctx))
222-
);
219+
let env = ContractEnv::new(Rc::new(RefCell::new(ctx)));
223220

224221
assert!(some.is_some());
225222
assert!(!some.is_none());
@@ -237,10 +234,7 @@ mod tests {
237234
let none: Maybe<u32> = Maybe::None;
238235
let mut ctx = MockContractContext::new();
239236
ctx.expect_revert().returning(|_| panic!("revert"));
240-
let env = ContractEnv::new(
241-
crate::contract_env::KeyEncoding::Legacy,
242-
Rc::new(RefCell::new(ctx))
243-
);
237+
let env = ContractEnv::new(Rc::new(RefCell::new(ctx)));
244238

245239
none.unwrap(&env);
246240
}

core/src/contract_container.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,7 @@ mod tests {
122122
)];
123123
let mut ctx = MockHostContext::new();
124124
ctx.expect_contract_env().returning(|| {
125-
ContractEnv::new(
126-
crate::contract_env::KeyEncoding::Legacy,
127-
Rc::new(RefCell::new(MockContractContext::new()))
128-
)
125+
ContractEnv::new(Rc::new(RefCell::new(MockContractContext::new())))
129126
});
130127
let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
131128

core/src/contract_env.rs

Lines changed: 23 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,6 @@ pub(crate) type StorageKey = [u8; KEY_LEN];
1919
/// Maximum nesting depth for module paths.
2020
pub(crate) const MAX_PATH_LEN: usize = 8;
2121

22-
/// Determines how storage keys are encoded.
23-
#[derive(Clone, Copy, Debug, PartialEq)]
24-
pub enum KeyEncoding {
25-
/// Default: fields 1-15 use legacy 4-bit u32 encoding, fields 16+ use path encoding.
26-
Legacy,
27-
/// All fields use path encoding. For new contracts only.
28-
V2
29-
}
30-
3122
/// Trait that needs to be implemented by all contract refs.
3223
pub trait ContractRef {
3324
/// Creates a new instance of the Contract Ref.
@@ -51,7 +42,6 @@ pub trait ContractRef {
5142
pub struct ContractEnv {
5243
path: [u8; MAX_PATH_LEN],
5344
path_len: u8,
54-
encoding: KeyEncoding,
5545
mapping_data: Vec<u8>,
5646
backend: Rc<RefCell<dyn ContractContext>>
5747
}
@@ -64,11 +54,10 @@ impl Revertible for ContractEnv {
6454

6555
impl ContractEnv {
6656
/// Creates a new ContractEnv instance.
67-
pub const fn new(encoding: KeyEncoding, backend: Rc<RefCell<dyn ContractContext>>) -> Self {
57+
pub const fn new(backend: Rc<RefCell<dyn ContractContext>>) -> Self {
6858
Self {
6959
path: [0u8; MAX_PATH_LEN],
7060
path_len: 0,
71-
encoding,
7261
mapping_data: Vec::new(),
7362
backend
7463
}
@@ -105,22 +94,18 @@ impl ContractEnv {
10594
/// - A → `[0xFF, 2, 3, 5]`, B → `[0xFF, 1, 3] ++ [5]` = `[0xFF, 1, 3, 5]` — **distinct.**
10695
pub(crate) fn index_bytes(&self) -> Vec<u8> {
10796
let path = &self.path[..self.path_len as usize];
108-
match self.encoding {
109-
// Legacy: pack indices into u32 via 4-bit shifts (e.g. path [3, 15] → 0x3F).
110-
// Only used when all indices fit in a nibble, preserving old storage keys.
111-
KeyEncoding::Legacy if path.iter().all(|&idx| idx <= 15) => {
112-
let index: u32 = path.iter().fold(0u32, |acc, &idx| (acc << 4) + idx as u32);
113-
index.to_be_bytes().to_vec()
114-
}
115-
// Path encoding: [0xFF, len, idx_0, idx_1, ...]. Used for fields 16+
116-
// in Legacy mode or for all fields in V2 mode.
117-
_ => {
118-
let mut bytes = Vec::with_capacity(2 + path.len());
119-
bytes.push(0xFF);
120-
bytes.push(self.path_len);
121-
bytes.extend_from_slice(path);
122-
bytes
123-
}
97+
// Legacy: pack indices into u32 via 4-bit shifts (e.g. path [3, 15] → 0x3F).
98+
// Only used when all indices fit in a nibble, preserving old storage keys.
99+
if path.iter().all(|&idx| idx <= 15) {
100+
let index: u32 = path.iter().fold(0u32, |acc, &idx| (acc << 4) + idx as u32);
101+
index.to_be_bytes().to_vec()
102+
} else {
103+
// Path encoding: [0xFF, len, idx_0, idx_1, ...]. Used for fields 16+.
104+
let mut bytes = Vec::with_capacity(2 + path.len());
105+
bytes.push(0xFF);
106+
bytes.push(self.path_len);
107+
bytes.extend_from_slice(path);
108+
bytes
124109
}
125110
}
126111

@@ -153,7 +138,6 @@ impl ContractEnv {
153138
Self {
154139
path: new_path,
155140
path_len: self.path_len + 1,
156-
encoding: self.encoding,
157141
mapping_data: self.mapping_data.clone(),
158142
backend: self.backend.clone()
159143
}
@@ -550,7 +534,7 @@ mod tests {
550534
use super::*;
551535
use crate::contract_context::MockContractContext;
552536

553-
fn make_env(encoding: KeyEncoding) -> ContractEnv {
537+
fn make_env() -> ContractEnv {
554538
let mut ctx = MockContractContext::new();
555539
ctx.expect_hash().returning(|input| {
556540
let mut result = [0u8; 32];
@@ -561,16 +545,16 @@ mod tests {
561545
}
562546
result
563547
});
564-
ContractEnv::new(encoding, Rc::new(RefCell::new(ctx)))
548+
ContractEnv::new(Rc::new(RefCell::new(ctx)))
565549
}
566550

567551
fn legacy_u32_for_path(path: &[u8]) -> u32 {
568552
path.iter().fold(0u32, |acc, &idx| (acc << 4) + idx as u32)
569553
}
570554

571555
#[test]
572-
fn legacy_encoding_matches_old_u32_formula() {
573-
let env = make_env(KeyEncoding::Legacy);
556+
fn encoding_matches_old_u32_formula() {
557+
let env = make_env();
574558
let child = env.child(3);
575559
assert_eq!(
576560
child.index_bytes(),
@@ -592,7 +576,7 @@ mod tests {
592576

593577
#[test]
594578
fn path_encoding_used_for_indices_above_15() {
595-
let env = make_env(KeyEncoding::Legacy);
579+
let env = make_env();
596580
let child = env.child(3).child(16);
597581
let bytes = child.index_bytes();
598582
assert_eq!(bytes[0], 0xFF);
@@ -601,28 +585,9 @@ mod tests {
601585
assert_eq!(bytes[3], 16);
602586
}
603587

604-
#[test]
605-
fn v2_encoding_always_uses_path() {
606-
let env = make_env(KeyEncoding::V2);
607-
let child = env.child(3);
608-
let bytes = child.index_bytes();
609-
assert_eq!(bytes[0], 0xFF);
610-
assert_eq!(bytes[1], 1);
611-
assert_eq!(bytes[2], 3);
612-
}
613-
614-
#[test]
615-
fn v2_and_legacy_produce_different_keys_for_same_path() {
616-
let legacy_env = make_env(KeyEncoding::Legacy);
617-
let v2_env = make_env(KeyEncoding::V2);
618-
let legacy_key = legacy_env.child(3).child(5).current_key();
619-
let v2_key = v2_env.child(3).child(5).current_key();
620-
assert_ne!(legacy_key, v2_key);
621-
}
622-
623588
#[test]
624589
fn no_collision_between_var_and_mapping() {
625-
let env = make_env(KeyEncoding::Legacy);
590+
let env = make_env();
626591

627592
let var_key = env.child(3).child(16).current_key();
628593
let mut map_env = env.child(3);
@@ -638,10 +603,10 @@ mod tests {
638603
}
639604

640605
#[test]
641-
fn no_collision_between_legacy_and_path_encoding() {
642-
let env = make_env(KeyEncoding::Legacy);
643-
let legacy_key = env.child(1).child(2).current_key();
606+
fn no_collision_between_small_and_path_encoding() {
607+
let env = make_env();
608+
let small_key = env.child(1).child(2).current_key();
644609
let path_key = env.child(1).child(20).current_key();
645-
assert_ne!(legacy_key, path_key);
610+
assert_ne!(small_key, path_key);
646611
}
647612
}

core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub use call_result::ContractCallResult;
4343
pub use casper_event_standard;
4444
pub use contract_container::ContractContainer;
4545
pub use contract_context::ContractContext;
46-
pub use contract_env::{ContractEnv, ContractRef, ExecutionEnv, KeyEncoding};
46+
pub use contract_env::{ContractEnv, ContractRef, ExecutionEnv};
4747
pub use contract_register::ContractRegister;
4848
pub use error::{AddressError, CollectionError, EventError, VmError, CASPER_ERROR_GENERIC_NAME};
4949

odra-casper/livenet-env/src/livenet_host.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,7 @@ impl LivenetHost {
4343
callstack.clone(),
4444
contract_register.clone()
4545
);
46-
let contract_env = Rc::new(ContractEnv::new(
47-
odra_core::KeyEncoding::Legacy,
48-
livenet_contract_env
49-
));
46+
let contract_env = Rc::new(ContractEnv::new(livenet_contract_env));
5047
Self {
5148
casper_client,
5249
contract_register,

odra-casper/wasm-env/src/wasm_contract_env.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,6 @@ impl ContractContext for WasmContractEnv {
134134
impl WasmContractEnv {
135135
/// Creates new ContractEnv with WasmContractEnv as backend.
136136
pub fn new_env() -> ContractEnv {
137-
ContractEnv::new(
138-
odra_core::KeyEncoding::Legacy,
139-
Rc::new(RefCell::new(WasmContractEnv))
140-
)
141-
}
142-
143-
/// Creates new ContractEnv with V2 key encoding.
144-
pub fn new_env_v2() -> ContractEnv {
145-
ContractEnv::new(
146-
odra_core::KeyEncoding::V2,
147-
Rc::new(RefCell::new(WasmContractEnv))
148-
)
137+
ContractEnv::new(Rc::new(RefCell::new(WasmContractEnv)))
149138
}
150139
}

odra-macros/src/ast/factory/parts/wasm_parts.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl TryFrom<(&'_ ModuleImplIR, &'_ FnIR)> for NoMangleFnItem<FactoryContext> {
2222
let result_ident = utils::ident::result();
2323
let exec_parts_ident = module.exec_parts_mod_ident()?;
2424
let exec_fn = func.execute_name();
25-
let new_env = utils::expr::new_wasm_contract_env(module.is_v2_keys());
25+
let new_env = utils::expr::new_wasm_contract_env();
2626

2727
let execute_stmt = match func.return_type() {
2828
syn::ReturnType::Default => parse_quote!(#exec_parts_ident::#exec_fn(#new_env);),
@@ -323,7 +323,7 @@ impl TryFrom<&'_ ModuleImplIR> for CallFnItem {
323323
fn try_from(module: &'_ ModuleImplIR) -> Result<Self, Self::Error> {
324324
Ok(Self {
325325
module_ident: module.module_ident()?,
326-
new_env_expr: utils::expr::new_wasm_contract_env(module.is_v2_keys())
326+
new_env_expr: utils::expr::new_wasm_contract_env()
327327
})
328328
}
329329
}
@@ -346,7 +346,7 @@ impl TryFrom<&'_ ModuleImplIR> for NoMangleFactoryFnItem {
346346
module_ident,
347347
event_ident,
348348
init_fn: module.constructor(),
349-
new_env_expr: utils::expr::new_wasm_contract_env(module.is_v2_keys()),
349+
new_env_expr: utils::expr::new_wasm_contract_env(),
350350
})
351351
}
352352
}
@@ -430,7 +430,7 @@ impl TryFrom<&'_ ModuleImplIR> for NoMangleFactoryUpgradeFnItem {
430430
module_ident,
431431
event_ident,
432432
upgrader_args,
433-
new_env_expr: utils::expr::new_wasm_contract_env(module.is_v2_keys()),
433+
new_env_expr: utils::expr::new_wasm_contract_env(),
434434
})
435435
}
436436
}

odra-macros/src/ast/wasm_parts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl TryFrom<&'_ ModuleImplIR> for CallFnItem {
126126
let ident_schemas = utils::ident::schemas();
127127
let ty_args = utils::ty::runtime_args();
128128
let ident_entry_points = utils::ident::entry_points();
129-
let new_env_expr = utils::expr::new_wasm_contract_env(module.is_v2_keys());
129+
let new_env_expr = utils::expr::new_wasm_contract_env();
130130
let exec_env_stmt: syn::Stmt = parse_quote!(
131131
let exec_env = {
132132
let env = #new_env_expr;
@@ -225,7 +225,7 @@ impl TryFrom<(&'_ ModuleImplIR, &'_ FnIR)> for NoMangleFnItem<ModuleContext> {
225225
let result_ident = utils::ident::result();
226226
let exec_parts_ident = module.exec_parts_mod_ident()?;
227227
let exec_fn = func.execute_name();
228-
let new_env = utils::expr::new_wasm_contract_env(module.is_v2_keys());
228+
let new_env = utils::expr::new_wasm_contract_env();
229229

230230
let execute_stmt = match func.return_type() {
231231
syn::ReturnType::Default => parse_quote!(#exec_parts_ident::#exec_fn(#new_env);),

odra-macros/src/ir/config.rs

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ mod kw {
2727
syn::custom_keyword!(events);
2828
syn::custom_keyword!(errors);
2929
syn::custom_keyword!(factory);
30-
syn::custom_keyword!(keys);
3130
}
3231

3332
#[derive(Default, Clone)]
@@ -36,9 +35,7 @@ pub struct ModuleConfiguration {
3635
pub errors: ModuleErrors,
3736
pub name: ModuleName,
3837
pub version: ModuleVersion,
39-
pub factory: Factory,
40-
#[allow(dead_code)]
41-
pub keys: ModuleKeys
38+
pub factory: Factory
4239
}
4340

4441
impl Parse for ModuleConfiguration {
@@ -48,8 +45,6 @@ impl Parse for ModuleConfiguration {
4845
let mut events = None;
4946
let mut errors = None;
5047
let mut factory = None;
51-
let mut keys = None;
52-
5348
while !input.is_empty() {
5449
if events.is_none() && input.peek(kw::events) {
5550
events = Some(input.parse::<ModuleEvents>()?);
@@ -81,11 +76,6 @@ impl Parse for ModuleConfiguration {
8176
continue;
8277
}
8378

84-
if keys.is_none() && input.peek(kw::keys) {
85-
keys = Some(input.parse::<ModuleKeys>()?);
86-
let _ = input.parse::<Token![,]>();
87-
continue;
88-
}
8979
return Err(input.error("Unexpected token"));
9080
}
9181

@@ -94,8 +84,7 @@ impl Parse for ModuleConfiguration {
9484
version: version.unwrap_or_default(),
9585
events: events.unwrap_or_default(),
9686
errors: errors.unwrap_or_default(),
97-
factory: factory.unwrap_or_default(),
98-
keys: keys.unwrap_or_default()
87+
factory: factory.unwrap_or_default()
9988
})
10089
}
10190
}
@@ -206,32 +195,6 @@ impl Parse for Factory {
206195
}
207196
}
208197

209-
#[derive(Default, Clone, Debug)]
210-
pub struct ModuleKeys(bool); // true = V2, false = Legacy
211-
212-
impl Deref for ModuleKeys {
213-
type Target = bool;
214-
215-
fn deref(&self) -> &Self::Target {
216-
&self.0
217-
}
218-
}
219-
220-
impl Parse for ModuleKeys {
221-
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
222-
input.parse::<kw::keys>()?;
223-
input.parse::<Token![=]>()?;
224-
let value = input.parse::<syn::LitStr>()?;
225-
match value.value().as_str() {
226-
"v2" => Ok(Self(true)),
227-
other => Err(syn::Error::new_spanned(
228-
value,
229-
format!("Unknown keys mode '{}'. Expected 'v2'.", other)
230-
))
231-
}
232-
}
233-
}
234-
235198
fn parse_list<T: Parse>(
236199
input: syn::parse::ParseStream
237200
) -> syn::Result<Punctuated<syn::Type, Token![,]>> {

0 commit comments

Comments
 (0)