Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: revert shared wallet #523

Merged
merged 22 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
45d6711
Revert "chore: reset rescan db"
sander2 Sep 13, 2023
21442d8
Revert "chore: use 0 minconf for listunspent"
sander2 Sep 13, 2023
4b8b27a
Revert "chore: rescan issues for old shared wallet"
sander2 Sep 13, 2023
7d2c7e5
Revert "chore: update tests"
sander2 Sep 13, 2023
78e4818
Revert "chore: add missing methods to replace mock"
sander2 Sep 13, 2023
1bf15a0
Revert "chore: clippy"
sander2 Sep 13, 2023
9c4cd17
Revert "chore: wait for last sweep tx inclusion"
sander2 Sep 13, 2023
613ffcb
Revert "refactor: don't fail if we can't sweep funds"
sander2 Sep 13, 2023
75b0ccd
Revert "chore: import derivation key to v2 shared wallet"
sander2 Sep 13, 2023
9837577
Revert "fix: also sweep from currency specific wallets"
sander2 Sep 13, 2023
f4fdd09
Revert "chore: add more logging"
sander2 Sep 13, 2023
3822cb5
Revert "fix: sweep funds into shared wallet v2"
sander2 Sep 13, 2023
501b687
Revert "fix: migration for pruned nodes"
sander2 Sep 13, 2023
39d1c4d
Revert "fix: create shared wallet"
sander2 Sep 13, 2023
2ebf990
Revert "chore: fix vaultid import"
sander2 Sep 13, 2023
d0869dc
Revert "refactor: import all issue keys"
sander2 Sep 13, 2023
0147a37
Revert "chore: duplicate rpc in test setup"
sander2 Sep 13, 2023
a596fca
Revert "refactor: merge duplicate bitcoin metrics"
sander2 Sep 13, 2023
4793dcc
Revert "refactor: merge currency specific bitcoin wallets"
sander2 Sep 13, 2023
863f75a
fix: fix incorrect merge conflict resolutions
sander2 Sep 13, 2023
0e80c01
fix: fix some reverts
sander2 Sep 20, 2023
2c2b92c
Revert "fix: option for migration in liquidated vaults"
sander2 Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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