commit 9eabce59a590696c5ca5c2a787c3867256348c4f
parent 6d2599c1b1ed11109b6a7c012167608eca00145e
Author: Antoine A <>
Date: Thu, 3 Feb 2022 18:26:19 +0100
Remove Delayed transaction status
Diffstat:
12 files changed, 162 insertions(+), 318 deletions(-)
diff --git a/README.md b/README.md
@@ -40,25 +40,20 @@ HTTP_LIFETIME = 0
WIRE_LIFETIME = 0
```
-Modules have specific configuration:
-
-- [wire-gateway](wire-gateway/README.md#Configuration)
-- [btc-wire](btc-wire/README.md#Configuration)
+### Stuck transaction
-## Architecture
+When a transaction is sent with a fee too small compared to other transaction,
+it can take an unlimited amount of time for this transaction to be mined. It is
+possible to replace this transaction with another transaction with more fees.
+Depolymerizer can be configured to do this automatically:
-### Linking Taler to blockchains
-
-```
- ┌─────┐ ┌────────────────┐ ┌──────────┐
- │Taler│◄─►│Depolymerization│◄─►│Blockchain│
- └─────┘ └────────────────┘ └──────────┘
+``` ini
+[depolymerizer-___]
+# Delay in seconds before bumping an unconfirmed transaction fee (0 mean never)
+BUMP_DELAY = 0
```
-### Depolymerization architecture
+Modules have specific configuration:
-```
- ┌────────────┐ ┌──────────┐ ┌────────┐
- │wire_gateway│◄─►│PostgreSQL│◄─►│###_wire│
- └────────────┘ └──────────┘ └────────┘
-```
-\ No newline at end of file
+- [wire-gateway](wire-gateway/README.md#Configuration)
+- [btc-wire](btc-wire/README.md#Configuration)
+\ No newline at end of file
diff --git a/btc-wire/README.md b/btc-wire/README.md
@@ -22,7 +22,6 @@ The configuration is based on [taler.conf](https://docs.taler.net/manpages/taler
DATA_DIR =
CONFIRMATION = 6
BOUNCE_FEE = 1000
-BUMP_DELAY =
```
### bitcoin.conf
@@ -41,62 +40,9 @@ the RPC server, `txindex=1` and `maxtxfee` are mandatory.
7. Run wire-gateway `wire-gateway`
8. Run btc-wire `btc-wire`
-## How it work ?
-
-
-### Outgoing transaction lifecycle
-
-#### Transaction lifecycle
-
-```
- │
- ▼
- ┌─────────┐
- ┌─┤Requested├─┐
- │ └─────────┘ │
- ▼ ▼
- ┌────┐ ┌───────┐
- │Sent│◄────►│Delayed│
- └────┘ └───────┘
-
- -> Requested API request
-Requested -> Sent Sent in the blockchain
-Requested -> Delayed Error while sending
-Delayed -> Sent Sent in the blockchain
-Send -> Delayed Conflicting transaction (reorg)
-```
-
-#### Bounce lifecycle
-
-```
- │
- ▼
- ┌─────────┐
- ┌─────┤Requested├────┐
- │ └────┬────┘ │
- ▼ ▼ ▼
- ┌────┐ ┌───────┐ ┌───────┐
- │Sent│◄─►│Delayed│ │Ignored│
- └────┘ └───────┘ └───────┘
-
- -> Requested Transaction in wrong format
-Requested -> Sent Sent in the blockchain
-Requested -> Ignored Insufficient amount
-Requested -> Delayed Error while sending
-Delayed -> Sent Sent in the blockchain
-Send -> Delayed Conflicting transaction (reorg)
-```
+## Implementation details
### Stuck transaction
-When a transaction is sent with a fee too small compared to other transaction,
-it can take an unlimited amount of time for this transaction to be mined. It is
-possible to replace this transaction with another transaction with more fees
-using [BIP 125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki).
-btc-wire can be configured to do this automatically:
-
-``` ini
-[depolymerizer-bitcoin]
-# Delay in seconds before bumping an unconfirmed transaction fee
-BUMP_DELAY = 10
-```
+We resolve stuck transaction by always sending replaceable transaction
+using [BIP 125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki).
+\ No newline at end of file
diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs
@@ -22,25 +22,25 @@ use std::{
use bitcoin::{hashes::Hash, Amount as BtcAmount, BlockHash, Txid};
use btc_wire::{
- rpc::{self, Rpc, Category, ErrorCode, TransactionFull},
+ rpc::{self, Category, ErrorCode, Rpc, TransactionFull},
rpc_utils::sender_address,
GetOpReturnErr, GetSegwitErr,
};
-use postgres::{fallible_iterator::FallibleIterator, Client};
use common::{
api_common::base32,
config::BtcConfig,
log::log::{error, info, warn},
postgres,
sql::{sql_array, sql_url},
+ status::{BounceStatus, WithdrawStatus},
};
+use postgres::{fallible_iterator::FallibleIterator, Client};
use crate::{
fail_point::fail_point,
metadata::OutMetadata,
reconnect::{AutoReconnectRPC, AutoReconnectSql},
sql::{sql_addr, sql_btc_amount, sql_txid},
- status::{BounceStatus, TxStatus},
taler_util::{btc_payto_url, btc_to_taler},
WireState,
};
@@ -108,16 +108,12 @@ pub fn worker(
// As we are now in sync with the blockchain if a transaction is in requested or delayed state it have not been sent
- // Send delayed transactions
- while send(db, rpc, TxStatus::Delayed)? {}
- // Send requested transactions
- while send(db, rpc, TxStatus::Requested)? {}
+ // Send requested withdraws
+ while withdraw(db, rpc)? {}
let bounce_fee = BtcAmount::from_sat(config.bounce_fee);
- // Send delayed bounce
- while bounce(db, rpc, BounceStatus::Delayed, &bounce_fee)? {}
// Send requested bounce
- while bounce(db, rpc, BounceStatus::Requested, &bounce_fee)? {}
+ while bounce(db, rpc, &bounce_fee)? {}
Ok(())
})();
@@ -138,13 +134,12 @@ pub fn worker(
}
}
-/// Send atransaction on the blockchain, return true if more transactions with the same status remains
-fn send(db: &mut Client, rpc: &mut Rpc, status: TxStatus) -> LoopResult<bool> {
- assert!(status == TxStatus::Delayed || status == TxStatus::Requested);
+/// Send a withdraw transaction on the blockchain, return false if no more requested transaction are found
+fn withdraw(db: &mut Client, rpc: &mut Rpc) -> LoopResult<bool> {
// We rely on the advisory lock to ensure we are the only one sending transactions
let row = db.query_opt(
"SELECT id, amount, wtid, credit_acc, exchange_url FROM tx_out WHERE status=$1 ORDER BY _date LIMIT 1",
- &[&(status as i16)],
+ &[&(WithdrawStatus::Requested as i16)],
)?;
if let Some(row) = &row {
let id: i32 = row.get(0);
@@ -152,50 +147,33 @@ fn send(db: &mut Client, rpc: &mut Rpc, status: TxStatus) -> LoopResult<bool> {
let wtid: [u8; 32] = sql_array(row, 2);
let addr = sql_addr(row, 3);
let url = sql_url(row, 4);
- let info = OutMetadata::Transaction { wtid, url };
- let metadata = info.encode();
+ let metadata = OutMetadata::Withdraw { wtid, url };
- match rpc.send_op_return(&addr, &amount, &metadata, false, true) {
- Ok(tx_id) => {
- fail_point("(injected) fail send", 0.3)?;
- db.execute(
- "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3",
- &[&(TxStatus::Sent as i16), &tx_id.as_ref(), &id],
- )?;
- let amount = btc_to_taler(&amount.to_signed().unwrap());
- info!(">> {} {} in {} to {}", amount, base32(&wtid), tx_id, addr);
- }
- Err(e) => {
- db.execute(
- "UPDATE tx_out SET status=$1 WHERE id=$2",
- &[&(TxStatus::Delayed as i16), &id],
- )?;
- Err(e)?;
- }
- }
+ let tx_id = rpc.send_op_return(&addr, &amount, &metadata.encode(), false, true)?;
+ fail_point("(injected) fail send", 0.3)?;
+ db.execute(
+ "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3",
+ &[&(WithdrawStatus::Sent as i16), &tx_id.as_ref(), &id],
+ )?;
+ let amount = btc_to_taler(&amount.to_signed().unwrap());
+ info!(">> {} {} in {} to {}", amount, base32(&wtid), tx_id, addr);
}
Ok(row.is_some())
}
-/// Bounce a transaction on the blockchain, return true if more bounce with the same status remains
-fn bounce(
- db: &mut Client,
- rpc: &mut Rpc,
- status: BounceStatus,
- fee: &BtcAmount,
-) -> LoopResult<bool> {
- assert!(status == BounceStatus::Delayed || status == BounceStatus::Requested);
+/// Bounce a transaction on the blockchain, return false if nor more requested transaction are found
+fn bounce(db: &mut Client, rpc: &mut Rpc, fee: &BtcAmount) -> LoopResult<bool> {
// We rely on the advisory lock to ensure we are the only one sending transactions
let row = db.query_opt(
"SELECT id, bounced FROM bounce WHERE status=$1 ORDER BY _date LIMIT 1",
- &[&(status as i16)],
+ &[&(BounceStatus::Requested as i16)],
)?;
if let Some(row) = &row {
let id: i32 = row.get(0);
let bounced: Txid = sql_txid(row, 1);
- let info = OutMetadata::Bounce { bounced };
+ let metadata = OutMetadata::Bounce { bounced };
- match rpc.bounce(&bounced, fee, &info.encode()) {
+ match rpc.bounce(&bounced, fee, &metadata.encode()) {
Ok(it) => {
fail_point("(injected) fail bounce", 0.3)?;
db.execute(
@@ -215,13 +193,7 @@ fn bounce(
)?;
info!("|| (ignore) {} because {}", &bounced, msg);
}
- e => {
- db.execute(
- "UPDATE bounce SET status=$1 WHERE id=$2",
- &[&(BounceStatus::Delayed as i16), &id],
- )?;
- Err(e)?;
- }
+ e => Err(e)?,
},
}
}
@@ -404,7 +376,7 @@ fn sync_chain_outgoing(
.map(|(full, bytes)| (full, OutMetadata::decode(&bytes)))
{
Ok((full, Ok(info))) => match info {
- OutMetadata::Transaction { wtid, .. } => {
+ OutMetadata::Withdraw { wtid, .. } => {
sync_chain_outgoing_send(id, &full, &wtid, rpc, db, confirmations, config)?
}
OutMetadata::Bounce { bounced } => {
@@ -438,7 +410,7 @@ fn sync_chain_outgoing_send(
// Handle conflicting tx
let nb_row = db.execute(
"UPDATE tx_out SET status=$1, txid=NULL where txid=$2",
- &[&(TxStatus::Delayed as i16), &id.as_ref()],
+ &[&(WithdrawStatus::Requested as i16), &id.as_ref()],
)?;
if nb_row > 0 {
warn!(
@@ -459,11 +431,16 @@ fn sync_chain_outgoing_send(
// If already in database, sync status
let row_id: i32 = row.get(0);
let status: i16 = row.get(1);
- match TxStatus::try_from(status as u8).unwrap() {
- TxStatus::Requested | TxStatus::Delayed => {
+ match WithdrawStatus::try_from(status as u8).unwrap() {
+ WithdrawStatus::Requested => {
let nb_row = db.execute(
"UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3 AND status=$4",
- &[&(TxStatus::Sent as i16), &id.as_ref(), &row_id, &status],
+ &[
+ &(WithdrawStatus::Sent as i16),
+ &id.as_ref(),
+ &row_id,
+ &status,
+ ],
)?;
if nb_row > 0 {
warn!(
@@ -475,7 +452,7 @@ fn sync_chain_outgoing_send(
);
}
}
- TxStatus::Sent => {
+ WithdrawStatus::Sent => {
if let Some(txid) = full.replaces_txid {
let stored_id = sql_txid(&row, 2);
if txid == stored_id {
@@ -501,7 +478,7 @@ fn sync_chain_outgoing_send(
let date = SystemTime::UNIX_EPOCH + Duration::from_secs(full.time);
let nb = db.execute(
"INSERT INTO tx_out (_date, amount, wtid, debit_acc, credit_acc, exchange_url, status, txid, request_uid) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (wtid) DO NOTHING",
- &[&date, &amount.to_string(), &wtid.as_ref(), &btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(credit_addr).as_ref(), &config.base_url.as_ref(), &(TxStatus::Sent as i16), &id.as_ref(), &None::<&[u8]>],
+ &[&date, &amount.to_string(), &wtid.as_ref(), &btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(credit_addr).as_ref(), &config.base_url.as_ref(), &(WithdrawStatus::Sent as i16), &id.as_ref(), &None::<&[u8]>],
)?;
if nb > 0 {
warn!(
@@ -551,7 +528,7 @@ fn sync_chain_outgoing_bounce(
// Handle conflicting tx
let nb_row = db.execute(
"UPDATE bounce SET status=$1, txid=NULL where txid=$2",
- &[&(BounceStatus::Delayed as i16), &id.as_ref()],
+ &[&(BounceStatus::Requested as i16), &id.as_ref()],
)?;
if nb_row > 0 {
warn!("|| (conflict) {} in {}", &bounced, &id);
@@ -567,7 +544,7 @@ fn sync_chain_outgoing_bounce(
let row_id: i32 = row.get(0);
let status: i16 = row.get(1);
match BounceStatus::try_from(status as u8).unwrap() {
- BounceStatus::Requested | BounceStatus::Delayed => {
+ BounceStatus::Requested => {
let nb_row = db.execute(
"UPDATE bounce SET status=$1, txid=$2 WHERE id=$3 AND status=$4",
&[&(BounceStatus::Sent as i16), &id.as_ref(), &row_id, &status],
diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs
@@ -19,21 +19,20 @@ use btc_wire::{
rpc::Rpc,
rpc_utils::default_data_dir,
};
-use reconnect::{AutoReconnectRPC, AutoReconnectSql};
-use std::{sync::atomic::AtomicU16, thread::JoinHandle};
use common::{
config::{load_btc_config, BtcConfig},
log::log::info,
};
+use reconnect::{AutoReconnectRPC, AutoReconnectSql};
+use std::{sync::atomic::AtomicU16, thread::JoinHandle};
use crate::loops::{analysis::analysis, watcher::watcher, worker::worker};
mod fail_point;
-mod metadata;
mod loops;
+mod metadata;
mod reconnect;
mod sql;
-mod status;
mod taler_util;
pub struct WireState {
diff --git a/btc-wire/src/metadata.rs b/btc-wire/src/metadata.rs
@@ -33,7 +33,7 @@ pub enum DecodeErr {
/// Encoded metadata for outgoing transaction
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OutMetadata {
- Transaction { wtid: [u8; 32], url: Url },
+ Withdraw { wtid: [u8; 32], url: Url },
Bounce { bounced: Txid },
}
@@ -44,7 +44,7 @@ impl OutMetadata {
pub fn encode(&self) -> Vec<u8> {
let mut buffer = Vec::new();
match self {
- OutMetadata::Transaction { wtid, url } => {
+ OutMetadata::Withdraw { wtid, url } => {
buffer.push(if url.scheme() == "http" { 1 } else { 0 });
buffer.extend_from_slice(wtid);
let parts = format!("{}{}", url.domain().unwrap_or(""), url.path());
@@ -75,7 +75,7 @@ impl OutMetadata {
uri_pack::unpack_uri(&bytes[33..])?,
);
let url = Url::parse(&packed).unwrap();
- Ok(OutMetadata::Transaction {
+ Ok(OutMetadata::Withdraw {
wtid: bytes[1..33].try_into().unwrap(),
url,
})
@@ -106,7 +106,7 @@ mod test {
for url in urls {
let wtid = rand_slice();
let url = Url::parse(url).unwrap();
- let info = OutMetadata::Transaction { wtid, url };
+ let info = OutMetadata::Withdraw { wtid, url };
let encoded = info.encode();
let decoded = OutMetadata::decode(&encoded).unwrap();
assert_eq!(decoded, info);
diff --git a/btc-wire/src/status.rs b/btc-wire/src/status.rs
@@ -1,69 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-//! Transactions status in database
-
-/// Outgoing transaction status
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum TxStatus {
- /// Client have ask for a transaction (default)
- Requested = 0,
- /// The wire failed to send this transaction and will try later
- Delayed = 1,
- /// Transaction have been announced to the bitcoin network
- Sent = 2,
-}
-
-impl TryFrom<u8> for TxStatus {
- type Error = ();
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- x if x == TxStatus::Requested as u8 => Ok(TxStatus::Requested),
- x if x == TxStatus::Sent as u8 => Ok(TxStatus::Sent),
- x if x == TxStatus::Delayed as u8 => Ok(TxStatus::Delayed),
- _ => Err(()),
- }
- }
-}
-
-/// Bounce transaction status
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum BounceStatus {
- /// Bounce have been requested (default)
- Requested = 0,
- /// The wire failed to send this bounce and will try later
- Delayed = 1,
- /// Bounce will not be sent (e.g: bounce amount smaller than bounce fee)
- Ignored = 2,
- /// Bounce have been announced to the bitcoin network
- Sent = 3,
-}
-
-impl TryFrom<u8> for BounceStatus {
- type Error = ();
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- x if x == BounceStatus::Requested as u8 => Ok(BounceStatus::Requested),
- x if x == BounceStatus::Sent as u8 => Ok(BounceStatus::Sent),
- x if x == BounceStatus::Delayed as u8 => Ok(BounceStatus::Delayed),
- x if x == BounceStatus::Ignored as u8 => Ok(BounceStatus::Ignored),
- _ => Err(()),
- }
- }
-}
diff --git a/common/src/lib.rs b/common/src/lib.rs
@@ -24,6 +24,7 @@ pub mod config;
pub mod error_codes;
pub mod log;
pub mod sql;
+pub mod status;
/// Secure random slice generator using getrandom
pub fn rand_slice<const N: usize>() -> [u8; N] {
diff --git a/common/src/status.rs b/common/src/status.rs
@@ -0,0 +1,72 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+//! Transactions status in database
+
+/// Withdraw transaction status
+///
+/// -> Requested API request
+/// Requested -> Sent Announced to the bitcoin network
+/// Sent -> Requested Conflicting transaction (reorg)
+#[repr(u8)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WithdrawStatus {
+ /// Withdraw have been requested (default)
+ Requested = 0,
+ /// Withdraw have been announced to the bitcoin network
+ Sent = 1,
+}
+
+impl TryFrom<u8> for WithdrawStatus {
+ type Error = ();
+
+ fn try_from(v: u8) -> Result<Self, Self::Error> {
+ match v {
+ x if x == WithdrawStatus::Requested as u8 => Ok(WithdrawStatus::Requested),
+ x if x == WithdrawStatus::Sent as u8 => Ok(WithdrawStatus::Sent),
+ _ => Err(()),
+ }
+ }
+}
+
+/// Bounce transaction status
+///
+/// -> Requested Deposit in wrong format
+/// Requested -> Ignored Insufficient found
+/// Requested -> Sent Announced to the bitcoin network
+/// Sent -> Requested Conflicting transaction (reorg)
+#[repr(u8)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum BounceStatus {
+ /// Bounce have been requested (default)
+ Requested = 0,
+ /// Bounce will never be sent (e.g: bounce amount smaller than bounce fee)
+ Ignored = 1,
+ /// Bounce have been announced to the bitcoin network
+ Sent = 2,
+}
+
+impl TryFrom<u8> for BounceStatus {
+ type Error = ();
+
+ fn try_from(v: u8) -> Result<Self, Self::Error> {
+ match v {
+ x if x == BounceStatus::Requested as u8 => Ok(BounceStatus::Requested),
+ x if x == BounceStatus::Sent as u8 => Ok(BounceStatus::Sent),
+ x if x == BounceStatus::Ignored as u8 => Ok(BounceStatus::Ignored),
+ _ => Err(()),
+ }
+ }
+}
diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs
@@ -15,22 +15,22 @@
*/
use std::time::SystemTime;
-use eth_wire::{
- metadata::InMetadata,
- rpc::Rpc,
- taler_util::{eth_payto_url, eth_to_taler},
- BlockState,
-};
use common::{
api_common::base32,
log::log::{error, info},
postgres::{fallible_iterator::FallibleIterator, Client},
sql::{sql_array, sql_url},
+ status::WithdrawStatus,
+};
+use eth_wire::{
+ metadata::InMetadata,
+ rpc::Rpc,
+ taler_util::{eth_payto_url, eth_to_taler},
+ BlockState,
};
use crate::{
sql::{sql_addr, sql_eth_amount},
- status::TxStatus,
LoopResult, WireState,
};
@@ -54,7 +54,7 @@ pub fn worker(mut rpc: Rpc, mut db: Client, state: &WireState) {
sync_chain(&mut rpc, &mut db, state)?;
- while send(&mut db, &mut rpc, state)? {}
+ while withdraw(&mut db, &mut rpc, state)? {}
Ok(())
})();
@@ -115,12 +115,12 @@ fn sync_chain(rpc: &mut Rpc, db: &mut Client, state: &WireState) -> LoopResult<b
Ok(true)
}
-/// Send a transaction on the blockchain, return true if more transactions with the same status remains
-fn send(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<bool> {
+/// Send a withdraw transaction on the blockchain, return false if no more requested transaction are found
+fn withdraw(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<bool> {
// We rely on the advisory lock to ensure we are the only one sending transactions
let row = db.query_opt(
"SELECT id, amount, wtid, credit_acc, exchange_url FROM tx_out WHERE status=$1 ORDER BY _date LIMIT 1",
-&[&(TxStatus::Requested as i16)],
+&[&(WithdrawStatus::Requested as i16)],
)?;
if let Some(row) = &row {
let id: i32 = row.get(0);
@@ -128,23 +128,13 @@ fn send(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<bool> {
let wtid: [u8; 32] = sql_array(row, 2);
let addr = sql_addr(row, 3);
let url = sql_url(row, 4);
- match rpc.withdraw(state.address, addr, amount, wtid, url) {
- Ok(tx_id) => {
- db.execute(
- "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3",
- &[&(TxStatus::Sent as i16), &tx_id.as_ref(), &id],
- )?;
- let amount = eth_to_taler(&amount);
- info!(">> {} {} in {} to {}", amount, base32(&wtid), tx_id, addr);
- }
- Err(e) => {
- db.execute(
- "UPDATE tx_out SET status=$1 WHERE id=$2",
- &[&(TxStatus::Delayed as i16), &id],
- )?;
- Err(e)?;
- }
- }
+ let tx_id = rpc.withdraw(state.address, addr, amount, wtid, url)?;
+ db.execute(
+ "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3",
+ &[&(WithdrawStatus::Sent as i16), &tx_id.as_ref(), &id],
+ )?;
+ let amount = eth_to_taler(&amount);
+ info!(">> {} {} in {} to {}", amount, base32(&wtid), tx_id, addr);
}
Ok(row.is_some())
}
diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs
@@ -16,20 +16,19 @@
use std::sync::atomic::AtomicU16;
+use common::{
+ config::{load_eth_config, EthConfig},
+ postgres::{self, Client, NoTls},
+};
use eth_wire::{
rpc::{self, Rpc},
taler_util::eth_payto_addr,
};
use ethereum_types::H160;
use loops::{watcher::watcher, worker::worker};
-use common::{
- config::{load_eth_config, EthConfig},
- postgres::{self, Client, NoTls},
-};
-mod status;
-mod sql;
mod loops;
+mod sql;
pub struct WireState {
confirmation: AtomicU16,
@@ -74,7 +73,9 @@ fn main() {
)
.unwrap();
- rpc_worker.unlock_account(&state.address, "password").unwrap();
+ rpc_worker
+ .unlock_account(&state.address, "password")
+ .unwrap();
let rpc_watcher = Rpc::new(
state
diff --git a/eth-wire/src/status.rs b/eth-wire/src/status.rs
@@ -1,69 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-//! Transactions status in database
-
-/// Outgoing transaction status
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum TxStatus {
- /// Client have ask for a transaction (default)
- Requested = 0,
- /// The wire failed to send this transaction and will try later
- Delayed = 1,
- /// Transaction have been announced to the bitcoin network
- Sent = 2,
-}
-
-impl TryFrom<u8> for TxStatus {
- type Error = ();
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- x if x == TxStatus::Requested as u8 => Ok(TxStatus::Requested),
- x if x == TxStatus::Sent as u8 => Ok(TxStatus::Sent),
- x if x == TxStatus::Delayed as u8 => Ok(TxStatus::Delayed),
- _ => Err(()),
- }
- }
-}
-
-/// Bounce transaction status
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum BounceStatus {
- /// Bounce have been requested (default)
- Requested = 0,
- /// The wire failed to send this bounce and will try later
- Delayed = 1,
- /// Bounce will not be sent (e.g: bounce amount smaller than bounce fee)
- Ignored = 2,
- /// Bounce have been announced to the bitcoin network
- Sent = 3,
-}
-
-impl TryFrom<u8> for BounceStatus {
- type Error = ();
-
- fn try_from(v: u8) -> Result<Self, Self::Error> {
- match v {
- x if x == BounceStatus::Requested as u8 => Ok(BounceStatus::Requested),
- x if x == BounceStatus::Sent as u8 => Ok(BounceStatus::Sent),
- x if x == BounceStatus::Delayed as u8 => Ok(BounceStatus::Delayed),
- x if x == BounceStatus::Ignored as u8 => Ok(BounceStatus::Ignored),
- _ => Err(()),
- }
- }
-}
diff --git a/test/common.sh b/test/common.sh
@@ -10,7 +10,7 @@ function cleanup() {
for n in `jobs -p`; do
kill $n &> /dev/null || true
done
- rm -rf $DIR &> /dev/null
+ rm -rf $DIR &> /dev/null || true
wait
}