Skip to content

Commit

Permalink
Merge pull request #523 from interlay/interlay-non-shared
Browse files Browse the repository at this point in the history
fix: revert shared wallet
  • Loading branch information
gregdhill authored Sep 20, 2023
2 parents 1065cfe + 2c2b92c commit 11d6d99
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 624 deletions.
5 changes: 0 additions & 5 deletions bitcoin/src/electrs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ impl ElectrsClient {
Ok(ret)
}

pub async fn is_tx_output_spent(&self, txid: &Txid, vout: u32) -> Result<bool, Error> {
let spending_value: SpendingValue = self.get_and_decode(&format!("/tx/{txid}/outspend/{vout}")).await?;
Ok(spending_value.spent)
}

pub async fn get_blocks_tip_height(&self) -> Result<u32, Error> {
Ok(self.get("/blocks/tip/height").await?.parse()?)
}
Expand Down
16 changes: 2 additions & 14 deletions bitcoin/src/electrs/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct TransactionStatus {
}

// https://github.com/Blockstream/electrs/blob/adedee15f1fe460398a7045b292604df2161adc0/src/rest.rs#L167-L189
#[derive(Deserialize, Clone)]
#[derive(Deserialize)]
pub struct TxInValue {
pub txid: Txid,
pub vout: u32,
Expand All @@ -33,7 +33,7 @@ pub struct TxInValue {
}

// https://github.com/Blockstream/electrs/blob/adedee15f1fe460398a7045b292604df2161adc0/src/rest.rs#L239-L270
#[derive(Deserialize, Clone)]
#[derive(Deserialize)]
pub struct TxOutValue {
pub scriptpubkey: ScriptBuf,
pub scriptpubkey_asm: String,
Expand Down Expand Up @@ -66,15 +66,3 @@ pub struct UtxoValue {
pub status: TransactionStatus,
pub value: u64,
}

// https://github.com/Blockstream/electrs/blob/adedee15f1fe460398a7045b292604df2161adc0/src/rest.rs#L448-L457
#[derive(Deserialize)]
pub struct SpendingValue {
pub spent: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub txid: Option<Txid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vin: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<TransactionStatus>,
}
8 changes: 2 additions & 6 deletions bitcoin/src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,15 @@ mod tests {
async fn wait_for_block(&self, height: u32, num_confirmations: u32) -> Result<Block, Error>;
fn get_balance(&self, min_confirmations: Option<u32>) -> Result<Amount, Error>;
fn list_transactions(&self, max_count: Option<usize>) -> Result<Vec<json::ListTransactionResult>, Error>;
fn list_addresses(&self) -> Result<Vec<Address>, Error>;
async fn get_block_count(&self) -> Result<u64, Error>;
async fn get_raw_tx(&self, txid: &Txid, block_hash: &BlockHash) -> Result<Vec<u8>, Error>;
async fn get_transaction(&self, txid: &Txid, block_hash: Option<BlockHash>) -> Result<Transaction, Error>;
async fn get_proof(&self, txid: Txid, block_hash: &BlockHash) -> Result<Vec<u8>, Error>;
async fn get_block_hash(&self, height: u32) -> Result<BlockHash, Error>;
async fn get_new_address(&self) -> Result<Address, Error>;
async fn get_new_sweep_address(&self) -> Result<Address, Error>;
async fn get_last_sweep_height(&self) -> Result<Option<u32>, Error>;
async fn get_new_public_key(&self) -> Result<PublicKey, Error>;
fn dump_private_key(&self, address: &Address) -> Result<PrivateKey, Error>;
fn import_private_key(&self, private_key: &PrivateKey, is_derivation_key: bool) -> Result<(), Error>;
fn dump_derivation_key(&self, public_key: &PublicKey) -> Result<PrivateKey, Error>;
fn import_derivation_key(&self, private_key: &PrivateKey) -> Result<(), Error>;
async fn add_new_deposit_key(
&self,
public_key: PublicKey,
Expand Down Expand Up @@ -253,7 +250,6 @@ mod tests {
fee_rate: SatPerVbyte,
num_confirmations: u32,
) -> Result<TransactionMetadata, Error>;
async fn sweep_funds(&self, address: Address) -> Result<Txid, Error>;
async fn create_or_load_wallet(&self) -> Result<(), Error>;
async fn rescan_blockchain(&self, start_height: usize, end_height: usize) -> Result<(), Error>;
async fn rescan_electrs_for_addresses(
Expand Down
136 changes: 12 additions & 124 deletions bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ pub use sp_core::H256;
use std::{
convert::TryInto,
future::Future,
str::FromStr,
sync::Arc,
time::{Duration, Instant},
};
Expand Down Expand Up @@ -101,8 +100,6 @@ const RANDOMIZATION_FACTOR: f64 = 0.25;
const DERIVATION_KEY_LABEL: &str = "derivation-key";
const DEPOSIT_LABEL: &str = "deposit";

const SWEEP_ADDRESS: &str = "sweep-address";

fn get_exponential_backoff() -> ExponentialBackoff {
ExponentialBackoff {
current_interval: INITIAL_INTERVAL,
Expand Down Expand Up @@ -150,8 +147,6 @@ pub trait BitcoinCoreApi {

fn list_transactions(&self, max_count: Option<usize>) -> Result<Vec<json::ListTransactionResult>, Error>;

fn list_addresses(&self) -> Result<Vec<Address>, Error>;

async fn get_raw_tx(&self, txid: &Txid, block_hash: &BlockHash) -> Result<Vec<u8>, Error>;

async fn get_transaction(&self, txid: &Txid, block_hash: Option<BlockHash>) -> Result<Transaction, Error>;
Expand All @@ -162,15 +157,11 @@ pub trait BitcoinCoreApi {

async fn get_new_address(&self) -> Result<Address, Error>;

async fn get_new_sweep_address(&self) -> Result<Address, Error>;

async fn get_last_sweep_height(&self) -> Result<Option<u32>, Error>;

async fn get_new_public_key(&self) -> Result<PublicKey, Error>;

fn dump_private_key(&self, address: &Address) -> Result<PrivateKey, Error>;
fn dump_derivation_key(&self, public_key: &PublicKey) -> Result<PrivateKey, Error>;

fn import_private_key(&self, private_key: &PrivateKey, is_derivation_key: bool) -> Result<(), Error>;
fn import_derivation_key(&self, private_key: &PrivateKey) -> Result<(), Error>;

async fn add_new_deposit_key(&self, public_key: PublicKey, secret_key: Vec<u8>) -> Result<(), Error>;

Expand Down Expand Up @@ -213,8 +204,6 @@ pub trait BitcoinCoreApi {
num_confirmations: u32,
) -> Result<TransactionMetadata, Error>;

async fn sweep_funds(&self, address: Address) -> Result<Txid, Error>;

async fn create_or_load_wallet(&self) -> Result<(), Error>;

async fn rescan_blockchain(&self, start_height: usize, end_height: usize) -> Result<(), Error>;
Expand Down Expand Up @@ -370,7 +359,7 @@ impl BitcoinCoreBuilder {

#[derive(Clone)]
pub struct BitcoinCore {
pub rpc: Arc<Client>,
rpc: Arc<Client>,
wallet_name: Option<String>,
network: Network,
transaction_creation_lock: Arc<Mutex<()>>,
Expand Down Expand Up @@ -482,6 +471,7 @@ impl BitcoinCore {
signed_funded_raw_tx.complete,
signed_funded_raw_tx.errors
);

return Err(Error::TransactionSigningError);
}

Expand Down Expand Up @@ -724,27 +714,6 @@ impl BitcoinCoreApi for BitcoinCore {
.list_transactions(None, max_count.or(Some(DEFAULT_MAX_TX_COUNT)), None, None)?)
}

// TODO: remove this once the wallet migration has completed
fn list_addresses(&self) -> Result<Vec<Address>, Error> {
// Lists groups of addresses which have had their common ownership
// made public by common use as inputs or as the resulting change
// in past transactions
let groupings: Vec<Vec<Vec<serde_json::Value>>> = self.rpc.call("listaddressgroupings", &[])?;
let addresses = groupings
.into_iter()
.flatten()
.filter_map(|group| {
group
.get(0)
.and_then(|v| v.as_str())
.map(Address::from_str)?
.and_then(|x| x.require_network(self.network))
.ok()
})
.collect::<Vec<_>>();
Ok(addresses)
}

/// Get the raw transaction identified by `Txid` and stored
/// in the specified block.
///
Expand Down Expand Up @@ -799,26 +768,6 @@ impl BitcoinCoreApi for BitcoinCore {
.require_network(self.network)?)
}

async fn get_new_sweep_address(&self) -> Result<Address, Error> {
Ok(self
.rpc
.get_new_address(Some(SWEEP_ADDRESS), Some(AddressType::Bech32))?
.require_network(self.network)?)
}

async fn get_last_sweep_height(&self) -> Result<Option<u32>, Error> {
Ok(self
.rpc
.list_transactions(Some(SWEEP_ADDRESS), Some(DEFAULT_MAX_TX_COUNT), None, None)?
.into_iter()
// we want to return None if there is no sweep tx for full nodes or new
// pruned nodes and we should return an error if any tx is still in the mempool
.map(|tx| tx.info.blockheight.ok_or(Error::ConfirmationError))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.min())
}

/// Gets a new public key for an address in the wallet
async fn get_new_public_key(&self) -> Result<PublicKey, Error> {
let address = self
Expand All @@ -830,16 +779,15 @@ impl BitcoinCoreApi for BitcoinCore {
Ok(public_key)
}

fn dump_private_key(&self, address: &Address) -> Result<PrivateKey, Error> {
Ok(self.rpc.dump_private_key(address)?)
fn dump_derivation_key(&self, public_key: &PublicKey) -> Result<PrivateKey, Error> {
let address = Address::p2wpkh(public_key, self.network).map_err(ConversionError::from)?;
Ok(self.rpc.dump_private_key(&address)?)
}

fn import_private_key(&self, private_key: &PrivateKey, is_derivation_key: bool) -> Result<(), Error> {
Ok(self.rpc.import_private_key(
private_key,
is_derivation_key.then_some(DERIVATION_KEY_LABEL),
Some(false),
)?)
fn import_derivation_key(&self, private_key: &PrivateKey) -> Result<(), Error> {
Ok(self
.rpc
.import_private_key(private_key, Some(DERIVATION_KEY_LABEL), Some(false))?)
}

/// Derive and import the private key for the master public key and public secret
Expand Down Expand Up @@ -1063,66 +1011,6 @@ impl BitcoinCoreApi for BitcoinCore {
.await?)
}

async fn sweep_funds(&self, address: Address) -> Result<Txid, Error> {
let unspent = self.rpc.list_unspent(Some(0), None, None, None, None)?;

let mut amount = Amount::ZERO;
let mut utxos = Vec::<json::CreateRawTransactionInput>::new();

for entry in unspent {
if self.electrs_client.is_tx_output_spent(&entry.txid, entry.vout).await? {
log::info!("{}:{} already spent", entry.txid, entry.vout);
// skip if already spent
continue;
}
amount += entry.amount;
utxos.push(json::CreateRawTransactionInput {
txid: entry.txid,
vout: entry.vout,
sequence: None,
})
}

log::info!("Sweeping {} from {} utxos", amount, utxos.len());
let mut outputs = serde_json::Map::<String, serde_json::Value>::new();
outputs.insert(address.to_string(), serde_json::Value::from(amount.to_btc()));

let args = [
serde_json::to_value::<&[json::CreateRawTransactionInput]>(&utxos)?,
serde_json::to_value(outputs)?,
serde_json::to_value(0i64)?, /* locktime - default 0: see https://developer.bitcoin.org/reference/rpc/createrawtransaction.html */
serde_json::to_value(true)?, // BIP125-replaceable, aka Replace By Fee (RBF)
];
let raw_tx: String = self.rpc.call("createrawtransaction", &args)?;

let funding_opts = FundRawTransactionOptions {
fee_rate: None,
add_inputs: Some(false),
subtract_fee_from_outputs: Some(vec![0]),
..Default::default()
};
let funded_raw_tx = self.rpc.fund_raw_transaction(raw_tx, Some(&funding_opts), None)?;

let signed_funded_raw_tx =
self.rpc
.sign_raw_transaction_with_wallet(&funded_raw_tx.transaction()?, None, None)?;

if signed_funded_raw_tx.errors.is_some() {
log::warn!(
"Received bitcoin funding errors (complete={}): {:?}",
signed_funded_raw_tx.complete,
signed_funded_raw_tx.errors
);
return Err(Error::TransactionSigningError);
}

let transaction = signed_funded_raw_tx.transaction()?;
let txid = self.rpc.send_raw_transaction(&transaction)?;
log::info!("Sent sweep tx: {txid}");

Ok(txid)
}

/// Create or load a wallet on Bitcoin Core.
async fn create_or_load_wallet(&self) -> Result<(), Error> {
let wallet_name = if let Some(ref wallet_name) = self.wallet_name {
Expand Down Expand Up @@ -1185,7 +1073,7 @@ impl BitcoinCoreApi for BitcoinCore {
// filter to only import
// a) payments in the blockchain (not in mempool), and
// b) payments TO the address (as bitcoin core will already know about transactions spending FROM it)
let confirmed_payments_to = all_transactions.iter().filter(|tx| {
let confirmed_payments_to = all_transactions.into_iter().filter(|tx| {
if let Some(status) = &tx.status {
if !status.confirmed {
return false;
Expand Down
30 changes: 3 additions & 27 deletions bitcoin/src/light/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,6 @@ impl BitcoinCoreApi for BitcoinLight {
Ok(Default::default())
}

// TODO: remove this later
fn list_addresses(&self) -> Result<Vec<Address>, BitcoinError> {
// don't need to migrate keys
Ok(Default::default())
}

async fn get_raw_tx(&self, txid: &Txid, _block_hash: &BlockHash) -> Result<Vec<u8>, BitcoinError> {
Ok(self.electrs.get_raw_tx(txid).await?)
}
Expand All @@ -168,29 +162,15 @@ impl BitcoinCoreApi for BitcoinLight {
Ok(self.get_change_address()?)
}

async fn get_new_sweep_address(&self) -> Result<Address, BitcoinError> {
Ok(self.get_change_address()?)
}

async fn get_last_sweep_height(&self) -> Result<Option<u32>, BitcoinError> {
Ok(None)
}

async fn get_new_public_key(&self) -> Result<PublicKey, BitcoinError> {
Ok(self.private_key.public_key(&self.secp_ctx))
}

fn dump_private_key(&self, address: &Address) -> Result<PrivateKey, BitcoinError> {
self.wallet
.key_store
.read()
.map_err(Into::<Error>::into)?
.get(address)
.ok_or(Error::NoPrivateKey.into())
.cloned()
fn dump_derivation_key(&self, _public_key: &PublicKey) -> Result<PrivateKey, BitcoinError> {
Ok(self.private_key)
}

fn import_private_key(&self, _private_key: &PrivateKey, _is_derivation_key: bool) -> Result<(), BitcoinError> {
fn import_derivation_key(&self, _private_key: &PrivateKey) -> Result<(), BitcoinError> {
// nothing to do
Ok(())
}
Expand Down Expand Up @@ -339,10 +319,6 @@ impl BitcoinCoreApi for BitcoinLight {
.await?)
}

async fn sweep_funds(&self, _address: Address) -> Result<Txid, BitcoinError> {
Ok(Txid::all_zeros())
}

async fn create_or_load_wallet(&self) -> Result<(), BitcoinError> {
// nothing to do
Ok(())
Expand Down
Loading

0 comments on commit 11d6d99

Please sign in to comment.