Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create first version of skeleton for kakarot ssj #42

Merged
merged 8 commits into from
Aug 14, 2023
Merged
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
7 changes: 7 additions & 0 deletions src/contract_account/contract_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Migrate https://github.com/kkrt-labs/kakarot/blob/7ec7a96074394ddb592a2b6fbea279c6c5cb25a6/src/kakarot/accounts/contract/contract_account.cairo#L4
// Note that we don't need proxies anymore with the new idiomatic way to replace implementations.
// For now, as discussed with Shahar Papini, we can still use storage slots to store bytecode.
// That being said, we can modify the way we store it with new mappings and storage outlays to optimize steps.
// Use Traits, impls blocks and idiomatic Cairo 1.0


61 changes: 61 additions & 0 deletions src/eoa/eth_transaction.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use array::ArrayTrait;

struct EthereumTransaction {
nonce: u128,
gas_price: u128,
gas_limit: u128,
destination: EthAddress,
amount: u256,
payload: Span<felt252>,
tx_hash: u256,
v: u128,
r: u256,
s: u256,
}

trait EthTransaction {
/// Decode a legacy Ethereum transaction
/// This function decodes a legacy Ethereum transaction in accordance with EIP-155.
/// It returns transaction details including nonce, gas price, gas limit, destination address, amount, payload,
/// transaction hash, and signature (v, r, s). The transaction hash is computed by keccak hashing the signed
/// transaction data, which includes the chain ID in accordance with EIP-155.
/// # Arguments
/// tx_data The raw transaction data
fn decode_legacy_tx(tx_data: Span<u8>) -> EthereumTransaction;

/// Decode a modern Ethereum transaction
/// This function decodes a modern Ethereum transaction in accordance with EIP-2718.
/// It returns transaction details including nonce, gas price, gas limit, destination address, amount, payload,
/// transaction hash, and signature (v, r, s). The transaction hash is computed by keccak hashing the signed
/// transaction data, which includes the chain ID as part of the transaction data itself.
/// # Arguments
/// tx_data The raw transaction data
fn decode_tx(tx_data: Span<u8>) -> EthereumTransaction;

/// Check if a raw transaction is a legacy Ethereum transaction
/// This function checks if a raw transaction is a legacy Ethereum transaction by checking the transaction type
/// according to EIP-2718. If the transaction type is less than or equal to 0xc0, it's a legacy transaction.
/// # Arguments
/// - `tx_data` The raw transaction data
fn is_legacy_tx(tx_data: Span<u8>) -> bool;

/// Decode a raw Ethereum transaction
/// This function decodes a raw Ethereum transaction. It checks if the transaction
/// is a legacy transaction or a modern transaction, and calls the appropriate decode function
/// resp. `decode_legacy_tx` or `decode_tx` based on the result.
/// # Arguments
/// - `tx_data` The raw transaction data
fn decode(tx_data: Span<u8>) -> EthereumTransaction;

/// Validate an Ethereum transaction
/// This function validates an Ethereum transaction by checking if the transaction
/// is correctly signed by the given address, and if the nonce in the transaction
/// matches the nonce of the account.
/// It decodes the transaction using the decode function,
/// and then verifies the Ethereum signature on the transaction hash.
/// # Arguments
/// - `address` The ethereum address that is supposed to have signed the transaction
/// - `account_nonce` The nonce of the account
/// - `param tx_data` The raw transaction data
fn validate_eth_tx(address: EthAddress, account_nonce: u128, tx_data: Span<u8>) -> bool;
}
3 changes: 3 additions & 0 deletions src/eoa/externally_owned_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Migrate https://github.com/kkrt-labs/kakarot/blob/7ec7a96074394ddb592a2b6fbea279c6c5cb25a6/src/kakarot/accounts/eoa/externally_owned_account.cairo#L4


4 changes: 4 additions & 0 deletions src/eoa/rlp.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Reproduce the original rlp.cairo from https://github.com/kkrt-labs/kakarot/blob/7ec7a96074394ddb592a2b6fbea279c6c5cb25a6/src/utils/rlp.cairo#L18
// By using new Cairo idiomatic ways: Traits, Struct and impl blocks.


2 changes: 1 addition & 1 deletion src/interpreter.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl EVMInterpreterImpl of EVMInterpreterTrait {

// Check if PC is not out of bounds.
if pc >= bytecode_len {
utils::panic_with_code(errors::PC_OUT_OF_BOUNDS);
panic_with_felt252(errors::PC_OUT_OF_BOUNDS);
}

let opcode: u8 = *bytecode.at(pc);
Expand Down
36 changes: 18 additions & 18 deletions src/memory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl InternalMemoryMethods of InternalMemoryTrait {
/// * `offset_in_chunk` - The offset within the memory chunk to store the element at.
fn _store_element(ref self: Memory, element: u256, chunk_index: usize, offset_in_chunk: u32) {
let mask: u256 = helpers::pow256_rev(offset_in_chunk);
let mask_c: u256 = utils::pow(256, 16).into() / mask;
let mask_c: u256 = helpers::pow(256, 16).into() / mask;

// Split the 2 input bytes16 chunks at offset_in_chunk.
let (el_hh, el_hl) = u256_safe_div_rem(element.high.into(), u256_as_non_zero(mask_c));
Expand Down Expand Up @@ -264,22 +264,22 @@ impl InternalMemoryMethods of InternalMemoryTrait {
break ();
}

let current: felt252 = ((*elements[0]).into() * utils::pow(256, 15)
+ (*elements[1]).into() * utils::pow(256, 14)
+ (*elements[2]).into() * utils::pow(256, 13)
+ (*elements[3]).into() * utils::pow(256, 12)
+ (*elements[4]).into() * utils::pow(256, 11)
+ (*elements[5]).into() * utils::pow(256, 10)
+ (*elements[6]).into() * utils::pow(256, 9)
+ (*elements[7]).into() * utils::pow(256, 8)
+ (*elements[8]).into() * utils::pow(256, 7)
+ (*elements[9]).into() * utils::pow(256, 6)
+ (*elements[10]).into() * utils::pow(256, 5)
+ (*elements[11]).into() * utils::pow(256, 4)
+ (*elements[12]).into() * utils::pow(256, 3)
+ (*elements[13]).into() * utils::pow(256, 2)
+ (*elements[14]).into() * utils::pow(256, 1)
+ (*elements[15]).into() * utils::pow(256, 0));
let current: felt252 = ((*elements[0]).into() * helpers::pow(256, 15)
+ (*elements[1]).into() * helpers::pow(256, 14)
+ (*elements[2]).into() * helpers::pow(256, 13)
+ (*elements[3]).into() * helpers::pow(256, 12)
+ (*elements[4]).into() * helpers::pow(256, 11)
+ (*elements[5]).into() * helpers::pow(256, 10)
+ (*elements[6]).into() * helpers::pow(256, 9)
+ (*elements[7]).into() * helpers::pow(256, 8)
+ (*elements[8]).into() * helpers::pow(256, 7)
+ (*elements[9]).into() * helpers::pow(256, 6)
+ (*elements[10]).into() * helpers::pow(256, 5)
+ (*elements[11]).into() * helpers::pow(256, 4)
+ (*elements[12]).into() * helpers::pow(256, 3)
+ (*elements[13]).into() * helpers::pow(256, 2)
+ (*elements[14]).into() * helpers::pow(256, 1)
+ (*elements[15]).into() * helpers::pow(256, 0));

self.items.insert(chunk_index.into(), current.try_into().unwrap());
chunk_index += 1;
Expand Down Expand Up @@ -349,7 +349,7 @@ impl InternalMemoryMethods of InternalMemoryTrait {
// Compute mask.

let mask: u256 = helpers::pow256_rev(offset_in_chunk);
let mask_c: u256 = utils::pow(2, 128).into() / mask;
let mask_c: u256 = helpers::pow(2, 128).into() / mask;

// Read the words at chunk_index, +1, +2.
let w0: u128 = self.items.get(chunk_index.into());
Expand Down
3 changes: 3 additions & 0 deletions src/tests/contract_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// import modules tests/contract_account folder


3 changes: 3 additions & 0 deletions src/tests/contract_account/test_contract_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// tests go here


3 changes: 3 additions & 0 deletions src/tests/eoa.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// import modules from tests/eoa folder here


3 changes: 3 additions & 0 deletions src/tests/eoa/test_eth_transaction.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// tests go here


3 changes: 3 additions & 0 deletions src/tests/eoa/test_externally_owned_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// tests go here


3 changes: 3 additions & 0 deletions src/tests/eoa/test_rlp.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// tests go here


3 changes: 3 additions & 0 deletions src/tests/instructions.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// import modules from tests/instructions folder here


Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// tests for stop and arithmetic operations go here


17 changes: 10 additions & 7 deletions src/tests/test_memory.cairo
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use core::dict::Felt252DictTrait;
use core::debug::PrintTrait;
use kakarot::memory::{MemoryTrait, InternalMemoryTrait, MemoryPrintTrait};
use kakarot::utils::helpers;
use kakarot::utils;
use kakarot::{utils, utils::helpers};
use array::{ArrayTrait, SpanTrait};
use traits::{Into, TryInto};
use option::OptionTrait;
Expand Down Expand Up @@ -134,36 +133,40 @@ fn _load_should_load_an_element_from_the_memory_with_offset(offset: usize, low:
#[available_gas(200000000)]
fn test__load__should_load_an_element_from_the_memory_with_offset_1() {
_load_should_load_an_element_from_the_memory_with_offset(
8, 2 * utils::pow(256, 8).try_into().unwrap(), utils::pow(256, 8).try_into().unwrap()
8, 2 * helpers::pow(256, 8).try_into().unwrap(), helpers::pow(256, 8).try_into().unwrap()
);
}
#[test]
#[available_gas(200000000)]
fn test__load__should_load_an_element_from_the_memory_with_offset_2() {
_load_should_load_an_element_from_the_memory_with_offset(
7, 2 * utils::pow(256, 7).try_into().unwrap(), utils::pow(256, 7).try_into().unwrap()
7, 2 * helpers::pow(256, 7).try_into().unwrap(), helpers::pow(256, 7).try_into().unwrap()
);
}
#[test]
#[available_gas(200000000)]
fn test__load__should_load_an_element_from_the_memory_with_offset_3() {
_load_should_load_an_element_from_the_memory_with_offset(
23, 3 * utils::pow(256, 7).try_into().unwrap(), 2 * utils::pow(256, 7).try_into().unwrap()
23,
3 * helpers::pow(256, 7).try_into().unwrap(),
2 * helpers::pow(256, 7).try_into().unwrap()
);
}

#[test]
#[available_gas(200000000)]
fn test__load__should_load_an_element_from_the_memory_with_offset_4() {
_load_should_load_an_element_from_the_memory_with_offset(
33, 4 * utils::pow(256, 1).try_into().unwrap(), 3 * utils::pow(256, 1).try_into().unwrap()
33,
4 * helpers::pow(256, 1).try_into().unwrap(),
3 * helpers::pow(256, 1).try_into().unwrap()
);
}
#[test]
#[available_gas(200000000)]
fn test__load__should_load_an_element_from_the_memory_with_offset_5() {
_load_should_load_an_element_from_the_memory_with_offset(
63, 0, 4 * utils::pow(256, 15).try_into().unwrap()
63, 0, 4 * helpers::pow(256, 15).try_into().unwrap()
);
}

Expand Down
72 changes: 0 additions & 72 deletions src/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,75 +6,3 @@ mod helpers;
mod constants;
mod u256_signed_math;

/// Panic with a custom message.
/// # Arguments
/// * `msg` - The message to panic with. Must be a short string to fit in a felt252.
fn panic_with(err: felt252) {
let mut data = ArrayTrait::new();
data.append(err);
panic(data);
}

/// Convert a `felt252` to a `NonZero` type.
/// # Arguments
/// * `felt252` - The `felt252` to convert.
/// # Returns
/// * `Option::<NonZero::<felt252>>` - The `felt252` as a `NonZero` type.
/// * `Option::<NonZero::<felt252>>::None` - If `felt252` is 0.
fn to_non_zero(felt252: felt252) -> Option::<NonZero<felt252>> {
let res = felt252_is_zero(felt252);
match res {
zeroable::IsZeroResult::Zero(()) => Option::<NonZero<felt252>>::None(()),
zeroable::IsZeroResult::NonZero(val) => Option::<NonZero<felt252>>::Some(val),
}
}


/// Force conversion from `felt252` to `u128`.
fn unsafe_felt252_to_u128(a: felt252) -> u128 {
let res = integer::u128_try_from_felt252(a);
res.unwrap()
}

/// Perform euclidean division on `felt252` types.
fn unsafe_euclidean_div_no_remainder(a: felt252, b: felt252) -> felt252 {
let a_u128 = unsafe_felt252_to_u128(a);
let b_u128 = unsafe_felt252_to_u128(b);
integer::u128_to_felt252(a_u128 / b_u128)
}

fn unsafe_euclidean_div(a: felt252, b: felt252) -> (felt252, felt252) {
let a_u128 = unsafe_felt252_to_u128(a);
let b_u128 = unsafe_felt252_to_u128(b);
(integer::u128_to_felt252(a_u128 / b_u128), integer::u128_to_felt252(a_u128 % b_u128))
}

fn max(a: usize, b: usize) -> usize {
if a > b {
return a;
} else {
return b;
}
}

// Raise a number to a power.
/// * `base` - The number to raise.
/// * `exp` - The exponent.
/// # Returns
/// * `felt252` - The result of base raised to the power of exp.
fn pow(base: felt252, exp: felt252) -> felt252 {
if exp == 0 {
return 1;
} else {
return base * pow(base, exp - 1);
}
}

/// Panic with a custom code.
/// # Arguments
/// * `code` - The code to panic with. Must be a short string to fit in a felt252.
fn panic_with_code(code: felt252) {
let mut data = ArrayTrait::new();
data.append(code);
panic(data);
}
13 changes: 13 additions & 0 deletions src/utils/helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,16 @@ impl ArrayPartialEq<T, impl PartialEqImpl: PartialEq<T>> of PartialEq<Array<T>>
!ArrayPartialEq::eq(lhs, rhs)
}
}

// Raise a number to a power.
/// * `base` - The number to raise.
/// * `exp` - The exponent.
/// # Returns
/// * `felt252` - The result of base raised to the power of exp.
fn pow(base: felt252, exp: felt252) -> felt252 {
Eikix marked this conversation as resolved.
Show resolved Hide resolved
if exp == 0 {
return 1;
} else {
return base * pow(base, exp - 1);
}
}