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

Lucas/state reader #283

Merged
merged 12 commits into from Apr 24, 2023
5 changes: 5 additions & 0 deletions .codecov.yml
@@ -0,0 +1,5 @@
coverage:
status:
project:
default:
threshold: 1%
6 changes: 0 additions & 6 deletions .tarpaulin.toml

This file was deleted.

26 changes: 13 additions & 13 deletions benchmarking/scripts/starknet-erc20.yml
Expand Up @@ -7,20 +7,20 @@ config:
local:
target: "ws://127.0.0.1:9944"
phases:
- duration: 4
arrivalCount: 1 # Number of users
name: Users Connection
- pause: 60
name: Performance Testing
- duration: 4
arrivalCount: 1 # Number of users
name: Users Connection
- pause: 60
name: Performance Testing
variables:
nonce: 0
engines:
substrate: {}
substrate: {}
scenarios:
- engine: substrate
name: starknet_transfer
flow:
- loop:
- function: "executeERC20Transfer"
- log: "Executed ERC20 transfer {{ nonce }}"
count: 100000
- engine: substrate
name: starknet_transfer
flow:
- loop:
- function: "executeERC20Transfer"
- log: "Executed ERC20 transfer {{ nonce }}"
count: 100000
194 changes: 91 additions & 103 deletions crates/pallets/starknet/src/lib.rs

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions crates/pallets/starknet/src/mock.rs
Expand Up @@ -99,6 +99,7 @@
type LengthToFee = IdentityFee<u128>;
type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
}
pub const TOKEN_CONTRACT_CLASS_HASH: &str = "06232eeb9ecb5de85fc927599f144913bfee6ac413f2482668c9f03ce4d07922";

Check warning on line 102 in crates/pallets/starknet/src/mock.rs

View check run for this annotation

Codecov / codecov/patch

crates/pallets/starknet/src/mock.rs#L102

Added line #L102 was not covered by tests

// Build genesis storage according to the mock runtime.
pub fn new_test_ext() -> sp_io::TestExternalities {
Expand All @@ -124,7 +125,7 @@
let simple_account_address =
<[u8; 32]>::from_hex("000000000000000000000000000000000000000000000000000000000000000F").unwrap();
let simple_account_class_hash =
<[u8; 32]>::from_hex("000000000000000000000000000000000000000000000000000000000000000E").unwrap();
<[u8; 32]>::from_hex("0279d77db761fba82e0054125a6fdb5f6baa6286fa3fb73450cc44d193c2d37f").unwrap();

// ACCOUNT CONTRACT
// - ref testnet tx(0x06cfa9b097bec7a811e791b4c412b3728fb4cd6d3b84ae57db3a10c842b00740)
Expand All @@ -142,7 +143,7 @@
<[u8; 32]>::from_hex("01cb5d0b5b5146e1aab92eb9fc9883a32a33a604858bb0275ac0ee65d885bba8").unwrap();

// FEE CONTRACT
let token_class_hash_str = "0000000000000000000000000000000000000000000000000000000000010000";
let token_class_hash_str = TOKEN_CONTRACT_CLASS_HASH;
let token_class_hash_bytes = <[u8; 32]>::from_hex(token_class_hash_str).unwrap();
let fee_token_address =
<[u8; 32]>::from_hex("00000000000000000000000000000000000000000000000000000000000000AA").unwrap();
Expand Down
184 changes: 106 additions & 78 deletions crates/pallets/starknet/src/tests.rs
@@ -1,17 +1,12 @@
use core::str::FromStr;

use blockifier::execution::contract_class::ContractClass;
use blockifier::test_utils::{get_contract_class, ACCOUNT_CONTRACT_PATH, ERC20_CONTRACT_PATH};
use blockifier::test_utils::{get_contract_class, ACCOUNT_CONTRACT_PATH};
use frame_support::{assert_err, assert_ok, bounded_vec, debug, BoundedVec};
use hex::FromHex;
use hexlit::hex;
use lazy_static::lazy_static;
use mp_starknet::block::Header as StarknetHeader;
use mp_starknet::crypto::commitment;
use mp_starknet::crypto::hash::pedersen::PedersenHasher;
use mp_starknet::execution::{
CallEntryPointWrapper, ContractAddressWrapper, ContractClassWrapper, EntryPointTypeWrapper,
};
use mp_starknet::execution::{CallEntryPointWrapper, ContractClassWrapper, EntryPointTypeWrapper};
use mp_starknet::starknet_serde::transaction_from_json;
use mp_starknet::transaction::types::{EventWrapper, Transaction, TxType};
use sp_core::{H256, U256};
Expand Down Expand Up @@ -324,14 +319,16 @@ fn given_contract_declare_tx_works_once_not_twice() {
let none_origin = RuntimeOrigin::none();
let (account_addr, _, _) = account_helper(TEST_ACCOUNT_SALT);

let erc20_class = ContractClassWrapper::from(get_contract_class(ERC20_CONTRACT_PATH));
let erc20_class_hash =
<[u8; 32]>::from_hex("057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap();
let balance_contract = ContractClassWrapper::from(get_contract_class(include_bytes!(
"../../../../resources/declare/declare_test.json"
)));
let balance_contract_class_hash =
<[u8; 32]>::from_hex("0399998c787e0a063c3ac1d2abac084dcbe09954e3b156d53a8c43a02aa27d35").unwrap();

let mut transaction = Transaction {
sender_address: account_addr,
call_entrypoint: CallEntryPointWrapper::new(
Some(erc20_class_hash),
Some(balance_contract_class_hash),
EntryPointTypeWrapper::External,
None,
bounded_vec![],
Expand All @@ -346,7 +343,7 @@ fn given_contract_declare_tx_works_once_not_twice() {
Error::<Test>::ContractClassMustBeSpecified
);

transaction.contract_class = Some(erc20_class);
transaction.contract_class = Some(balance_contract);

assert_ok!(Starknet::declare(none_origin.clone(), transaction.clone()));
// TODO: Uncomment once we have ABI support
Expand Down Expand Up @@ -494,86 +491,117 @@ fn given_erc20_transfer_when_invoke_then_it_works() {
System::set_block_number(0);
run_to_block(1);
let origin = RuntimeOrigin::none();
let (sender_account, _, _) = account_helper(TEST_ACCOUNT_SALT);
// Declare ERC20 contract
declare_erc20(origin.clone(), sender_account);
let sender_account = <[u8; 32]>::from_hex("000000000000000000000000000000000000000000000000000000000000000F").unwrap();
// ERC20 is already declared for the fees.
// Deploy ERC20 contract
deploy_erc20(origin.clone(), sender_account);
let deploy_transaction = Transaction {
LucasLvy marked this conversation as resolved.
Show resolved Hide resolved
version: 1,
sender_address: sender_account,
call_entrypoint: CallEntryPointWrapper::new(
Some(<[u8;32]>::from_hex(TOKEN_CONTRACT_CLASS_HASH).unwrap()),
EntryPointTypeWrapper::External,
None,
bounded_vec![
U256::from(15), // Simple contract address
U256::from_str("0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8").unwrap(), // deploy_contract selector
U256::from_str("0x0000000000000000000000000000000000000000000000000000000000000009").unwrap(), // Calldata len
U256::from_str(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash
U256::one(), // Contract address salt
U256::from_str("0x0000000000000000000000000000000000000000000000000000000000000006").unwrap(), // Constructor_calldata_len
U256::from_str("0x000000000000000000000000000000000000000000000000000000000000000A").unwrap(), // Name
U256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), // Symbol
U256::from_str("0x0000000000000000000000000000000000000000000000000000000000000002").unwrap(), // Decimals
U256::from_str("0x000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply low
U256::from_str("0x000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply high
U256::from_big_endian(&sender_account) // recipient
],
sender_account,
sender_account,
),
hash: H256::from_str("0x06fc3466f58b5c6aaa6633d48702e1f2048fb96b7de25f2bde0bce64dca1d212").unwrap(),
signature: bounded_vec!(),
nonce: U256::one(),
contract_class: None,
contract_address_salt: None,
};
let expected_erc20_address = "0348571287631347b50c7d2b7011b22349919ea14e7065a45b79632a6891c608";

assert_ok!(Starknet::invoke(origin.clone(), deploy_transaction));

System::assert_last_event(
Event::StarknetEvent(EventWrapper {
keys: bounded_vec![
H256::from_str("0x026b160f10156dea0639bec90696772c640b9706a47f5b8c52ea1abe5858b34d").unwrap()
],
data: bounded_vec!(
H256::from_str(expected_erc20_address).unwrap(), // Contract address
H256::zero(), // Deployer (always 0 with this account contract)
H256::from_str(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000006").unwrap(), // Constructor calldata len
H256::from_str("0x000000000000000000000000000000000000000000000000000000000000000a").unwrap(), // Name
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), // Symbol
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000002").unwrap(), // Decimals
H256::from_str("0x000000000000000000000000000000000fffffffffffffffffffffffffffffff").unwrap(), // Initial supply low
H256::from_str("0x000000000000000000000000000000000fffffffffffffffffffffffffffffff").unwrap(), // Initial supply high
H256::from_str("0x000000000000000000000000000000000000000000000000000000000000000f").unwrap(), // Recipient
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), // Salt
),
from_address: sender_account,
})
.into(),
);

// TODO: use dynamic values to craft invoke transaction
// Transfer some token
invoke_transfer_erc20(origin, sender_account);
let transfer_transaction = Transaction {
version: 1,
sender_address: sender_account,
call_entrypoint: CallEntryPointWrapper::new(
Some(<[u8;32]>::from_hex("06232eeb9ecb5de85fc927599f144913bfee6ac413f2482668c9f03ce4d07922").unwrap()),
EntryPointTypeWrapper::External,
None,
bounded_vec![
U256::from_str(expected_erc20_address).unwrap(), // Token address
U256::from_str("0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e").unwrap(), // transfer selector
U256::from(3), // Calldata len
U256::from(16), // recipient
U256::from(15), // initial supply low
U256::zero(), // initial supply high
],
sender_account,
sender_account,
),
hash: H256::from_str("0x06fc3466f58b5c6aaa6633d48702e1f2048fb96b7de25f2bde0bce64dca1d213").unwrap(),
signature: bounded_vec!(),
nonce: U256::one(),
contract_class: None,
contract_address_salt: None,
};
// Also asserts that the deployment has been saved.
assert_ok!(Starknet::invoke(origin, transfer_transaction));
pretty_assertions::assert_eq!(Starknet::storage((<[u8; 32]>::from_hex(expected_erc20_address).unwrap(),H256::from_str("078e4fa4db2b6f3c7a9ece31571d47ac0e853975f90059f7c9df88df974d9093").unwrap())),U256::from_str("ffffffffffffffffffffffffffffff0").unwrap());
pretty_assertions::assert_eq!(Starknet::storage((<[u8; 32]>::from_hex(expected_erc20_address).unwrap(),H256::from_str("078e4fa4db2b6f3c7a9ece31571d47ac0e853975f90059f7c9df88df974d9094").unwrap())),U256::from_str("fffffffffffffffffffffffffffffff").unwrap());

pretty_assertions::assert_eq!(Starknet::storage((<[u8; 32]>::from_hex(expected_erc20_address).unwrap(),H256::from_str("0x011cb0dc747a73020cbd50eac7460edfaa7d67b0e05823b882b05c3f33b1c73e").unwrap())),U256::from(15));
pretty_assertions::assert_eq!(Starknet::storage((<[u8; 32]>::from_hex(expected_erc20_address).unwrap(),H256::from_str("0x011cb0dc747a73020cbd50eac7460edfaa7d67b0e05823b882b05c3f33b1c73f").unwrap())),U256::zero());


System::assert_last_event(
Event::StarknetEvent(EventWrapper {
keys: bounded_vec![
H256::from_str("0x0099cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9").unwrap()
],
data: bounded_vec!(
H256::from_str("0x000000000000000000000000000000000000000000000000000000000000000f").unwrap(),
H256::from_str("0x01176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8").unwrap(),
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000002").unwrap(),
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
H256::from_str("0x000000000000000000000000000000000000000000000000000000000000000F").unwrap(), // From
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000010").unwrap(), // To
H256::from_str("0x000000000000000000000000000000000000000000000000000000000000000F").unwrap(), // Amount low
H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), // Amount high
),
from_address: H256::from_str("0x0074c41dd9ba722396796cba415f8a742d671eb872371c96ce1ce6016fd0f2bb")
from_address: H256::from_str("0x0348571287631347b50c7d2b7011b22349919ea14e7065a45b79632a6891c608")
.unwrap()
.to_fixed_bytes(),
})
.into(),
);
})
}

/// Helper function to declare ERC20 contract.
/// # Arguments
/// * `origin` - The origin of the transaction.
/// * `sender_account` - The address of the sender account.
fn declare_erc20(origin: RuntimeOrigin, sender_account: ContractAddressWrapper) {
let declare_transaction = Transaction {
sender_address: sender_account,
call_entrypoint: CallEntryPointWrapper::new(
Some(ERC20_CLASS_HASH),
EntryPointTypeWrapper::External,
None,
bounded_vec![],
sender_account,
sender_account,
),
contract_class: Some(ERC20_CONTRACT_CLASS.clone()),
..Transaction::default()
};
assert_ok!(Starknet::declare(origin, declare_transaction));
}

/// Helper function to deploy ERC20 contract.
/// # Arguments
/// * `origin` - The origin of the transaction.
/// * `sender_account` - The address of the sender account.
fn deploy_erc20(origin: RuntimeOrigin, _sender_account: ContractAddressWrapper) {
let deploy_transaction = transaction_from_json(
include_str!("../../../../resources/transactions/deploy_erc20.json"),
include_bytes!("../../../../resources/account/account.json"),
)
.unwrap();
assert_ok!(Starknet::invoke(origin, deploy_transaction));
}

/// Helper function to mint some tokens.
/// # Arguments
/// * `origin` - The origin of the transaction.
/// * `sender_account` - The address of the sender account.
fn invoke_transfer_erc20(origin: RuntimeOrigin, _sender_account: ContractAddressWrapper) {
let erc20_mint_tx_json: &str = include_str!("../../../../resources/transactions/invoke_erc20_transfer.json");
let erc20_mint_tx = transaction_from_json(erc20_mint_tx_json, &[]).expect("Failed to create Transaction from JSON");
assert_ok!(Starknet::invoke(origin, erc20_mint_tx));
}

lazy_static! {
static ref ERC20_CONTRACT_CLASS: ContractClassWrapper =
get_contract_class_wrapper(include_bytes!("../../../../resources/erc20/erc20.json"));
}
const ERC20_CLASS_HASH: [u8; 32] = hex!("01d1aacf8f874c4a865b974236419a46383a5161925626e9053202d8e87257e9");

fn get_contract_class_wrapper(contract_content: &'static [u8]) -> ContractClassWrapper {
let contract_class: ContractClass =
serde_json::from_slice(contract_content).expect("File must contain the content of a compiled contract.");
ContractClassWrapper::from(contract_class)
}
9 changes: 4 additions & 5 deletions crates/primitives/starknet/src/execution/mod.rs
Expand Up @@ -9,8 +9,7 @@
use blockifier::block_context::BlockContext;
use blockifier::execution::contract_class::ContractClass;
use blockifier::execution::entry_point::{CallEntryPoint, CallInfo, CallType, ExecutionContext, ExecutionResources};
use blockifier::state::cached_state::CachedState;
use blockifier::state::state_api::StateReader;
use blockifier::state::state_api::State;
use blockifier::transaction::objects::AccountTransactionContext;
use frame_support::BoundedVec;
use serde_json::{from_slice, to_string};
Expand Down Expand Up @@ -67,9 +66,9 @@

/// Convert to starknet contract class.
pub fn to_starknet_contract_class(&self) -> Result<ContractClass, serde_json::Error> {
let program = from_slice::<Program>(self.program.as_ref())?;
let entrypoints =
from_slice::<HashMap<EntryPointType, vec::Vec<EntryPoint>>>(self.entry_points_by_type.as_ref())?;
let program = from_slice::<Program>(self.program.as_ref())?;
Ok(ContractClass { program, abi: None, entry_points_by_type: entrypoints })
}
}
Expand Down Expand Up @@ -278,9 +277,9 @@
/// # Returns
///
/// * The result of the entry point execution.
pub fn execute<S: StateReader>(
pub fn execute<S: State>(

Check warning on line 280 in crates/primitives/starknet/src/execution/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/primitives/starknet/src/execution/mod.rs#L280

Added line #L280 was not covered by tests
&self,
state: &mut CachedState<S>,
state: &mut S,

Check warning on line 282 in crates/primitives/starknet/src/execution/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/primitives/starknet/src/execution/mod.rs#L282

Added line #L282 was not covered by tests
block: StarknetBlock,
fee_token_address: ContractAddressWrapper,
) -> EntryPointExecutionResultWrapper<CallInfo> {
Expand Down
7 changes: 3 additions & 4 deletions crates/primitives/starknet/src/transaction/mod.rs
Expand Up @@ -7,8 +7,7 @@ use alloc::vec;
use blockifier::block_context::BlockContext;
use blockifier::execution::contract_class::ContractClass;
use blockifier::execution::entry_point::{CallInfo, ExecutionResources};
use blockifier::state::cached_state::CachedState;
use blockifier::state::state_api::StateReader;
use blockifier::state::state_api::State;
use blockifier::transaction::errors::TransactionExecutionError;
use blockifier::transaction::objects::AccountTransactionContext;
use blockifier::transaction::transactions::Executable;
Expand Down Expand Up @@ -328,9 +327,9 @@ impl Transaction {
///
/// * `TransactionExecutionResult<TransactionExecutionInfo>` - The result of the transaction
/// execution
pub fn execute<S: StateReader>(
pub fn execute<S: State>(
&self,
state: &mut CachedState<S>,
state: &mut S,
block: StarknetBlock,
tx_type: TxType,
contract_class: Option<ContractClass>,
Expand Down
9 changes: 1 addition & 8 deletions resources/account/account.cairo
Expand Up @@ -13,13 +13,7 @@ from starkware.starknet.common.syscalls import (

@event
func ContractDeployed(
address: felt,
deployer: felt,
classHash: felt,
calldata_len: felt,
calldata: felt*,
salt: felt,
metadata: felt,
address: felt, deployer: felt, classHash: felt, calldata_len: felt, calldata: felt*, salt: felt
) {
}

Expand Down Expand Up @@ -73,7 +67,6 @@ func deploy_contract{syscall_ptr: felt*, range_check_ptr}(
calldata_len=constructor_calldata_len,
calldata=constructor_calldata,
salt=contract_address_salt,
metadata='fuck Abdel',
);
return (contract_address=0);
}