Skip to content

Commit

Permalink
complete
Browse files Browse the repository at this point in the history
  • Loading branch information
TonioMacaronio committed May 30, 2019
1 parent bce4fb7 commit 79b2e27
Show file tree
Hide file tree
Showing 9 changed files with 1,343 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ authors = [
]

[dependencies]
data_restore = { path = "src/data_restore" }
eth_client = { path = "src/eth_client" }
plasma = { path = "src/plasma" }
models = { path = "src/models" }
Expand Down
18 changes: 18 additions & 0 deletions src/data_restore/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "data_restore"
version = "0.1.0"

[dependencies]
bigdecimal = { version = "0.1.0", features = ["serde"]}
futures = "0.1.26"
web3 = { git = "https://github.com/tomusdrw/rust-web3" }
tiny-keccak = "1.4.2"
ethabi = "7.0.0"
hex = "0.3.2"
sapling-crypto = { package = "sapling-crypto_ce", version = "0.0.5" }
ff = { package = "ff_ce", version = "0.6.0", features = ["derive"] }
pairing = { package = "pairing_ce", version = "0.17.0" }
tokio = "0.1"
bitvec = "0.11"

plasma = { path = "../plasma" }
425 changes: 425 additions & 0 deletions src/data_restore/src/accounts_state/mod.rs

Large diffs are not rendered by default.

373 changes: 373 additions & 0 deletions src/data_restore/src/block_events/mod.rs

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions src/data_restore/src/blocks/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::cmp::Ordering;
use web3::types::H256;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BlockType {
Committed,
Verified,
Unknown
}

#[derive(Debug, Copy, Clone, Eq)]
pub struct LogBlockData {
pub block_num: u32,
pub transaction_hash: H256,
pub block_type: BlockType
}

impl PartialOrd for LogBlockData {
fn partial_cmp(&self, other: &LogBlockData) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for LogBlockData {
fn cmp(&self, other: &LogBlockData) -> Ordering {
self.block_num.cmp(&other.block_num)
}
}

impl PartialEq for LogBlockData {
fn eq(&self, other: &LogBlockData) -> bool {
self.block_num == other.block_num
}
}
202 changes: 202 additions & 0 deletions src/data_restore/src/data_restore_driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
use web3::types::U256;
use franklin_transaction::FranklinTransaction;
use helpers::*;
use block_events::BlockEventsFranklin;
use accounts_state::FranklinAccountsStates;
use blocks::LogBlockData;
use std::sync::mpsc::Sender;
use plasma::models::Fr;

pub struct ProtoAccountsState {
errored: bool,
root_hash: Fr,
}

pub struct DataRestoreDriver {
pub channel: Option<Sender<ProtoAccountsState>>,
pub endpoint: InfuraEndpoint,
pub genesis_block: U256,
pub blocks_delta: U256,
pub run_updates: bool,
pub block_events: BlockEventsFranklin,
pub account_states: FranklinAccountsStates,
}

impl DataRestoreDriver {

pub fn new(endpoint: InfuraEndpoint, genesis_block: U256, blocks_delta: U256, channel: Option<Sender<ProtoAccountsState>>) -> Self {
Self {
channel: channel,
endpoint: endpoint,
genesis_block: genesis_block,
blocks_delta: blocks_delta,
run_updates: false,
block_events: BlockEventsFranklin::new(endpoint),
account_states: FranklinAccountsStates::new(endpoint),
}
}

pub fn load_past_state(&mut self) -> Result<(), DataRestoreError> {
println!("Loading past state");
let states = DataRestoreDriver::get_past_franklin_blocks_events_and_accounts_tree_state(self.endpoint, self.genesis_block, self.blocks_delta).map_err(|e| DataRestoreError::NoData(e.to_string()))?;
self.block_events = states.0;
self.account_states = states.1;

// let accs = &self.account_states.get_accounts();
// println!("Accs: {:?}", accs);
let root = &self.account_states.root_hash();
println!("Root: {:?}", &root);
println!("______________");

if let Some(ref _channel) = self.channel {
let state = ProtoAccountsState {
errored: false,
root_hash: root.clone(),
};
let _send_result = _channel.send(state);
if _send_result.is_err() {
return Err(DataRestoreError::StateUpdate("Cant send last state".to_string()));
}
}
println!("Finished loading past state");
Ok(())
}

pub fn stop_state_updates(&mut self) {
self.run_updates = false
}

pub fn run_state_updates(&mut self) -> Option<DataRestoreError> {
println!("Start state updates");
self.run_updates = true;
let mut err: Option<DataRestoreError> = None;
while self.run_updates {
match DataRestoreDriver::update_franklin_blocks_events_and_accounts_tree_state(self) {
Err(error) => {
println!("Something goes wrong: {:?}", error);
self.run_updates = false;
err = Some(DataRestoreError::StateUpdate(format!("Error occured: {:?}", error)));
},
Ok(()) => {
// println!("Updated, last watched ethereum block: {:?}", &self.block_events.last_watched_block_number);
// println!("Committed franklin blocks count: {:?}", &self.block_events.committed_blocks.len());
// println!("Last committed franklin block: {:?}", &self.block_events.committed_blocks.last());
// println!("Verified franklin blocks count: {:?}", &self.block_events.verified_blocks.len());
// println!("Last verified franklin block: {:?}", &self.block_events.verified_blocks.last());
// let accs = self.account_states.get_accounts();
// let root = self.account_states.root_hash();
// println!("Accs: {:?}", accs);
// println!("Root: {:?}", &root);
},
};
let root = self.account_states.root_hash();
println!("New root: {:?}", &root);
println!("______________");
if let Some(ref _channel) = self.channel {
let state = ProtoAccountsState {
errored: !self.run_updates,
root_hash: root.clone(),
};
let _send_result = _channel.send(state);
if _send_result.is_err() {
self.run_updates = false;
err = Some(DataRestoreError::StateUpdate("Cant send last state".to_string()));
}
}
}
println!("Stopped state updates");
return err;
}

fn get_past_franklin_blocks_events_and_accounts_tree_state(endpoint: InfuraEndpoint, genesis_block: U256, blocks_delta: U256) -> Result<(BlockEventsFranklin, FranklinAccountsStates), DataRestoreError> {
let events_state = DataRestoreDriver::get_past_blocks_state(endpoint, genesis_block, blocks_delta).map_err(|e| DataRestoreError::NoData(e.to_string()))?;
// println!("Last watched block: {:?}", events_state.last_watched_block_number);
let verified_blocks = events_state.verified_blocks.clone();
let txs = DataRestoreDriver::get_verified_committed_blocks_transactions_from_blocks_state(&events_state, &verified_blocks);
let sorted_txs = DataRestoreDriver::sort_transactions_by_block_number(txs);
// println!("Transactions: {:?}", sorted_txs);

let mut accounts_state = FranklinAccountsStates::new(endpoint);
let _ = DataRestoreDriver::update_accounts_state_from_transactions(&mut accounts_state, &sorted_txs).map_err(|e| DataRestoreError::StateUpdate(e.to_string()))?;
println!("Accounts and events state finished update");
Ok((events_state, accounts_state))
}

fn get_past_blocks_state(endpoint: InfuraEndpoint, genesis_block: U256, blocks_delta: U256) -> Result<BlockEventsFranklin, DataRestoreError> {
let events = BlockEventsFranklin::get_past_state_from_genesis_with_blocks_delta(endpoint, genesis_block, blocks_delta).map_err(|e| DataRestoreError::NoData(e.to_string()))?;
println!("Got past events state till ethereum block: {:?}", &events.last_watched_block_number);
println!("Committed franklin blocks count: {:?}", &events.committed_blocks.len());
println!("Last committed franklin block: {:?}", &events.committed_blocks.last());
println!("Verified franklin blocks count: {:?}", &events.verified_blocks.len());
println!("Last verified franklin block: {:?}", &events.verified_blocks.last());
Ok(events)
}

fn get_verified_committed_blocks_transactions_from_blocks_state(block_events_state: &BlockEventsFranklin, verified_blocks: &Vec<LogBlockData>) -> Vec<FranklinTransaction> {
let committed_blocks = block_events_state.get_only_verified_committed_blocks(verified_blocks);
// println!("Committed verified blocks: {:?}", committed_blocks);
let mut transactions = vec![];
for block in committed_blocks {
let tx = FranklinTransaction::get_transaction(block_events_state.endpoint, &block);
if tx.is_none() {
continue;
}
transactions.push(tx.unwrap());
}
println!("Transactions sorted: only verified commited");
transactions
}

fn sort_transactions_by_block_number(transactions: Vec<FranklinTransaction>) -> Vec<FranklinTransaction> {
let mut sorted_transactions = transactions;
sorted_transactions.sort_by_key(|x| x.block_number);
println!("Transactions sorted: by number");
sorted_transactions
}

fn update_accounts_state_from_transactions(state: &mut FranklinAccountsStates, transactions: &Vec<FranklinTransaction>) -> Result<(), DataRestoreError> {
// let mut state = accounts_state::FranklinAccountsStates::new(endpoint);
println!("Start accounts state updating");
for transaction in transactions {
let _ = state.update_accounts_states_from_transaction(&transaction).map_err(|e| DataRestoreError::StateUpdate(e.to_string()))?;
}
println!("Finished accounts state updating");
Ok(())
}

fn update_franklin_blocks_events_and_accounts_tree_state(data_restore_driver: &mut DataRestoreDriver) -> Result<(), DataRestoreError> {
let mut new_events: (Vec<LogBlockData>, Vec<LogBlockData>) = (vec![], vec![]);
while data_restore_driver.run_updates {
let ne = data_restore_driver.block_events.update_state_from_last_watched_block_with_blocks_delta_and_return_new_blocks(data_restore_driver.blocks_delta);
match ne {
Ok(result) => new_events = result,
Err(error) => {
println!("Got no events: {:?}", error);
continue
},
}
if new_events.1.is_empty() {
println!("No new verified blocks");
continue
// return Err(DataRestoreError::NoData("No verified blocks".to_string()))
} else {
println!("Got new events state till ethereum block: {:?}", &data_restore_driver.block_events.last_watched_block_number);
println!("Committed franklin blocks count: {:?}", &data_restore_driver.block_events.committed_blocks.len());
println!("Last committed franklin block: {:?}", &data_restore_driver.block_events.committed_blocks.last());
println!("Verified franklin blocks count: {:?}", &data_restore_driver.block_events.verified_blocks.len());
println!("Last verified franklin block: {:?}", &data_restore_driver.block_events.verified_blocks.last());
break
}
}
if !data_restore_driver.run_updates {
return Err(DataRestoreError::StateUpdate("Stopped getting new blocks".to_string()))
}
let verified_blocks = &new_events.1;
let txs = DataRestoreDriver::get_verified_committed_blocks_transactions_from_blocks_state(&data_restore_driver.block_events, &verified_blocks);
let sorted_txs = DataRestoreDriver::sort_transactions_by_block_number(txs);

let _ = DataRestoreDriver::update_accounts_state_from_transactions(&mut data_restore_driver.account_states, &sorted_txs).map_err(|e| DataRestoreError::StateUpdate(e.to_string()))?;

Ok(())
}
}
98 changes: 98 additions & 0 deletions src/data_restore/src/franklin_transaction/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use web3::futures::Future;
use web3::types::{H256, Transaction, TransactionId};

use helpers::*;
use blocks::LogBlockData;

#[derive(Debug, Copy, Clone)]
pub enum FranklinTransactionType {
Deposit,
Transfer,
FullExit,
Unknown
}

#[derive(Debug, Clone)]
pub struct FranklinTransaction {
pub network: InfuraEndpoint,
pub franklin_transaction_type: FranklinTransactionType,
pub block_number: u32,
pub ethereum_transaction: Transaction,
pub commitment_data: Vec<u8>,
}

impl FranklinTransaction {
pub fn get_transaction(network: InfuraEndpoint, franklin_block: &LogBlockData) -> Option<Self> {
let transaction = FranklinTransaction::get_ethereum_transaction(network, &franklin_block.transaction_hash)?;
let input_data = FranklinTransaction::get_input_data_from_ethereum_transaction(&transaction);
let tx_type = FranklinTransaction::get_transaction_type(&input_data);
let commitment_data = FranklinTransaction::get_commitment_data_from_input_data(&input_data)?;
let this = Self {
network: network,
franklin_transaction_type: tx_type,
block_number: franklin_block.block_num,
ethereum_transaction: transaction,
commitment_data: commitment_data,
};
Some(this)
}

fn get_ethereum_transaction(network: InfuraEndpoint, transaction_hash: &H256) -> Option<Transaction> {
let infura_endpoint = match network {
InfuraEndpoint::Mainnet => INFURA_MAINNET_ENDPOINT,
InfuraEndpoint::Rinkeby => INFURA_RINKEBY_ENDPOINT,
};
let (_eloop, transport) = web3::transports::Http::new(infura_endpoint).unwrap();
let web3 = web3::Web3::new(transport);
let tx_id = TransactionId::Hash(transaction_hash.clone());
let web3_transaction = web3.eth().transaction(tx_id).wait();
let tx = match web3_transaction {
Ok(tx) => {
tx
},
Err(_) => {
None
}
};
tx
}

fn get_input_data_from_ethereum_transaction(transaction: &Transaction) -> Vec<u8> {
transaction.clone().input.0
}

fn get_commitment_data_from_input_data(input_data: &Vec<u8>) -> Option<Vec<u8>> {
let input_data_contains_more_than_4_bytes = input_data.len() > 4;
let commitment_data = match input_data_contains_more_than_4_bytes {
true => Some(input_data[4..input_data.len()].to_vec()),
false => None
};
commitment_data
}

fn get_transaction_type(input_data: &Vec<u8>) -> FranklinTransactionType {
let input_data_contains_more_than_4_bytes = input_data.len() > 4;
if input_data_contains_more_than_4_bytes == false {
return FranklinTransactionType::Unknown
}
let deposit_method_bytes: Vec<u8> = vec![83, 61, 227, 10];
let transaction_method_bytes: Vec<u8> = vec![244, 135, 178, 142];
let full_exit_method_bytes: Vec<u8> = vec![121, 178, 173, 112];
let method_bytes: Vec<u8> = input_data[0..4].to_vec();
let method_type = match method_bytes {
_ if method_bytes == deposit_method_bytes => {
FranklinTransactionType::Deposit
},
_ if method_bytes == transaction_method_bytes => {
FranklinTransactionType::Transfer
},
_ if method_bytes == full_exit_method_bytes => {
FranklinTransactionType::FullExit
},
_ => {
FranklinTransactionType::Unknown
}
};
method_type
}
}
Loading

0 comments on commit 79b2e27

Please sign in to comment.