generated from keep-starknet-strange/alexandria
-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: contract account bytecode storage (#425)
* feat: storage of bytecode (full bytes31 words) * fix: renamed core_contracts to contracts
- Loading branch information
Showing
18 changed files
with
413 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//! Contract Account related functions, including bytecode storage | ||
|
||
use alexandria_storage::list::{List, ListTrait}; | ||
use hash::{HashStateTrait, HashStateExTrait}; | ||
use poseidon::PoseidonTrait; | ||
use starknet::{ | ||
StorageBaseAddress, storage_base_address_from_felt252, Store, EthAddress, SyscallResult, | ||
storage_write_syscall, storage_address_from_base, storage_read_syscall, | ||
storage_address_from_base_and_offset | ||
}; | ||
use utils::helpers::{ByteArrayExTrait}; | ||
use utils::storage::{compute_storage_base_address}; | ||
use utils::traits::{StorageBaseAddressIntoFelt252, StoreBytes31}; | ||
|
||
/// Stores the EVM bytecode of a contract account in Kakarot Core's contract storage. The bytecode is first packed | ||
/// into a ByteArray and then stored in the contract storage. | ||
/// # Arguments | ||
/// * `evm_address` - The EVM address of the contract account | ||
/// * `bytecode` - The bytecode to store | ||
fn store_bytecode(evm_address: EthAddress, bytecode: Span<u8>) { | ||
let packed_bytecode: ByteArray = ByteArrayExTrait::from_bytes(bytecode); | ||
// data_address is h(h(sn_keccak("contract_account_bytecode")), evm_address) | ||
let data_address = compute_storage_base_address( | ||
selector!("contract_account_bytecode"), array![evm_address.into()].span() | ||
); | ||
// We start storing the full 31-byte words of bytecode data at address | ||
// `data_address`. The `pending_word` and `pending_word_len` are stored at | ||
// address `data_address-2` and `data_address-1` respectively. | ||
//TODO(eni) replace with ListTrait::new() once merged in alexandria | ||
let mut stored_list: List<bytes31> = List { | ||
address_domain: 0, base: data_address, len: 0, storage_size: Store::<bytes31>::size() | ||
}; | ||
let pending_word_addr: felt252 = data_address.into() - 2; | ||
let pending_word_len_addr: felt252 = pending_word_addr + 1; | ||
|
||
// Store the `ByteArray` in the contract storage. | ||
Store::< | ||
felt252 | ||
>::write(0, storage_base_address_from_felt252(pending_word_addr), packed_bytecode.pending_word); | ||
Store::< | ||
usize | ||
>::write( | ||
0, | ||
storage_base_address_from_felt252(pending_word_len_addr), | ||
packed_bytecode.pending_word_len | ||
); | ||
stored_list.from_span(packed_bytecode.data.span()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
#[cfg(test)] | ||
mod test_contract_account; | ||
#[cfg(test)] | ||
mod test_kakarot_core; | ||
|
||
#[cfg(test)] | ||
mod test_ownable; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
use alexandria_storage::list::{List, ListTrait}; | ||
use contracts::contract_account::{store_bytecode}; | ||
use contracts::tests::utils::constants::EVM_ADDRESS; | ||
use starknet::{storage_base_address_from_felt252, Store}; | ||
use utils::storage::{compute_storage_base_address}; | ||
use utils::traits::{StoreBytes31, StorageBaseAddressIntoFelt252}; | ||
|
||
#[test] | ||
#[available_gas(20000000)] | ||
fn test_store_bytecode_word_not_full() { | ||
let byte_array: Array<u8> = array![0x01, 0x02, 0x03, // 3 elements | ||
]; | ||
let evm_address = EVM_ADDRESS(); | ||
store_bytecode(evm_address, byte_array.span()); | ||
|
||
// Address at which the bytecode should be stored | ||
let data_addr = compute_storage_base_address( | ||
selector!("contract_account_bytecode"), array![evm_address.into()].span() | ||
); | ||
let pending_word_addr = storage_base_address_from_felt252(data_addr.into() - 2_felt252); | ||
let pending_word_len_addr = storage_base_address_from_felt252(data_addr.into() - 1_felt252); | ||
|
||
let pending_word = Store::<felt252>::read(0, pending_word_addr).unwrap(); | ||
let pending_word_len = Store::<u32>::read(0, pending_word_len_addr).unwrap(); | ||
let list: List<bytes31> = Store::<List<bytes31>>::read(0, data_addr).unwrap(); | ||
let bytecode: ByteArray = ByteArray { | ||
data: list.array(), pending_word: pending_word, pending_word_len: pending_word_len | ||
}; | ||
|
||
assert(bytecode.pending_word_len == 3, 'pending word not 3'); | ||
assert(bytecode.pending_word == 0x010203, 'pending word not restituted'); | ||
assert(bytecode.data.len() == 0, 'data not empty'); | ||
} | ||
|
||
|
||
#[test] | ||
#[available_gas(20000000)] | ||
fn test_store_bytecode_one_word() { | ||
let byte_array: Array<u8> = array![ | ||
0x01, | ||
0x02, | ||
0x03, | ||
0x04, | ||
0x05, | ||
0x06, | ||
0x07, | ||
0x08, | ||
0x09, | ||
0x0A, | ||
0x0B, | ||
0x0C, | ||
0x0D, | ||
0x0E, | ||
0x0F, | ||
0x10, | ||
0x11, | ||
0x12, | ||
0x13, | ||
0x14, | ||
0x15, | ||
0x16, | ||
0x17, | ||
0x18, | ||
0x19, | ||
0x1A, | ||
0x1B, | ||
0x1C, | ||
0x1D, | ||
0x1E, | ||
0x1F, // 31 elements | ||
]; | ||
let evm_address = EVM_ADDRESS(); | ||
store_bytecode(evm_address, byte_array.span()); | ||
|
||
// Address at which the bytecode should be stored | ||
let data_addr = compute_storage_base_address( | ||
selector!("contract_account_bytecode"), array![evm_address.into()].span() | ||
); | ||
let pending_word_addr = storage_base_address_from_felt252(data_addr.into() - 2_felt252); | ||
let pending_word_len_addr = storage_base_address_from_felt252(data_addr.into() - 1_felt252); | ||
|
||
let pending_word = Store::<felt252>::read(0, pending_word_addr).unwrap(); | ||
let pending_word_len = Store::<u32>::read(0, pending_word_len_addr).unwrap(); | ||
let list: List<bytes31> = Store::<List<bytes31>>::read(0, data_addr).unwrap(); | ||
let bytecode: ByteArray = ByteArray { | ||
data: list.array(), pending_word: pending_word, pending_word_len: pending_word_len | ||
}; | ||
|
||
assert(bytecode.pending_word_len == 0, 'pending word len not empty'); | ||
assert(bytecode.pending_word == 0, 'pending word not empty'); | ||
let mut i: u32 = 0; | ||
loop { | ||
if i == byte_array.len() { | ||
break; | ||
} | ||
assert(bytecode[i] == *byte_array[i], 'stored bytecode error'); | ||
i += 1; | ||
} | ||
} | ||
|
||
#[test] | ||
#[available_gas(20000000)] | ||
fn test_store_bytecode_one_word_pending() { | ||
let byte_array: Array<u8> = array![ | ||
0x01, | ||
0x02, | ||
0x03, | ||
0x04, | ||
0x05, | ||
0x06, | ||
0x07, | ||
0x08, | ||
0x09, | ||
0x0A, | ||
0x0B, | ||
0x0C, | ||
0x0D, | ||
0x0E, | ||
0x0F, | ||
0x10, | ||
0x11, | ||
0x12, | ||
0x13, | ||
0x14, | ||
0x15, | ||
0x16, | ||
0x17, | ||
0x18, | ||
0x19, | ||
0x1A, | ||
0x1B, | ||
0x1C, | ||
0x1D, | ||
0x1E, | ||
0x1F, | ||
0x20, | ||
0x21 // 33 elements | ||
]; | ||
let evm_address = EVM_ADDRESS(); | ||
store_bytecode(evm_address, byte_array.span()); | ||
|
||
// Address at which the bytecode should be stored | ||
let data_addr = compute_storage_base_address( | ||
selector!("contract_account_bytecode"), array![evm_address.into()].span() | ||
); | ||
let pending_word_addr = storage_base_address_from_felt252(data_addr.into() - 2_felt252); | ||
let pending_word_len_addr = storage_base_address_from_felt252(data_addr.into() - 1_felt252); | ||
|
||
let pending_word = Store::<felt252>::read(0, pending_word_addr).unwrap(); | ||
let pending_word_len = Store::<u32>::read(0, pending_word_len_addr).unwrap(); | ||
let list: List<bytes31> = Store::<List<bytes31>>::read(0, data_addr).unwrap(); | ||
let bytecode: ByteArray = ByteArray { | ||
data: list.array(), pending_word: pending_word, pending_word_len: pending_word_len | ||
}; | ||
|
||
assert(bytecode.pending_word_len == 2, 'pending word len not two'); | ||
assert(bytecode.pending_word == 0x2021, 'pending word not restituted'); | ||
let mut i: u32 = 0; | ||
loop { | ||
if i == byte_array.len() { | ||
break; | ||
} | ||
assert(bytecode[i] == *byte_array[i], 'stored bytecode error'); | ||
i += 1; | ||
} | ||
} | ||
//TODO add a test with huge amount of bytecode - using SNFoundry and loading data from txt | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ mod eth_transaction; | |
mod rlp; | ||
mod traits; | ||
mod i256; | ||
mod storage; | ||
|
||
#[cfg(test)] | ||
mod tests; |
Oops, something went wrong.