Skip to content

Commit

Permalink
feat: create first version of skeleton for kakarot ssj (#42)
Browse files Browse the repository at this point in the history
* feat: create first version of skeleton for kakarot ssj

* fix: run scarb fmt

* fix: use span

* fix: fix rebase on main

* chore: format

* fix: remove unused methods

* feat: change types to not use felts

* chore: remove max unused function
  • Loading branch information
Eikix authored Aug 14, 2023
1 parent e780f8d commit ea71ea2
Show file tree
Hide file tree
Showing 17 changed files with 141 additions and 98 deletions.
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 {
if exp == 0 {
return 1;
} else {
return base * pow(base, exp - 1);
}
}

0 comments on commit ea71ea2

Please sign in to comment.