Skip to content

Commit

Permalink
Add UTXO-specific estimate_fee_blocks param to coins file #656 (#804)
Browse files Browse the repository at this point in the history
* Add UTXO-specific estimate_fee_blocks param to coins file #656

* Fix tests.

* Fix tests after merge.

* Make trade_test_electrum_and_eth_coins more stable
by triggering subscription to the topic.

* Make trade_test_electrum_and_eth_coins more stable
by waiting for bob to listen on p2p port.
  • Loading branch information
artemii235 authored Feb 2, 2021
1 parent 25272e5 commit 12cf6a0
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 28 deletions.
2 changes: 1 addition & 1 deletion azure-pipelines-build-stage-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
mkdir upload
echo 2.1.$(Build.BuildId)_$(Build.SourceBranchName)_$(COMMIT_HASH)_$(Agent.OS)_Release > MM_VERSION
cat MM_VERSION
cargo build --features native --release
cargo build --features native --release --bin mm2
displayName: 'Build MM2 Release'
# Explicit --test-threads=16 makes testing process slightly faster on agents that have <16 CPU cores.
- bash: |
Expand Down
3 changes: 3 additions & 0 deletions etomic_build/client/enable_BCH
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
source userpass
curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"electrum\",\"coin\":\"BCH\",\"servers\":[{\"url\":\"electrum1.cipig.net:10055\"},{\"url\":\"electrum2.cipig.net:10055\"},{\"url\":\"electrum3.cipig.net:10055\"}]}"
9 changes: 9 additions & 0 deletions etomic_build/client/get_trade_fee
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
source userpass
curl --url "http://127.0.0.1:7783" --data '
{
"userpass":"'$userpass'",
"method":"get_trade_fee",
"coin":"'$1'"
}
'
6 changes: 6 additions & 0 deletions mm2src/coins/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ pub struct UtxoCoinFields {
/// The daemon needs some time to update the listunspent list for address which makes it return already spent UTXOs
/// This cache helps to prevent UTXO reuse in such cases
pub recently_spent_outpoints: AsyncMutex<RecentlySpentOutPoints>,
/// The number of blocks used for estimate_fee/estimate_smart_fee RPC calls
pub estimate_fee_blocks: u32,
}

#[cfg_attr(test, mockable)]
Expand Down Expand Up @@ -777,6 +779,7 @@ pub trait UtxoCoinBuilder {
let mtp_block_count = self.mtp_block_count();
let estimate_fee_mode = self.estimate_fee_mode();
let dust_amount = self.dust_amount();
let estimate_fee_blocks = self.estimate_fee_blocks();

let _my_script_pubkey = Builder::build_p2pkh(&my_address.hash).to_bytes();
let coin = UtxoCoinFields {
Expand Down Expand Up @@ -813,6 +816,7 @@ pub trait UtxoCoinBuilder {
mature_confirmations,
tx_cache_directory,
recently_spent_outpoints: AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)),
estimate_fee_blocks,
};
Ok(coin)
}
Expand Down Expand Up @@ -974,6 +978,8 @@ pub trait UtxoCoinBuilder {

fn dust_amount(&self) -> u64 { json::from_value(self.conf()["dust"].clone()).unwrap_or(UTXO_DUST_AMOUNT) }

fn estimate_fee_blocks(&self) -> u32 { json::from_value(self.conf()["estimate_fee_blocks"].clone()).unwrap_or(1) }

fn network(&self) -> Result<BlockchainNetwork, String> {
let conf = self.conf();
if !conf["network"].is_null() {
Expand Down
36 changes: 20 additions & 16 deletions mm2src/coins/utxo/rpc_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ pub trait UtxoRpcClientOps: fmt::Debug + Send + Sync + 'static {
decimals: u8,
fee_method: &EstimateFeeMethod,
mode: &Option<EstimateFeeMode>,
n_blocks: u32,
) -> RpcRes<u64>;

fn get_relay_fee(&self) -> RpcRes<BigDecimal>;
Expand Down Expand Up @@ -513,16 +514,17 @@ impl UtxoRpcClientOps for NativeClient {
decimals: u8,
fee_method: &EstimateFeeMethod,
mode: &Option<EstimateFeeMode>,
n_blocks: u32,
) -> RpcRes<u64> {
match fee_method {
EstimateFeeMethod::Standard => Box::new(self.estimate_fee().map(move |fee| {
EstimateFeeMethod::Standard => Box::new(self.estimate_fee(n_blocks).map(move |fee| {
if fee > 0.00001 {
(fee * 10.0_f64.powf(decimals as f64)) as u64
} else {
1000
}
})),
EstimateFeeMethod::SmartFee => Box::new(self.estimate_smart_fee(mode).map(move |res| {
EstimateFeeMethod::SmartFee => Box::new(self.estimate_smart_fee(mode, n_blocks).map(move |res| {
if res.fee_rate > 0.00001 {
(res.fee_rate * 10.0_f64.powf(decimals as f64)) as u64
} else {
Expand Down Expand Up @@ -681,16 +683,16 @@ impl NativeClientImpl {
}

/// https://developer.bitcoin.org/reference/rpc/estimatefee.html
/// Always estimate fee for transaction to be confirmed in next block
fn estimate_fee(&self) -> RpcRes<f64> {
let n_blocks = 1;
rpc_func!(self, "estimatefee", n_blocks)
}
/// It is recommended to set n_blocks as low as possible.
/// However, in some cases, n_blocks = 1 leads to an unreasonably high fee estimation.
/// https://github.com/KomodoPlatform/atomicDEX-API/issues/656#issuecomment-743759659
fn estimate_fee(&self, n_blocks: u32) -> RpcRes<f64> { rpc_func!(self, "estimatefee", n_blocks) }

/// https://developer.bitcoin.org/reference/rpc/estimatesmartfee.html
/// Always estimate fee for transaction to be confirmed in next block
pub fn estimate_smart_fee(&self, mode: &Option<EstimateFeeMode>) -> RpcRes<EstimateSmartFeeRes> {
let n_blocks = 1;
/// It is recommended to set n_blocks as low as possible.
/// However, in some cases, n_blocks = 1 leads to an unreasonably high fee estimation.
/// https://github.com/KomodoPlatform/atomicDEX-API/issues/656#issuecomment-743759659
pub fn estimate_smart_fee(&self, mode: &Option<EstimateFeeMode>, n_blocks: u32) -> RpcRes<EstimateSmartFeeRes> {
match mode {
Some(m) => rpc_func!(self, "estimatesmartfee", n_blocks, m),
None => rpc_func!(self, "estimatesmartfee", n_blocks),
Expand Down Expand Up @@ -721,8 +723,8 @@ impl NativeClientImpl {
}

pub fn detect_fee_method(&self) -> impl Future<Item = EstimateFeeMethod, Error = String> + Send {
let estimate_fee_fut = self.estimate_fee();
self.estimate_smart_fee(&None).then(move |res| -> Box<dyn Future<Item=EstimateFeeMethod, Error=String> + Send> {
let estimate_fee_fut = self.estimate_fee(1);
self.estimate_smart_fee(&None, 1).then(move |res| -> Box<dyn Future<Item=EstimateFeeMethod, Error=String> + Send> {
match res {
Ok(smart_fee) => if smart_fee.fee_rate > 0. {
Box::new(futures01::future::ok(EstimateFeeMethod::SmartFee))
Expand Down Expand Up @@ -1449,9 +1451,10 @@ impl ElectrumClient {
}

/// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-estimatefee
/// Always estimate fee for transaction to be confirmed in next block
fn estimate_fee(&self, mode: &Option<EstimateFeeMode>) -> RpcRes<f64> {
let n_blocks = 1;
/// It is recommended to set n_blocks as low as possible.
/// However, in some cases, n_blocks = 1 leads to an unreasonably high fee estimation.
/// https://github.com/KomodoPlatform/atomicDEX-API/issues/656#issuecomment-743759659
fn estimate_fee(&self, mode: &Option<EstimateFeeMode>, n_blocks: u32) -> RpcRes<f64> {
match mode {
Some(m) => rpc_func!(self, "blockchain.estimatefee", n_blocks, m),
None => rpc_func!(self, "blockchain.estimatefee", n_blocks),
Expand Down Expand Up @@ -1524,8 +1527,9 @@ impl UtxoRpcClientOps for ElectrumClient {
decimals: u8,
_fee_method: &EstimateFeeMethod,
mode: &Option<EstimateFeeMode>,
n_blocks: u32,
) -> RpcRes<u64> {
Box::new(self.estimate_fee(mode).map(move |fee| {
Box::new(self.estimate_fee(mode, n_blocks).map(move |fee| {
if fee > 0.00001 {
(fee * 10.0_f64.powf(decimals as f64)) as u64
} else {
Expand Down
2 changes: 1 addition & 1 deletion mm2src/coins/utxo/utxo_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ pub async fn get_tx_fee(coin: &UtxoCoinFields) -> Result<ActualTxFee, JsonRpcErr
TxFee::Dynamic(method) => {
let fee = coin
.rpc_client
.estimate_fee_sat(coin.decimals, method, &coin.estimate_fee_mode)
.estimate_fee_sat(coin.decimals, method, &coin.estimate_fee_mode, coin.estimate_fee_blocks)
.compat()
.await?;
Ok(ActualTxFee::Dynamic(fee))
Expand Down
1 change: 1 addition & 0 deletions mm2src/coins/utxo/utxo_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ fn utxo_coin_fields_for_test(rpc_client: UtxoRpcClientEnum, force_seed: Option<&
mature_confirmations: MATURE_CONFIRMATIONS_DEFAULT,
tx_cache_directory: None,
recently_spent_outpoints: AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)),
estimate_fee_blocks: 1,
}
}

Expand Down
2 changes: 1 addition & 1 deletion mm2src/docker_tests/qrc20_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ fn wait_for_estimate_smart_fee(timeout: u64) -> Result<(), String> {
UtxoRpcClientEnum::Electrum(_) => panic!("Expected NativeClient"),
};
while now_ms() / 1000 < timeout {
if let Ok(res) = client.estimate_smart_fee(&None).wait() {
if let Ok(res) = client.estimate_smart_fee(&None, 1).wait() {
if res.errors.is_empty() {
*state = EstimateSmartFeeState::Ok;
return Ok(());
Expand Down
8 changes: 8 additions & 0 deletions mm2src/mm2_libp2p/src/atomicdex_behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ pub fn start_gossipsub(
CONNECTED_RELAYS_CHECK_INTERVAL,
);
let mut announce_interval = Interval::new_at(Instant::now() + ANNOUNCE_INITIAL_DELAY, ANNOUNCE_INTERVAL);
let mut listening = false;
let polling_fut = poll_fn(move |cx: &mut Context| {
loop {
match swarm.cmd_rx.poll_next_unpin(cx) {
Expand All @@ -742,6 +743,13 @@ pub fn start_gossipsub(
while let Poll::Ready(Some(())) = check_connected_relays_interval.poll_next_unpin(cx) {
maintain_connection_to_relays(&mut swarm, &bootstrap);
}

if !listening && i_am_relay {
for listener in Swarm::listeners(&swarm) {
info!("Listening on {}", listener);
listening = true;
}
}
on_poll(&swarm);
Poll::Pending
});
Expand Down
30 changes: 21 additions & 9 deletions mm2src/mm2_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,14 +791,13 @@ async fn trade_base_rel_electrum(pairs: Vec<(&'static str, &'static str)>) {
log! ({"Alice log path: {}", mm_alice.log_path.display()})
}

// Wait for keypair initialization, `lp_passphrase_init`.
unwrap!(mm_bob.wait_for_log(11., |l| l.contains("version: ")).await);
unwrap!(mm_alice.wait_for_log(11., |l| l.contains("version: ")).await);

// wait until both nodes RPC API is active
wait_log_re!(mm_bob, 22., ">>>>>>>>> DEX stats ");
wait_log_re!(mm_alice, 22., ">>>>>>>>> DEX stats ");

// wait until bob starts listening on the p2p port
wait_log_re!(mm_bob, 22., "Listening on");

// Enable coins on Bob side. Print the replies in case we need the address.
let rc = enable_coins_eth_electrum(&mm_bob, vec!["http://195.201.0.6:8565"]).await;
log! ({"enable_coins (bob): {:?}", rc});
Expand Down Expand Up @@ -828,12 +827,25 @@ async fn trade_base_rel_electrum(pairs: Vec<(&'static str, &'static str)>) {
assert!(rc.0.is_success(), "!setprice: {}", rc.1);
}

// Allow the order to be converted to maker after not being matched in 30 seconds.
// log! ("Waiting 32 seconds…");
// Timer::sleep (32.) .await;

for (base, rel) in pairs.iter() {
log!("Issue alice " (base) "/" (rel) " buy request");
common::log::info!(
"Trigger alice subscription to {}/{} orderbook topic first and sleep for 1 second",
base,
rel
);
let rc = unwrap!(
mm_alice
.rpc(json! ({
"userpass": mm_alice.userpass,
"method": "orderbook",
"base": base,
"rel": rel,
}))
.await
);
assert!(rc.0.is_success(), "!orderbook: {}", rc.1);
Timer::sleep(1.).await;
common::log::info!("Issue alice {}/{} buy request", base, rel);
let rc = unwrap!(
mm_alice
.rpc(json! ({
Expand Down

0 comments on commit 12cf6a0

Please sign in to comment.