summaryrefslogtreecommitdiff
path: root/eth-wire
diff options
context:
space:
mode:
authorAntoine A <>2022-02-24 17:19:11 +0100
committerAntoine A <>2022-02-24 17:19:11 +0100
commitf83ecda42ee694ade4e5f4e16ce019d92b3754f4 (patch)
tree3832beeb539f2671ba6239390f4bc0bb3087a689 /eth-wire
parentec1d6043820b5a5d37e46fe2d26f228528663d60 (diff)
downloaddepolymerization-f83ecda42ee694ade4e5f4e16ce019d92b3754f4.tar.gz
depolymerization-f83ecda42ee694ade4e5f4e16ce019d92b3754f4.tar.bz2
depolymerization-f83ecda42ee694ade4e5f4e16ce019d92b3754f4.zip
Add eth instrumentation test and fix eth bounce
Diffstat (limited to 'eth-wire')
-rw-r--r--eth-wire/src/bin/eth-wire-utils.rs6
-rw-r--r--eth-wire/src/lib.rs114
-rw-r--r--eth-wire/src/loops/worker.rs73
-rw-r--r--eth-wire/src/main.rs88
-rw-r--r--eth-wire/src/rpc.rs29
-rw-r--r--eth-wire/src/taler_util.rs4
6 files changed, 178 insertions, 136 deletions
diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs
index 5032036..16a3588 100644
--- a/eth-wire/src/bin/eth-wire-utils.rs
+++ b/eth-wire/src/bin/eth-wire-utils.rs
@@ -108,7 +108,7 @@ fn main() {
.as_ref()
.and_then(|it| it.data_dir.as_deref())
.or(args.datadir.as_deref());
- let mut rpc = Rpc::new(data_dir.unwrap().join("geth.ipc")).unwrap();
+ let mut rpc = Rpc::new(data_dir.unwrap_or(&PathBuf::from("/tmp/")).join("geth.ipc")).unwrap();
let passwd = password();
match args.cmd {
Cmd::Deposit(TransactionCmd {
@@ -143,7 +143,6 @@ fn main() {
to,
value,
nonce: None,
- gas: None,
gas_price: None,
data: Hex(vec![]),
})
@@ -188,7 +187,7 @@ fn main() {
}
Cmd::Balance { addr } => {
let addr = H160::from_str(&addr).unwrap();
- let balance = rpc.balance(&addr).unwrap();
+ let balance = rpc.get_balance(&addr).unwrap();
println!("{}", (balance / 10_000_000_000u64).as_u64());
}
Cmd::Connect { datadir } => {
@@ -215,7 +214,6 @@ fn main() {
from,
to: tx.to.unwrap(),
value: U256::zero(),
- gas: None,
gas_price: Some(U256::from(1u8)), // Bigger gas price to replace fee
data: Hex(vec![]),
nonce: Some(tx.nonce),
diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs
index b386006..923bdaf 100644
--- a/eth-wire/src/lib.rs
+++ b/eth-wire/src/lib.rs
@@ -14,17 +14,18 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-use common::url::Url;
-use ethereum_types::{Address, H256, U256, U64};
+use std::{str::FromStr, sync::atomic::AtomicU16};
+
+use common::{api_common::Amount, config::EthConfig, url::Url};
+use ethereum_types::{Address, H160, H256, U256, U64};
use metadata::{InMetadata, OutMetadata};
-use rpc::hex::Hex;
+use rpc::{hex::Hex, Transaction};
+use taler_util::{eth_payto_addr, taler_to_eth};
pub mod metadata;
pub mod rpc;
pub mod taler_util;
-const GWEI: u64 = 1_000_000_000;
-
impl rpc::Rpc {
pub fn deposit(
&mut self,
@@ -39,7 +40,6 @@ impl rpc::Rpc {
to,
value,
nonce: None,
- gas: None,
gas_price: None,
data: Hex(metadata.encode()),
})
@@ -59,7 +59,6 @@ impl rpc::Rpc {
to,
value,
nonce: None,
- gas: None,
gas_price: None,
data: Hex(metadata.encode()),
})
@@ -76,7 +75,6 @@ impl rpc::Rpc {
to: tx.from.expect("Cannot bounce coinbase transaction"),
value: bounce_value,
nonce: None,
- gas: None,
gas_price: None,
data: Hex(metadata.encode()),
};
@@ -85,13 +83,80 @@ impl rpc::Rpc {
// Deduce fee price from bounced value
request.value = request
.value
- .saturating_sub(fill.tx.gas * GWEI * fill.tx.gas_price);
+ .saturating_sub(fill.tx.gas * fill.tx.gas_price.or(fill.tx.max_fee_per_gas).unwrap());
Ok(if request.value.is_zero() {
None
} else {
Some(self.send_transaction(&request)?)
})
}
+
+ /// List new and removed transaction since the last sync state, returning a new sync state
+ pub fn list_since_sync_state(
+ &mut self,
+ address: &Address,
+ state: SyncState,
+ min_confirmation: u16,
+ ) -> rpc::Result<(Vec<(Transaction, u16)>, Vec<(Transaction, u16)>, SyncState)> {
+ let match_tx = |txs: Vec<Transaction>, conf: u16| -> Vec<(Transaction, u16)> {
+ txs.into_iter()
+ .filter_map(|tx| {
+ (tx.from == Some(*address) || tx.to == Some(*address)).then(|| (tx, conf))
+ })
+ .collect()
+ };
+
+ let mut txs = Vec::new();
+ let mut removed = Vec::new();
+
+ // Add pending transaction
+ txs.extend(match_tx(self.pending_transactions()?, 0));
+
+ let latest = self.latest_block()?;
+
+ let mut confirmation = 1;
+ let mut chain_cursor = latest.clone();
+
+ // Move until tip height
+ while chain_cursor.number.unwrap() != state.tip_height {
+ txs.extend(match_tx(chain_cursor.transactions, confirmation));
+ chain_cursor = self.block(&chain_cursor.parent_hash)?.unwrap();
+ confirmation += 1;
+ }
+
+ // Check if fork
+ if chain_cursor.hash.unwrap() != state.tip_hash {
+ let mut fork_cursor = self.block(&state.tip_hash)?.unwrap();
+ // Move until found common parent
+ while fork_cursor.hash != chain_cursor.hash {
+ txs.extend(match_tx(chain_cursor.transactions, confirmation));
+ removed.extend(match_tx(fork_cursor.transactions, confirmation));
+ chain_cursor = self.block(&chain_cursor.parent_hash)?.unwrap();
+ fork_cursor = self.block(&fork_cursor.parent_hash)?.unwrap();
+ confirmation += 1;
+ }
+ }
+
+ // Move until last conf
+ while chain_cursor.number.unwrap() > state.conf_height {
+ txs.extend(match_tx(chain_cursor.transactions, confirmation));
+ chain_cursor = self.block(&chain_cursor.parent_hash)?.unwrap();
+ confirmation += 1;
+ }
+
+ Ok((
+ txs,
+ removed,
+ SyncState {
+ tip_hash: latest.hash.unwrap(),
+ tip_height: latest.number.unwrap(),
+ conf_height: latest
+ .number
+ .unwrap()
+ .saturating_sub(U64::from(min_confirmation)),
+ },
+ ))
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -119,6 +184,37 @@ impl SyncState {
}
}
+const DEFAULT_CONFIRMATION: u16 = 24;
+const DEFAULT_BOUNCE_FEE: &'static str = "ETH:0.00001";
+pub struct WireState {
+ pub confirmation: AtomicU16,
+ pub max_confirmations: u16,
+ pub address: H160,
+ pub config: EthConfig,
+ pub bounce_fee: U256,
+}
+
+impl WireState {
+ pub fn from_taler_config(config: EthConfig) -> Self {
+ let init_confirmation = config.confirmation.unwrap_or(DEFAULT_CONFIRMATION);
+ Self {
+ confirmation: AtomicU16::new(init_confirmation),
+ max_confirmations: init_confirmation * 2,
+ address: eth_payto_addr(&config.payto).unwrap(),
+ bounce_fee: config_bounce_fee(&config),
+ config,
+ }
+ }
+}
+
+fn config_bounce_fee(config: &EthConfig) -> U256 {
+ let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
+ Amount::from_str(&config)
+ .ok()
+ .and_then(|a| taler_to_eth(&a).ok())
+ .expect("config value BOUNCE_FEE is no a valid ethereum amount")
+}
+
#[cfg(test)]
mod test {
use common::{rand::random, rand_slice};
diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs
index c6864c2..4f8b659 100644
--- a/eth-wire/src/loops/worker.rs
+++ b/eth-wire/src/loops/worker.rs
@@ -29,7 +29,7 @@ use eth_wire::{
taler_util::{eth_payto_url, eth_to_taler},
SyncState,
};
-use ethereum_types::{Address, H256, U256, U64};
+use ethereum_types::{Address, H256, U256};
use crate::{
fail_point::fail_point,
@@ -119,73 +119,6 @@ pub fn worker(mut rpc: AutoRpcWallet, mut db: AutoReconnectDb, state: &WireState
}
}
-/// List new and removed transaction since the last sync state, returning a new sync state
-fn list_since_block_state(
- rpc: &mut Rpc,
- address: &Address,
- state: SyncState,
- min_confirmation: u16,
-) -> LoopResult<(Vec<(Transaction, u16)>, Vec<(Transaction, u16)>, SyncState)> {
- let match_tx = |txs: Vec<Transaction>, conf: u16| -> Vec<(Transaction, u16)> {
- txs.into_iter()
- .filter_map(|tx| {
- (tx.from == Some(*address) || tx.to == Some(*address)).then(|| (tx, conf))
- })
- .collect()
- };
-
- let mut txs = Vec::new();
- let mut removed = Vec::new();
-
- // Add pending transaction
- txs.extend(match_tx(rpc.pending_transactions()?, 0));
-
- let latest = rpc.latest_block()?;
-
- let mut confirmation = 1;
- let mut chain_cursor = latest.clone();
-
- // Move until tip height
- while chain_cursor.number.unwrap() != state.tip_height {
- txs.extend(match_tx(chain_cursor.transactions, confirmation));
- chain_cursor = rpc.block(&chain_cursor.parent_hash)?.unwrap();
- confirmation += 1;
- }
-
- // Check if fork
- if chain_cursor.hash.unwrap() != state.tip_hash {
- let mut fork_cursor = rpc.block(&state.tip_hash)?.unwrap();
- // Move until found common parent
- while fork_cursor.hash != chain_cursor.hash {
- txs.extend(match_tx(chain_cursor.transactions, confirmation));
- removed.extend(match_tx(fork_cursor.transactions, confirmation));
- chain_cursor = rpc.block(&chain_cursor.parent_hash)?.unwrap();
- fork_cursor = rpc.block(&fork_cursor.parent_hash)?.unwrap();
- confirmation += 1;
- }
- }
-
- // Move until last conf
- while chain_cursor.number.unwrap() > state.conf_height {
- txs.extend(match_tx(chain_cursor.transactions, confirmation));
- chain_cursor = rpc.block(&chain_cursor.parent_hash)?.unwrap();
- confirmation += 1;
- }
-
- Ok((
- txs,
- removed,
- SyncState {
- tip_hash: latest.hash.unwrap(),
- tip_height: latest.number.unwrap(),
- conf_height: latest
- .number
- .unwrap()
- .saturating_sub(U64::from(min_confirmation)),
- },
- ))
-}
-
/// Parse new transactions, return true if the database is up to date with the latest mined block
fn sync_chain(
rpc: &mut Rpc,
@@ -199,7 +132,7 @@ fn sync_chain(
let min_confirmations = state.confirmation.load(Ordering::SeqCst);
let (txs, removed, next_state) =
- list_since_block_state(rpc, &state.address, block, min_confirmations)?;
+ rpc.list_since_sync_state(&state.address, block, min_confirmations)?;
// Check if a confirmed incoming transaction have been removed by a blockchain reorganisation
let new_status = sync_chain_removed(&txs, &removed, db, &state.address, min_confirmations)?;
@@ -520,7 +453,7 @@ fn bounce(db: &mut Client, rpc: &mut Rpc, fee: U256) -> LoopResult<bool> {
"UPDATE bounce SET status=$1 WHERE id=$2",
&[&(BounceStatus::Ignored as i16), &id],
)?;
- info!("|| (ignore) {} ", &bounced);
+ info!("|| (ignore) {} ", hex::encode(bounced));
}
}
}
diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs
index 2b97c94..694c8db 100644
--- a/eth-wire/src/main.rs
+++ b/eth-wire/src/main.rs
@@ -14,47 +14,26 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-use std::{path::PathBuf, str::FromStr, sync::atomic::AtomicU16};
+use std::path::PathBuf;
use clap::StructOpt;
use common::{
- api_common::Amount,
- config::{load_eth_config, Config, CoreConfig, EthConfig},
+ config::{load_eth_config, Config, CoreConfig},
named_spawn, password,
postgres::{Client, NoTls},
reconnect::auto_reconnect_db,
};
use eth_wire::{
rpc::{auto_rpc_common, auto_rpc_wallet, Rpc},
- taler_util::{eth_payto_addr, taler_to_eth},
- SyncState,
+ SyncState, WireState,
};
-use ethereum_types::{H160, U256};
+use ethereum_types::H160;
use loops::{analysis::analysis, watcher::watcher, worker::worker};
mod fail_point;
mod loops;
mod sql;
-const DEFAULT_CONFIRMATION: u16 = 24;
-const DEFAULT_BOUNCE_FEE: &'static str = "ETH:0.00001";
-
-pub struct WireState {
- confirmation: AtomicU16,
- max_confirmations: u16,
- address: H160,
- config: EthConfig,
- bounce_fee: U256,
-}
-
-fn config_bounce_fee(config: &EthConfig) -> U256 {
- let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
- Amount::from_str(&config)
- .ok()
- .and_then(|a| taler_to_eth(&a).ok())
- .expect("config value BOUNCE_FEE is no a valid ethereum amount")
-}
-
/// Taler wire for geth
#[derive(clap::Parser, Debug)]
struct Args {
@@ -89,8 +68,13 @@ fn init(config: Option<PathBuf>, init: Init) {
// Connect to database
let mut db = Client::connect(&config.db_url, NoTls).expect("Failed to connect to database");
// Connect to ethereum node
- let mut rpc = Rpc::new(config.data_dir.unwrap().join("geth.ipc"))
- .expect("Failed to connect to ethereum RPC server");
+ let mut rpc = Rpc::new(
+ config
+ .data_dir
+ .unwrap_or(PathBuf::from("/tmp/"))
+ .join("geth.ipc"),
+ )
+ .expect("Failed to connect to ethereum RPC server");
match init {
Init::Initdb => {
@@ -111,12 +95,11 @@ fn init(config: Option<PathBuf>, init: Init) {
tip_height: block.number.unwrap(),
conf_height: block.number.unwrap(),
};
- db
- .execute(
- "INSERT INTO state (name, value) VALUES ('sync', $1) ON CONFLICT (name) DO NOTHING",
- &[&state.to_bytes().as_ref()],
- )
- .expect("Failed to update database state");
+ db.execute(
+ "INSERT INTO state (name, value) VALUES ('sync', $1) ON CONFLICT (name) DO NOTHING",
+ &[&state.to_bytes().as_ref()],
+ )
+ .expect("Failed to update database state");
println!("Database initialised");
}
Init::Initwallet => {
@@ -172,18 +155,33 @@ fn init(config: Option<PathBuf>, init: Init) {
fn run(config: Option<PathBuf>) {
let config = load_eth_config(config.as_deref());
- let init_confirmation = config.confirmation.unwrap_or(DEFAULT_CONFIRMATION);
- let state: &'static WireState = Box::leak(Box::new(WireState {
- confirmation: AtomicU16::new(init_confirmation),
- max_confirmations: init_confirmation * 2,
- address: eth_payto_addr(&config.payto).unwrap(),
- bounce_fee: config_bounce_fee(&config),
- config,
- }));
-
- let rpc_worker = auto_rpc_wallet(state.config.core.data_dir.clone().unwrap(), state.address);
- let rpc_analysis = auto_rpc_common(state.config.core.data_dir.clone().unwrap());
- let rpc_watcher = auto_rpc_common(state.config.core.data_dir.clone().unwrap());
+ let state: &'static _ = Box::leak(Box::new(WireState::from_taler_config(config)));
+
+ let rpc_worker = auto_rpc_wallet(
+ state
+ .config
+ .core
+ .data_dir
+ .clone()
+ .unwrap_or(PathBuf::from("/tmp/")),
+ state.address,
+ );
+ let rpc_analysis = auto_rpc_common(
+ state
+ .config
+ .core
+ .data_dir
+ .clone()
+ .unwrap_or(PathBuf::from("/tmp/")),
+ );
+ let rpc_watcher = auto_rpc_common(
+ state
+ .config
+ .core
+ .data_dir
+ .clone()
+ .unwrap_or(PathBuf::from("/tmp/")),
+ );
let db_watcher = auto_reconnect_db(state.config.core.db_url.clone());
let db_analysis = auto_reconnect_db(state.config.core.db_url.clone());
diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs
index 1ee31e4..4dadd8b 100644
--- a/eth-wire/src/rpc.rs
+++ b/eth-wire/src/rpc.rs
@@ -224,6 +224,13 @@ impl Rpc {
}
}
+ pub fn get_transaction_receipt(&mut self, hash: &H256) -> Result<Option<TransactionReceipt>> {
+ match self.call("eth_getTransactionReceipt", &[hash]) {
+ Err(Error::Null) => Ok(None),
+ r => r,
+ }
+ }
+
pub fn fill_transaction(&mut self, params: &TransactionRequest) -> Result<Filled> {
self.call("eth_fillTransaction", &[params])
}
@@ -271,7 +278,7 @@ impl Rpc {
self.call("eth_getBlockByNumber", &("earliest", &true))
}
- pub fn balance(&mut self, addr: &Address) -> Result<U256> {
+ pub fn get_balance(&mut self, addr: &Address) -> Result<U256> {
self.call("eth_getBalance", &(addr, "latest"))
}
@@ -364,6 +371,17 @@ pub struct Transaction {
pub input: Hex,
}
+/// Description of a Transaction, pending or in the chain.
+#[derive(Debug, Clone, serde::Deserialize)]
+pub struct TransactionReceipt {
+ /// Gas used by this transaction alone.
+ #[serde(rename = "gasUsed")]
+ pub gas_used: U256,
+ /// Effective gas price
+ #[serde(rename = "effectiveGasPrice")]
+ pub effective_gas_price: Option<U256>,
+}
+
/// Fill result
#[derive(Debug, serde::Deserialize)]
pub struct Filled {
@@ -377,7 +395,10 @@ pub struct FilledGas {
pub gas: U256,
/// Gas price
#[serde(rename = "gasPrice")]
- pub gas_price: U256,
+ pub gas_price: Option<U256>,
+ /// Max fee per gas
+ #[serde(rename = "maxFeePerGas")]
+ pub max_fee_per_gas: Option<U256>,
}
/// Send Transaction Parameters
@@ -389,11 +410,7 @@ pub struct TransactionRequest {
pub to: Address,
/// Transferred value
pub value: U256,
- /// Supplied gas (None for sensible default)
- #[serde(skip_serializing_if = "Option::is_none")]
- pub gas: Option<U256>,
/// Gas price (None for sensible default)
- #[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "gasPrice")]
pub gas_price: Option<U256>,
/// Transaction data
diff --git a/eth-wire/src/taler_util.rs b/eth-wire/src/taler_util.rs
index 7f9fef1..b5db5df 100644
--- a/eth-wire/src/taler_util.rs
+++ b/eth-wire/src/taler_util.rs
@@ -18,8 +18,8 @@ use std::str::FromStr;
use ethereum_types::{Address, U256};
use common::{api_common::Amount, url::Url};
-const WEI: u64 = 1_000_000_000_000_000_000;
-const TRUNC: u64 = 10_000_000_000;
+pub const WEI: u64 = 1_000_000_000_000_000_000;
+pub const TRUNC: u64 = 10_000_000_000;
/// Generate a payto uri from an eth address
pub fn eth_payto_url(addr: &Address) -> Url {