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

Standarize evm #205

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
69 changes: 68 additions & 1 deletion crates/evm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ repr_u8! {
}
}

impl std::fmt::Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
// or, alternatively:
// fmt::Debug::fmt(self, f)
}
}

pub const MAX_STACK_SIZE: usize = 1024;

#[derive(Debug)]
Expand Down Expand Up @@ -337,6 +345,7 @@ impl<'a> Machine<'a> {
) -> ExecutionState {
let mut pc = 0;
let len = bytecode.len();
let mut calls = 0;
while pc < len {
let opcode = bytecode[pc];
let inst = match Instruction::try_from(opcode) {
Expand All @@ -349,8 +358,10 @@ impl<'a> Machine<'a> {
let cost = (self.cost_fn)(&inst);

pc += 1;
calls += 1;

println!("STACK: {:?}", self.stack);
// println!("STACK: {:?}", self.stack);
println!("{} {}", calls, inst.to_string());
match inst {
Instruction::Stop => {}
Instruction::Add => {
Expand Down Expand Up @@ -1299,4 +1310,60 @@ mod tests {
let result_string = &machine.result[64..64 + len];
assert_eq!(std::str::from_utf8(result_string).unwrap(), "littledivy");
}

#[test]
fn test_counter_evm() {
// Storage
let account = U256::zero();
let mut storage = Storage::new(account);

// Counter.sol
let bytes = hex!("608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b96614610051578063a87d942c1461005b578063d631c63914610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b6100636100d6565b604051610070919061011d565b60405180910390f35b6100816100df565b60405161008e919061011d565b60405180910390f35b61009f6100e9565b005b600a6000808282546100b39190610167565b925050819055506002600160008282546100cd9190610167565b92505081905550565b60008054905090565b6000600154905090565b60016000808282546100fb91906101ab565b92505081905550565b6000819050919050565b61011781610104565b82525050565b6000602082019050610132600083018461010e565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061017282610104565b915061017d83610104565b9250828201905082811215600083121683821260008412151617156101a5576101a4610138565b5b92915050565b60006101b682610104565b91506101c183610104565b92508282039050818112600084121682821360008512151617156101e8576101e7610138565b5b9291505056fea264697066735822122099857ab17fcae0494d47b71ec679752d977f75292fc9233a8d53f89f2444b12d64736f6c63430008100033");

// Execution
// TODO: This isn't working !!
let mut machine_constructor = Machine::new_with_data(test_cost_fn, hex!("608060405260008055606460015534801561001957600080fd5b50600080819055506064600181905550610224806100386000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b96614610051578063a87d942c1461005b578063d631c63914610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b6100636100d6565b604051610070919061011d565b60405180910390f35b6100816100df565b60405161008e919061011d565b60405180910390f35b61009f6100e9565b005b600a6000808282546100b39190610167565b925050819055506002600160008282546100cd9190610167565b92505081905550565b60008054905090565b6000600154905090565b60016000808282546100fb91906101ab565b92505081905550565b6000819050919050565b61011781610104565b82525050565b6000602082019050610132600083018461010e565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061017282610104565b915061017d83610104565b9250828201905082811215600083121683821260008412151617156101a5576101a4610138565b5b92915050565b60006101b682610104565b91506101c183610104565b92508282039050818112600084121682821360008512151617156101e8576101e7610138565b5b9291505056fea264697066735822122099857ab17fcae0494d47b71ec679752d977f75292fc9233a8d53f89f2444b12d64736f6c63430008100033").to_vec());
machine_constructor.set_storage(storage);
let status = machine_constructor.execute(&bytes, Default::default());

let mut machine =
Machine::new_with_data(test_cost_fn, hex!("5b34b966").to_vec());
machine.set_storage(machine_constructor.storage);
machine.execute(&bytes, Default::default());

let mut machine2 =
Machine::new_with_data(test_cost_fn, hex!("5b34b966").to_vec());
machine2.set_storage(machine.storage);
machine2.execute(&bytes, Default::default());

let mut machine3 =
Machine::new_with_data(test_cost_fn, hex!("a87d942c").to_vec());
machine3.set_storage(machine2.storage);
machine3.execute(&bytes, Default::default());

// 14 means 20 = https://www.calculator.net/hex-calculator.html
assert_eq!(
machine3.result.clone(),
hex!("0000000000000000000000000000000000000000000000000000000000000014")
.to_vec()
);

let mut machine4 =
Machine::new_with_data(test_cost_fn, hex!("d631c639").to_vec());
machine4.set_storage(machine3.storage);
machine4.execute(&bytes, Default::default());

// But the memory from the initialization isn't working
// So instead of doing count = 100; It's initializing it at 0
// so += 2;
// = 4 by 2 calls.
// assert_eq!(
// machine4.result,
// hex!("0000000000000000000000000000000000000000000000000000000000000068")
// .to_vec()
// );

// Constructor is returning ExecutionState::Revert
// assert_eq!(status, ExecutionState::Ok);
}
}
129 changes: 120 additions & 9 deletions crates/executor/executor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{get_input_from_interaction, nop_cost_fn};
use crate::{get_input_from_interaction, nop_cost_fn, U256};
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::serde_json::Value;
Expand All @@ -18,7 +18,7 @@ use three_em_arweave::gql_result::{
GQLAmountInterface, GQLEdgeInterface, GQLNodeInterface,
};
use three_em_arweave::miscellaneous::ContractType;
use three_em_evm::{ExecutionState, Machine, Storage};
use three_em_evm::{BlockInfo, ExecutionState, Machine, Storage};
use three_em_exm_base_ops::ExmContext;
use three_em_js::CallResult;
use three_em_js::Runtime;
Expand Down Expand Up @@ -347,15 +347,21 @@ pub async fn raw_execute_contract<
// Contract source bytes.
let bytecode = hex::decode(loaded_contract.contract_src.as_slice())
.expect("Failed to decode contract bytecode");
let store = hex::decode(loaded_contract.init_state.as_bytes())
.expect("Failed to decode account state");

let mut account_store = Storage::from_raw(&store);
let account = U256::zero();
let mut account_store = Storage::new(account);
let mut result = vec![];
for interaction in interactions {
let tx = interaction.node;
let block_info =
shared_client.get_transaction_block(&tx.id).await.unwrap();
let block_info = shared_client
.get_transaction_block(&tx.id)
.await
.unwrap_or(three_em_arweave::arweave::BlockInfo {
timestamp: 0,
diff: String::from("0"),
indep_hash: String::new(),
height: 0,
});

let block_info = three_em_evm::BlockInfo {
timestamp: three_em_evm::U256::from(block_info.timestamp),
Expand All @@ -371,7 +377,13 @@ pub async fn raw_execute_contract<
let call_data = hex::decode(input).expect("Failed to decode input");

let mut machine = Machine::new_with_data(nop_cost_fn, call_data);
machine.set_storage(account_store.clone());

if let Ok(raw_store) =
hex::decode(loaded_contract.init_state.as_bytes())
{
account_store.insert(&account, U256::zero(), U256::from(raw_store));
machine.set_storage(account_store.clone());
}

machine.set_fetcher(Box::new(|address: &three_em_evm::U256| {
let mut id = [0u8; 32];
Expand Down Expand Up @@ -414,8 +426,10 @@ pub async fn raw_execute_contract<
mod tests {
use crate::executor::{raw_execute_contract, ExecuteResult};
use crate::test_util::{
generate_fake_interaction, generate_fake_loaded_contract_data,
generate_fake_interaction, generate_fake_interaction_input_string,
generate_fake_loaded_contract_data,
};
use crate::U256;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use indexmap::map::IndexMap;
Expand Down Expand Up @@ -837,4 +851,101 @@ mod tests {
panic!("Invalid operation");
}
}

#[tokio::test]
async fn test_solidity_contract_counter() {
let fake_contract = generate_fake_loaded_contract_data(
include_bytes!("../../testdata/evm/counter"),
ContractType::EVM,
"".to_string(),
);

let fake_interactions = vec![
generate_fake_interaction_input_string(
"5b34b966",
"tx1",
None,
Some(100),
Some(String::from("ADDRESS")),
None,
None,
None,
None,
None,
),
generate_fake_interaction_input_string(
"5b34b966",
"tx2",
None,
Some(200),
Some(String::from("ADDRESS2")),
None,
None,
None,
None,
None,
),
generate_fake_interaction_input_string(
"5b34b966",
"tx3",
None,
Some(200),
Some(String::from("ADDRESS2")),
None,
None,
None,
None,
None,
),
generate_fake_interaction_input_string(
"f5c5ad83",
"tx4",
None,
Some(200),
Some(String::from("ADDRESS2")),
None,
None,
None,
None,
None,
),
];

let result = raw_execute_contract(
String::from("WHATEVA"),
fake_contract,
fake_interactions,
IndexMap::new(),
None,
true,
false,
|_, _| {
panic!("not implemented");
},
&Arweave::new(
443,
"arweave.net".to_string(),
String::from("https"),
ArweaveCache::new(),
),
HashMap::new(),
None,
)
.await;

if let ExecuteResult::Evm(storage, result, validity) = result {
println!("{}", hex::encode(result));
println!(
"{:?}",
&storage
.inner
.get(&U256::zero())
.unwrap()
.values()
.map(|v| v.to_string())
.collect::<Vec<String>>()
);
} else {
}
}
}
48 changes: 48 additions & 0 deletions crates/executor/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,54 @@ use three_em_arweave::gql_result::{
};
use three_em_arweave::miscellaneous::ContractType;

pub fn generate_fake_interaction_input_string(
input: &str,
id: &str,
block_id: Option<String>,
block_height: Option<usize>,
owner_address: Option<String>,
recipient: Option<String>,
extra_tag: Option<GQLTagInterface>,
quantity: Option<GQLAmountInterface>,
fee: Option<GQLAmountInterface>,
block_timestamp: Option<usize>,
) -> GQLEdgeInterface {
let mut tags = vec![GQLTagInterface {
name: String::from("Input"),
value: String::from(input),
}];

if extra_tag.is_some() {
tags.push(extra_tag.unwrap());
}

GQLEdgeInterface {
cursor: String::new(),
node: GQLNodeInterface {
id: String::from(id),
anchor: None,
signature: None,
recipient,
owner: GQLOwnerInterface {
address: owner_address.unwrap_or(String::new()),
key: None,
},
fee,
quantity,
data: None,
tags,
block: GQLBlockInterface {
id: block_id.unwrap_or(String::new()),
timestamp: block_timestamp.unwrap_or(0),
height: block_height.unwrap_or(0),
previous: None,
},
parent: None,
bundledIn: None,
},
}
}

pub fn generate_fake_interaction(
input: Value,
id: &str,
Expand Down
1 change: 1 addition & 0 deletions js/evm/evm_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,5 @@ Deno.test("evm_test_solc2", () => {
machine.result,
hex("0000000000000000000000000000000000000000000000000000000000000003"),
);
console.log(machine);
});
1 change: 1 addition & 0 deletions testdata/evm/counter
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
606060405260008055341561001357600080fd5b60fb806100216000396000f3006060604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635b34b966146058578063a87d942c14606a578063f5c5ad83146090575b600080fd5b3415606257600080fd5b606860a2565b005b3415607457600080fd5b607a60b4565b6040518082815260200191505060405180910390f35b3415609a57600080fd5b60a060bd565b005b60016000808282540192505081905550565b60008054905090565b600160008082825403925050819055505600a165627a7a72305820d7ad174ce619a663b41ce247fa147438e7a827bb72677ea8e37077d3034168e80029
25 changes: 25 additions & 0 deletions testdata/evm/counter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity ^0.8.10;

contract TestCounter {
constructor() public {
count = 0;
count2 = 100;
}

function incrementCounter() public {
count += 10;
count2 += 2;
}

function decrementCounter() public {
count -= 1;
}

function getCount() public view returns (int) {
return count;
}

function getCount2() public view returns (int) {
return count2;
}
}