fn emit_load_struct_array_element(
bytecode: &mut Vec<u8>,
module: &ir::Module,
state_index: usize,
key_types: &[ValueType],
access: StructArrayElementAccess<'_>,
use_callt: bool,
token_patches: &mut Vec<MethodTokenPatch>,
) {
emit_struct_field_slot(
bytecode,
module,
state_index,
key_types,
access.field_keys,
use_callt,
token_patches,
);
bytecode.push(0x50); emit_serialize_key(
bytecode,
&ValueType::Integer {
signed: false,
bits: 256,
},
use_callt,
token_patches,
); bytecode.push(0x50); bytecode.push(0x8B); emit_native_contract_call(
bytecode,
ir::NativeContract::CryptoLib,
"keccak256",
1,
use_callt,
token_patches,
);
match access.element_type {
ValueType::Struct { fields, .. } => {
push_integer_bigint(bytecode, &BigInt::from(fields.len() as u64));
bytecode.push(0xC3);
for (field_index, field) in fields.iter().enumerate() {
bytecode.push(0x4B); push_data(bytecode, &field.key);
bytecode.push(0x50); bytecode.push(0x8B); emit_native_contract_call(
bytecode,
ir::NativeContract::CryptoLib,
"keccak256",
1,
use_callt,
token_patches,
);
match &field.ty {
ValueType::Struct { fields, .. } => {
emit_load_struct_value_from_slot(bytecode, fields, use_callt, token_patches);
}
_ => {
emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Get");
emit_coerce_storage_value(bytecode, &field.ty);
}
}
bytecode.push(0x4B); bytecode.push(0x50); push_integer_bigint(bytecode, &BigInt::from(field_index as u64));
bytecode.push(0x50); bytecode.push(0xD0); }
bytecode.push(0x50); bytecode.push(0x45); }
_ => {
emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Get");
emit_coerce_storage_value(bytecode, access.element_type);
}
}
}
fn emit_store_struct_array_element(
bytecode: &mut Vec<u8>,
module: &ir::Module,
state_index: usize,
key_types: &[ValueType],
access: StructArrayElementAccess<'_>,
use_callt: bool,
token_patches: &mut Vec<MethodTokenPatch>,
) {
emit_struct_field_slot(
bytecode,
module,
state_index,
key_types,
access.field_keys,
use_callt,
token_patches,
);
bytecode.push(0x50); emit_serialize_key(
bytecode,
&ValueType::Integer {
signed: false,
bits: 256,
},
use_callt,
token_patches,
); bytecode.push(0x50); bytecode.push(0x8B); emit_native_contract_call(
bytecode,
ir::NativeContract::CryptoLib,
"keccak256",
1,
use_callt,
token_patches,
);
match access.element_type {
ValueType::Struct { fields, .. } => {
for (field_index, field) in fields.iter().enumerate() {
bytecode.push(0x4A); push_data(bytecode, &field.key);
bytecode.push(0x50); bytecode.push(0x8B); emit_native_contract_call(
bytecode,
ir::NativeContract::CryptoLib,
"keccak256",
1,
use_callt,
token_patches,
);
bytecode.push(0x12); bytecode.push(0x4D); push_integer_bigint(bytecode, &BigInt::from(field_index as u64));
bytecode.push(0xCE);
match &field.ty {
ValueType::Struct { fields, .. } => {
emit_store_struct_value_to_slot(
bytecode,
fields,
use_callt,
token_patches,
);
}
ValueType::Array(_) => {
emit_store_array_field_deep_copy(
bytecode,
use_callt,
token_patches,
);
}
_ => {
bytecode.push(0x50); emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Put");
}
}
}
bytecode.push(0x45); bytecode.push(0x45); }
_ => {
emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Put");
}
}
}
fn emit_store_array_field_deep_copy(
bytecode: &mut Vec<u8>,
use_callt: bool,
token_patches: &mut Vec<MethodTokenPatch>,
) {
bytecode.push(0x4A); bytecode.push(0xCA);
let loop_start_pos = bytecode.len();
bytecode.push(0x4A); bytecode.push(0x10); bytecode.push(0x97); let jmp_exit_pos = bytecode.len();
bytecode.push(0x25); let jmp_exit_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
bytecode.push(0x9D);
bytecode.push(0x4A); emit_serialize_key(
bytecode,
&ValueType::Integer {
signed: false,
bits: 256,
},
use_callt,
token_patches,
); bytecode.push(0x13); bytecode.push(0x4D); bytecode.push(0x8B); emit_native_contract_call(
bytecode,
ir::NativeContract::CryptoLib,
"keccak256",
1,
use_callt,
token_patches,
);
bytecode.push(0x12); bytecode.push(0x4D); bytecode.push(0x12); bytecode.push(0x4D); bytecode.push(0xCE);
bytecode.push(0x50); emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Put");
let jmp_back_pos = bytecode.len();
bytecode.push(0x23); let jmp_back_operand = bytecode.len();
bytecode.extend_from_slice(&[0, 0, 0, 0]);
let rel_back = (loop_start_pos as i32)
.checked_sub(jmp_back_pos as i32)
.unwrap_or(0);
bytecode[jmp_back_operand..jmp_back_operand + 4].copy_from_slice(&rel_back.to_le_bytes());
let exit_pos = bytecode.len();
let rel_exit = (exit_pos as i32)
.checked_sub(jmp_exit_pos as i32)
.unwrap_or(0);
bytecode[jmp_exit_operand..jmp_exit_operand + 4].copy_from_slice(&rel_exit.to_le_bytes());
bytecode.push(0x45); bytecode.push(0xCA); bytecode.push(0x50); emit_syscall(bytecode, "System.Storage.GetContext");
emit_syscall(bytecode, "System.Storage.Put");
}