Skip to content

Commit

Permalink
Merge branch 'feature/evm' into canonbrother/ci-evm
Browse files Browse the repository at this point in the history
  • Loading branch information
canonbrother committed Apr 6, 2023
2 parents c2fd3be + 35c85d4 commit b677871
Show file tree
Hide file tree
Showing 20 changed files with 941 additions and 383 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,4 @@ src/secp256k1/src/ecmult_static_context.h
# EVM
src/evm/Cargo.lock
src/evm/target/
*.bin
2 changes: 2 additions & 0 deletions src/amount.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ struct DCT_ID {

static constexpr CAmount COIN = 100000000;
static constexpr CAmount CENT = 1000000;
static constexpr int64_t WEI_IN_GWEI = 1000000000;
static constexpr int64_t CAMOUNT_TO_WEI = 10;

//Converts the given value to decimal format string with COIN precision.
inline std::string GetDecimalString(CAmount nValue)
Expand Down
52 changes: 41 additions & 11 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3834,12 +3834,6 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
const auto sumFrom = SumAllTransfers(obj.from);
const auto sumTo = SumAllTransfers(obj.to);

if (obj.type == CTransferBalanceType::EvmIn || obj.type == CTransferBalanceType::EvmOut) {
for (const auto& [id, _] : sumFrom.balances)
if (id != DCT_ID{0})
return Res::Err("For EVM in/out transfers only DFI token is currently supported");
}

if (sumFrom != sumTo)
return Res::Err("sum of inputs (from) != sum of outputs (to)");

Expand All @@ -3851,18 +3845,54 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
if (!res)
return res;
} else if (obj.type == CTransferBalanceType::EvmIn) {
for (const auto& [addr, _] : obj.to) {
res = SubBalancesDelShares(obj.from);
if (!res)
return res;

for (const auto& [addr, balances] : obj.to) {
CTxDestination dest;
if (ExtractDestination(addr, dest)) {
if (dest.index() != WitV16KeyEthHashType) {
return Res::Err("To address must be an ETH address in case of \"evmin\" transfertype");
}
}

const auto toAddress = std::get<WitnessV16EthHash>(dest);

for (const auto& [id, amount] : balances.balances) {
if (id != DCT_ID{0}) {
return Res::Err("For EVM out transfers, only DFI token is currently supported");
}

arith_uint256 balanceIn = amount;
balanceIn *= CAMOUNT_TO_WEI * WEI_IN_GWEI;
evm_add_balance(evmContext, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).ToArrayReversed());
}
}
res = SubBalancesDelShares(obj.from);
if (!res)
return res;
} else if (obj.type == CTransferBalanceType::EvmOut) {
for (const auto& [addr, balances] : obj.from) {
CTxDestination dest;
if (ExtractDestination(addr, dest)) {
if (dest.index() != WitV16KeyEthHashType) {
return Res::Err("Invalid destination");
}
}

const auto fromAddress = std::get<WitnessV16EthHash>(dest);

for (const auto& [id, amount] : balances.balances) {
if (id != DCT_ID{0}) {
return Res::Err("For EVM out transfers, only DFI token is currently supported");
}

arith_uint256 balanceIn = amount;
balanceIn *= CAMOUNT_TO_WEI * WEI_IN_GWEI;
if (!evm_sub_balance(evmContext, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).ToArrayReversed())) {
return Res::Err("Not enough balance in %s to cover EVM out", EncodeDestination(dest));
}
}
}

res = AddBalancesSetShares(obj.to);
if (!res)
return res;
Expand Down Expand Up @@ -4085,7 +4115,7 @@ Res ApplyCustomTx(CCustomCSView &mnview,
PopulateVaultHistoryData(mnview.GetHistoryWriters(), view, txMessage, txType, height, txn, tx.GetHash());
}

res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, txn);
res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, txn, evmContext);

if (res) {
if (canSpend && txType == CustomTxType::UpdateMasternode) {
Expand Down
3 changes: 0 additions & 3 deletions src/masternodes/rpc_evm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#include <libain_evm.h>
#include <key_io.h>

const int64_t WEI_IN_GWEI = 1000000000;
const int64_t CAMOUNT_TO_WEI = 10;

UniValue evmtx(const JSONRPCRequest& request) {
auto pwallet = GetWallet(request);

Expand Down
1 change: 1 addition & 0 deletions src/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 24 additions & 11 deletions src/rust/crates/ain-evm-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::error::Error;
#[cxx::bridge]
mod ffi {
extern "Rust" {
fn evm_add_balance(address: &str, amount: [u8; 32]) -> Result<()>;
fn evm_sub_balance(address: &str, amount: [u8; 32]) -> Result<()>;
fn evm_add_balance(context: u64, address: &str, amount: [u8; 32]) -> Result<()>;
fn evm_sub_balance(context: u64, address: &str, amount: [u8; 32]) -> Result<bool>;
fn evm_validate_raw_tx(tx: &str) -> Result<bool>;

fn evm_get_context() -> u64;
Expand All @@ -33,39 +33,52 @@ mod ffi {
}
}

pub fn evm_add_balance(address: &str, amount: [u8; 32]) -> Result<(), Box<dyn Error>> {
RUNTIME.evm.add_balance(address, amount.into())
pub fn evm_add_balance(
context: u64,
address: &str,
amount: [u8; 32],
) -> Result<(), Box<dyn Error>> {
let address = address.parse()?;
Ok(RUNTIME.evm.add_balance(context, address, amount.into()))
}

pub fn evm_sub_balance(address: &str, amount: [u8; 32]) -> Result<(), Box<dyn Error>> {
RUNTIME.evm.sub_balance(address, amount.into())
pub fn evm_sub_balance(
context: u64,
address: &str,
amount: [u8; 32],
) -> Result<bool, Box<dyn Error>> {
let address = address.parse()?;
match RUNTIME.evm.sub_balance(context, address, amount.into()) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}

pub fn evm_validate_raw_tx(tx: &str) -> Result<bool, Box<dyn Error>> {
match RUNTIME.evm.validate_raw_tx(tx) {
match RUNTIME.handlers.evm.validate_raw_tx(tx) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}

pub fn evm_get_context() -> u64 {
RUNTIME.evm.get_context()
RUNTIME.handlers.evm.get_context()
}

fn evm_discard_context(context: u64) {
// TODO discard
RUNTIME.evm.discard_context(context)
RUNTIME.handlers.evm.discard_context(context)
}

fn evm_queue_tx(context: u64, raw_tx: &str) -> Result<bool, Box<dyn Error>> {
match RUNTIME.evm.queue_tx(context, raw_tx) {
match RUNTIME.handlers.evm.queue_tx(context, raw_tx) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}

use rlp::Encodable;
fn evm_finalise(context: u64, update_state: bool) -> Result<Vec<u8>, Box<dyn Error>> {
let (block, _failed_tx) = RUNTIME.evm.finalize_block(context, update_state)?;
let (block, _failed_tx) = RUNTIME.handlers.evm.finalize_block(context, update_state)?;
Ok(block.header.rlp_bytes().into())
}
15 changes: 5 additions & 10 deletions src/rust/crates/ain-evm-runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ain_evm_state::handler::EVMHandler;
use ain_evm_state::handler::Handlers;
use ain_evm_state::traits::PersistentState;
use ain_evm_state::EVM_STATE_PATH;
use jsonrpsee_http_server::HttpServerHandle;
use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
Expand All @@ -17,7 +16,7 @@ pub struct Runtime {
pub tx: Sender<()>,
pub handle: Mutex<Option<JoinHandle<()>>>,
pub jrpc_handle: Mutex<Option<HttpServerHandle>>, // dropping the handle kills server
pub evm: Arc<EVMHandler>,
pub handlers: Arc<Handlers>,
}

impl Runtime {
Expand All @@ -34,7 +33,7 @@ impl Runtime {
});
}))),
jrpc_handle: Mutex::new(None),
evm: Arc::new(EVMHandler::new()),
handlers: Arc::new(Handlers::new()),
}
}

Expand All @@ -49,11 +48,7 @@ impl Runtime {
.unwrap();

// Persist EVM State to disk
self.evm
.state
.write()
.unwrap()
.save_to_disk(EVM_STATE_PATH)
.unwrap();
self.handlers.evm.flush();
self.handlers.block.flush();
}
}
109 changes: 109 additions & 0 deletions src/rust/crates/ain-evm-state/src/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use crate::traits::PersistentState;
use ethereum::BlockAny;
use primitive_types::{H256, U256};
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io::{Read, Write};
use std::ops::Index;
use std::path::Path;
use std::sync::{Arc, RwLock};

pub static BLOCK_MAP_PATH: &str = "block_map.bin";
pub static BLOCK_DATA_PATH: &str = "block_data.bin";

type BlockHashtoBlock = HashMap<H256, U256>;
type Blocks = Vec<BlockAny>;

pub struct BlockHandler {
pub block_map: Arc<RwLock<BlockHashtoBlock>>,
pub blocks: Arc<RwLock<Blocks>>,
}

impl PersistentState for BlockHashtoBlock {
fn save_to_disk(&self, path: &str) -> Result<(), String> {
let serialized_state = bincode::serialize(self).map_err(|e| e.to_string())?;
let mut file = File::create(path).map_err(|e| e.to_string())?;
file.write_all(&serialized_state).map_err(|e| e.to_string())
}

fn load_from_disk(path: &str) -> Result<Self, String> {
if Path::new(path).exists() {
let mut file = File::open(path).map_err(|e| e.to_string())?;
let mut data = Vec::new();
file.read_to_end(&mut data).map_err(|e| e.to_string())?;
let new_state: HashMap<H256, U256> =
bincode::deserialize(&data).map_err(|e| e.to_string())?;
Ok(new_state)
} else {
Ok(Self::new())
}
}
}

impl PersistentState for Blocks {
fn save_to_disk(&self, path: &str) -> Result<(), String> {
let serialized_state = bincode::serialize(self).map_err(|e| e.to_string())?;
let mut file = File::create(path).map_err(|e| e.to_string())?;
file.write_all(&serialized_state).map_err(|e| e.to_string())
}

fn load_from_disk(path: &str) -> Result<Self, String> {
if Path::new(path).exists() {
let mut file = File::open(path).map_err(|e| e.to_string())?;
let mut data = Vec::new();
file.read_to_end(&mut data).map_err(|e| e.to_string())?;
let new_state: Vec<BlockAny> =
bincode::deserialize(&data).map_err(|e| e.to_string())?;
Ok(new_state)
} else {
Ok(Self::new())
}
}
}

impl BlockHandler {
pub fn new() -> Self {
Self {
block_map: Arc::new(RwLock::new(
BlockHashtoBlock::load_from_disk(BLOCK_MAP_PATH).unwrap(),
)),
blocks: Arc::new(RwLock::new(
Blocks::load_from_disk(BLOCK_DATA_PATH).unwrap(),
)),
}
}

pub fn connect_block(&self, block: BlockAny) {
let mut blocks = self.blocks.write().unwrap();
blocks.push(block.clone());

let mut blockhash = self.block_map.write().unwrap();
blockhash.insert(block.header.hash(), block.header.number);
}

pub fn flush(&self) {
let _ = self
.block_map
.write()
.unwrap()
.save_to_disk(BLOCK_MAP_PATH)
.unwrap();
let _ = self
.blocks
.write()
.unwrap()
.save_to_disk(BLOCK_DATA_PATH)
.unwrap();
}

pub fn get_block_hash(&self, hash: H256) -> Result<BlockAny, Box<dyn Error>> {
let block_map = self.block_map.read().unwrap();
let block_number = block_map.get(&hash).unwrap().clone();

let blocks = self.blocks.read().unwrap();
let block = blocks.get(block_number.as_usize()).unwrap().clone();

Ok(block)
}
}
Loading

0 comments on commit b677871

Please sign in to comment.