Skip to content

Commit

Permalink
Implementation of EIP-1153: Transient Storage using Disk Persistence …
Browse files Browse the repository at this point in the history
…and Lifecycle Management (#1588)

* initial implementation of EIP-1153: Transient Storage - TODOs remain around comparing the liveliness of the transient data and validating that functionality in a test

* fix transient state error message

* remove pub visibility from transient_data_lifespan. TODO still is combine transient_slots with transient_data_lifespan anyway.

* further implementation of lifecycle management for transient data, TODO reinitialize does not properly clear state KAMT due to clone/reference issues that are being debugged

* update evm contract State to use transient_data a composite of transient_data_state and transient_data_lifespan

* cargo fmt

* update comments on tests

* add tstorage test contract files

* use a non optimized delete method to clear transient storage. TODO update kamt lirbary to support a clear method

* failing tests that need to be investigated

* add test confirming transient storage is cleared

* more test debugging

* cargo fmt

* fix cargo check nit

* simplify transient test

* support nested and reentry in transient storage in integration tests

* progress on fixing removing tranisent storage lifespan from system, but still issues with reload

* use clear instead of loop and delete

* use kamt clear in reload

* unused var

* remove Options from transient data in state and handle None better to avoid panics

* add current_transient_data_lifespan to state and refactor get_current_transient_data_lifespan to be a free function

* fmt

* set in call to true because transient data calls message() which has that assertion

* Update actors/evm/src/interpreter/system.rs

Co-authored-by: Steven Allen <[email protected]>

* Revert "Update actors/evm/src/interpreter/system.rs"

This reverts commit 3d5deba.

* Revert "Revert "Update actors/evm/src/interpreter/system.rs""

This reverts commit 22963df.

* get get_current_transient_data_lifespan throw an error if it cannot form a valid object

* change transient data origin from id to Address

* Revert "change transient data origin from id to Address"

This reverts commit 3c6d9a7.

* remove test: origin is always an ID address

* remove unused import

* remove duplicate comment

* use self.current_transient_data_lifespan

* get_current_transient_data_lifespan does not need to be public

* remove match from get_current_transient_data_lifespan and use an unwrap because we have already validated the existance of an id

* remove error case from new

* remove allow non snake case from transient storage tests

* Update actors/evm/src/interpreter/system.rs

Co-authored-by: Steven Allen <[email protected]>

* Update actors/evm/tests/basic.rs

Co-authored-by: Rod Vagg <[email protected]>

* Update actors/evm/tests/contracts/TransientStorageTest.sol

Co-authored-by: Rod Vagg <[email protected]>

* Update actors/evm/tests/contracts/TransientStorageTest.sol

Co-authored-by: Rod Vagg <[email protected]>

* Update actors/evm/tests/contracts/TransientStorageTest.sol

Co-authored-by: Rod Vagg <[email protected]>

* remove now unused solidity test contracts that have previously been refactored into TransientStorageTest

* forge fmt and solc recompile

* add comments to transient storage test file with test information

---------

Co-authored-by: Steven Allen <[email protected]>
Co-authored-by: Rod Vagg <[email protected]>
  • Loading branch information
3 people authored Jan 14, 2025
1 parent b4ed8cf commit fdbdfc6
Show file tree
Hide file tree
Showing 19 changed files with 635 additions and 26 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ fvm_shared = "4.5.1"
fvm_ipld_encoding = "0.5.0"
fvm_ipld_blockstore = "0.3.0"
fvm_ipld_hamt = "0.10.2"
fvm_ipld_kamt = "0.4.2"
fvm_ipld_kamt = "0.4.3"
fvm_ipld_amt = { version = "0.7.3" }
fvm_ipld_bitfield = "0.7.0"

Expand Down
4 changes: 4 additions & 0 deletions actors/evm/src/interpreter/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub mod opcodes {
0x59: MSIZE,
0x5a: GAS,
0x5b: JUMPDEST,
0x5c: TLOAD,
0x5d: TSTORE,
0x5e: MCOPY,
0x5F: PUSH0,
0x60: PUSH1,
Expand Down Expand Up @@ -400,6 +402,8 @@ mod tests {
MSTORE8,
SLOAD,
SSTORE,
TLOAD,
TSTORE,
LOG0,
LOG1,
LOG2,
Expand Down
20 changes: 0 additions & 20 deletions actors/evm/src/interpreter/instructions/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ mod tests {
use cid::multihash::Multihash;
use cid::Cid;
use fil_actors_evm_shared::uints::U256;
use fil_actors_runtime::EAM_ACTOR_ID;
use fvm_ipld_encoding::{DAG_CBOR, IPLD_RAW};
use fvm_shared::address::Address as FilAddress;

Expand Down Expand Up @@ -364,25 +363,6 @@ mod tests {
};
}

#[test]
fn test_origin_ethaddr() {
let addr_bytes = hex_literal::hex!("FEEDFACECAFEBEEF000000000000000000001234");
let eth_addr = EthAddress(addr_bytes);
let fil_addr = FilAddress::new_delegated(EAM_ACTOR_ID, &addr_bytes).unwrap();
evm_unit_test! {
(rt) {
rt.in_call.replace(true);
rt.set_origin(fil_addr);
}
(m) {
ORIGIN;
}
m.step().expect("execution step failed");
assert_eq!(m.state.stack.len(), 1);
assert_eq!(m.state.stack.pop().unwrap(), eth_addr.as_evm_word());
};
}

#[test]
fn test_caller() {
evm_unit_test! {
Expand Down
2 changes: 2 additions & 0 deletions actors/evm/src/interpreter/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def_stdproc! { MSTORE(a, b) => memory::mstore }
def_stdproc! { MSTORE8(a, b) => memory::mstore8 }
def_stdfun! { SLOAD(a) => storage::sload }
def_stdproc! { SSTORE(a, b) => storage::sstore }
def_stdfun! { TLOAD(a) => storage::tload }
def_stdproc! { TSTORE(a, b) => storage::tstore }
def_stdfun! { MSIZE() => memory::msize }
def_stdfun! { GAS() => context::gas }
def_stdlog! { LOG0(0, ()) }
Expand Down
71 changes: 71 additions & 0 deletions actors/evm/src/interpreter/instructions/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ pub fn sstore(
system.set_storage(key, value)
}

#[inline]
pub fn tload(
_state: &mut ExecutionState,
system: &mut System<impl Runtime>,
location: U256,
) -> Result<U256, ActorError> {
// get from storage and place on stack
system.get_transient_storage(location)
}

#[inline]
pub fn tstore(
_state: &mut ExecutionState,
system: &mut System<impl Runtime>,
key: U256,
value: U256,
) -> Result<(), ActorError> {
if system.readonly {
return Err(ActorError::read_only("store called while read-only".into()));
}

system.set_transient_storage(key, value)
}

#[cfg(test)]
mod tests {
use fil_actors_evm_shared::uints::U256;
Expand Down Expand Up @@ -82,4 +106,51 @@ mod tests {
assert_eq!(m.system.get_storage(U256::from(0)).unwrap(), U256::from(0x42));
};
}

#[test]
fn test_tload() {
// happy path
evm_unit_test! {
(m) {
TLOAD;
}
m.system.set_transient_storage(U256::from(0), U256::from(0x42)).unwrap();
m.state.stack.push(U256::from(0)).unwrap();
let result = m.step();
assert!(result.is_ok(), "execution step failed");
assert_eq!(m.state.stack.len(), 1);
assert_eq!(m.state.stack.pop().unwrap(), U256::from(0x42));
};
}

#[test]
fn test_tload_oob() {
// oob access -- unitialized is zero
evm_unit_test! {
(m) {
TLOAD;
}
m.state.stack.push(U256::from(1234)).unwrap();
let result = m.step();
assert!(result.is_ok(), "execution step failed");
assert_eq!(m.state.stack.len(), 1);
assert_eq!(m.state.stack.pop().unwrap(), U256::from(0));
};
}

#[test]
fn test_tstore() {
evm_unit_test! {
(m) {
TSTORE;
}

m.state.stack.push(U256::from(0x42)).unwrap();
m.state.stack.push(U256::from(0)).unwrap();
let result = m.step();
assert!(result.is_ok(), "execution step failed");
assert_eq!(m.state.stack.len(), 0);
assert_eq!(m.system.get_transient_storage(U256::from(0)).unwrap(), U256::from(0x42));
};
}
}
20 changes: 20 additions & 0 deletions actors/evm/src/interpreter/precompiles/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ mod tests {
#[test]
fn bn_recover() {
let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let input = &hex!(
Expand Down Expand Up @@ -357,6 +359,8 @@ mod tests {
let input = "foo bar baz boxy".as_bytes();

let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let expected = hex!("ace8597929092c14bd028ede7b07727875788c7e130278b5afed41940d965aba");
Expand All @@ -370,6 +374,8 @@ mod tests {
let input = "foo bar baz boxy".as_bytes();

let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let expected = hex!("0000000000000000000000004cd7a0452bd3d682e4cbd5fa90f446d7285b156a");
Expand All @@ -389,6 +395,8 @@ mod tests {
);

let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let expected = hex!("08");
Expand Down Expand Up @@ -450,6 +458,8 @@ mod tests {
#[test]
fn bn_add() {
let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let input = hex::decode(
Expand Down Expand Up @@ -519,6 +529,8 @@ mod tests {
];

let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

for (f, name) in tests {
Expand Down Expand Up @@ -546,6 +558,8 @@ mod tests {
&[(blake2f, "fail-blake2f")];

let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

for (f, name) in failures {
Expand All @@ -561,6 +575,8 @@ mod tests {
#[test]
fn bn_mul() {
let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let input = hex::decode(
Expand Down Expand Up @@ -614,6 +630,8 @@ mod tests {
#[test]
fn bn_pair() {
let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

let input = hex::decode(
Expand Down Expand Up @@ -701,6 +719,8 @@ mod tests {
fn blake2() {
use super::blake2f;
let rt = MockRuntime::default();
rt.in_call.replace(true);

let mut system = System::create(&rt).unwrap();

// // helper to turn EIP test cases into something readable
Expand Down
Loading

0 comments on commit fdbdfc6

Please sign in to comment.