Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/added/982.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New storage opcodes `SCLR`, `SRDD`, `SRDI`, `SWRD`, `SWRI`, `SUPD`, `SUPI`, `SPLD` and `SPCP` that allow working with variably-sized storage slots.
1 change: 1 addition & 0 deletions .changes/changed/982.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`SRW` instruction now allows and offset argument. All existing storage operations are internally changed to function with variably sized slots, maintaining full backwards compatibility.
27 changes: 24 additions & 3 deletions fuel-asm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! FuelVM instruction and opcodes representation.

#![recursion_limit = "256"]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "std", doc = include_str!("../README.md"))]
Expand Down Expand Up @@ -198,7 +199,7 @@ impl_instructions! {
"Clear a series of slots from contract storage."
0x37 SCWQ scwq [key_ptr: RegId status: RegId lenq: RegId]
"Load a word from contract storage."
0x38 SRW srw [dst: RegId status: RegId key_ptr: RegId]
0x38 SRW srw [dst: RegId status: RegId key_ptr: RegId imm: Imm06]
"Load a series of 32 byte slots from contract storage."
0x39 SRWQ srwq [dst_ptr: RegId status: RegId key_ptr: RegId lenq: RegId]
"Store a word in contract storage."
Expand Down Expand Up @@ -362,6 +363,25 @@ impl_instructions! {
0xbc ECOP ecop [dst_ptr: RegId curve_id: RegId operation_type: RegId points_ptr: RegId]
"Given some curve, performs a pairing on groups of points"
0xbe EPAR epar [success: RegId curve_id: RegId number_elements: RegId points_ptr: RegId]

"Clear a storage slot"
0xc0 SCLR sclr [key_ptr: RegId count: RegId]
"Read storage slot (register length)"
0xc1 SRDD srdd [dst_ptr: RegId key_ptr: RegId offset: RegId len: RegId]
"Read storage slot (immediate length)"
0xc2 SRDI srdi [dst_ptr: RegId key_ptr: RegId offset: RegId len: Imm06]
"Write to a storage slot (full overwrite) (register length)"
0xc3 SWRD swrd [key_ptr: RegId value_ptr: RegId len: RegId]
"Write to a storage slot (full overwrite) (immedidate length)"
0xc4 SWRI swri [key_ptr: RegId value_ptr: RegId len: Imm12]
"Update a storage slot (read+write) (register length)"
0xc5 SUPD supd [key_ptr: RegId value_ptr: RegId offset: RegId len: RegId]
"Update a storage slot (read+write) (immedidate length)"
0xc6 SUPI supi [key_ptr: RegId value_ptr: RegId offset: RegId len: Imm06]
"Storage preload"
0xc7 SPLD spld [len_dst: RegId key_ptr: RegId]
"Copy from preloaded storage slot"
0xc8 SPCP spcp [dst: RegId offset: RegId len_reg: RegId len_imm: Imm06]
}

impl Instruction {
Expand Down Expand Up @@ -1010,8 +1030,9 @@ fn check_predicate_allowed() {
if let Ok(repr) = Opcode::try_from(byte) {
let should_allow = match repr {
BAL | BHEI | BHSH | BURN | CALL | CB | CCP | CROO | CSIZ | LOG | LOGD
| MINT | RETD | RVRT | SMO | SCWQ | SRW | SRWQ | SWW | SWWQ | TIME
| TR | TRO => false,
| MINT | RETD | RVRT | SMO | SCWQ | SRW | SRWQ | SWW | SWWQ | SCLR
| SRDD | SRDI | SWRD | SWRI | SUPD | SUPI | SPLD | SPCP | TIME | TR
| TRO => false,
_ => true,
};
assert_eq!(should_allow, repr.is_predicate_allowed());
Expand Down
2 changes: 2 additions & 0 deletions fuel-asm/src/panic_reason.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ enum_from! {
CanNotGetGasPriceInPredicate = 0x40,
/// The owner of the transaction is unknown
OwnerIsUnknown = 0x41,
/// Storage operation out of bounds or exceeds maximum allowed size
StorageOutOfBounds = 0x42,
}
}

Expand Down
87 changes: 80 additions & 7 deletions fuel-tx/src/transaction/consensus_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,53 +818,83 @@ impl Default for TxParametersV1 {
)]
pub enum ScriptParameters {
V1(ScriptParametersV1),
V2(ScriptParametersV2),
}

impl ScriptParameters {
#[cfg(feature = "test-helpers")]
/// Default parameters just for testing.
pub const DEFAULT: Self = Self::V1(ScriptParametersV1::DEFAULT);
pub const DEFAULT: Self = Self::V2(ScriptParametersV2::DEFAULT);

/// Replace the max script length with the given argument
#[cfg(feature = "test-helpers")]
pub const fn with_max_script_length(self, max_script_length: u64) -> Self {
match self {
Self::V1(mut params) => {
params.max_script_length = max_script_length;
Self::V1(params)
}
Self::V2(mut params) => {
params.max_script_length = max_script_length;
Self::V2(params)
}
}
}

/// Replace the max script data length with the given argument
#[cfg(feature = "test-helpers")]
pub const fn with_max_script_data_length(self, max_script_data_length: u64) -> Self {
match self {
Self::V1(mut params) => {
params.max_script_data_length = max_script_data_length;
Self::V1(params)
}
Self::V2(mut params) => {
params.max_script_data_length = max_script_data_length;
Self::V2(params)
}
}
}

/// Replace the max
#[cfg(feature = "test-helpers")]
pub const fn with_max_storage_slot_length(
self,
max_storage_slot_length: u64,
) -> Self {
match self {
Self::V1(_) => {
panic!("ScriptParametersV1 does not support max_storage_slot_length");
}
Self::V2(mut params) => {
params.max_storage_slot_length = max_storage_slot_length;
Self::V2(params)
}
}
}
}

impl ScriptParameters {
/// Get the maximum script length
pub const fn max_script_length(&self) -> u64 {
match self {
Self::V1(params) => params.max_script_length,
Self::V2(params) => params.max_script_length,
}
}

/// Get the maximum script data length
pub const fn max_script_data_length(&self) -> u64 {
match self {
Self::V1(params) => params.max_script_data_length,
Self::V2(params) => params.max_script_data_length,
}
}
}

impl From<ScriptParametersV1> for ScriptParameters {
fn from(params: ScriptParametersV1) -> Self {
Self::V1(params)
/// Get the maximum script data length
pub const fn max_storage_slot_length(&self) -> u64 {
match self {
Self::V1(_) => 32, // Legacy slots are 32 bytes
Self::V2(params) => params.max_storage_slot_length,
}
}
}

Expand All @@ -885,6 +915,12 @@ pub struct ScriptParametersV1 {
pub max_script_data_length: u64,
}

impl From<ScriptParametersV1> for ScriptParameters {
fn from(params: ScriptParametersV1) -> Self {
Self::V1(params)
}
}

#[cfg(feature = "test-helpers")]
impl ScriptParametersV1 {
/// Default parameters just for testing.
Expand All @@ -901,6 +937,43 @@ impl Default for ScriptParametersV1 {
}
}

#[derive(
Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct ScriptParametersV2 {
/// Maximum length of script, in instructions.
pub max_script_length: u64,
/// Maximum length of script data, in bytes.
pub max_script_data_length: u64,
/// Maximum length of a storage slot value, in bytes.
/// Note that if this is set to less than 32, the legacy storage operations will
/// still allow using 32-byte slots.
pub max_storage_slot_length: u64,
}

impl From<ScriptParametersV2> for ScriptParameters {
fn from(params: ScriptParametersV2) -> Self {
Self::V2(params)
}
}

#[cfg(feature = "test-helpers")]
impl ScriptParametersV2 {
/// Default parameters just for testing.
pub const DEFAULT: Self = Self {
max_script_length: 1024 * 1024,
max_script_data_length: 1024 * 1024,
max_storage_slot_length: 1024 * 1024,
};
}

#[cfg(feature = "test-helpers")]
impl Default for ScriptParametersV2 {
fn default() -> Self {
Self::DEFAULT
}
}

/// Versioned contract parameters.
#[derive(
Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
Expand Down
Loading
Loading