mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-23 14:50:45 +01:00
Merge pull request #2213 from benthecarman/error-sign-provider-addrs
Allow get_shutdown_scriptpubkey and get_destination_script to return an Error
This commit is contained in:
commit
101c09f9bf
8 changed files with 80 additions and 38 deletions
|
@ -259,18 +259,18 @@ impl SignerProvider for KeyProvider {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
fn get_destination_script(&self) -> Result<Script, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let channel_monitor_claim_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, self.node_secret[31]]).unwrap();
|
||||
let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
|
||||
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
|
||||
Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script())
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let secret_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, self.node_secret[31]]).unwrap();
|
||||
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
|
||||
ShutdownScript::new_p2wpkh(&pubkey_hash)
|
||||
Ok(ShutdownScript::new_p2wpkh(&pubkey_hash))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -376,18 +376,18 @@ impl SignerProvider for KeyProvider {
|
|||
))
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
fn get_destination_script(&self) -> Result<Script, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
|
||||
let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
|
||||
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
|
||||
Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script())
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let secret_key = SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]).unwrap();
|
||||
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
|
||||
ShutdownScript::new_p2wpkh(&pubkey_hash)
|
||||
Ok(ShutdownScript::new_p2wpkh(&pubkey_hash))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,9 +141,9 @@ impl SignerProvider for KeyProvider {
|
|||
|
||||
fn read_chan_signer(&self, _data: &[u8]) -> Result<EnforcingSigner, DecodeError> { unreachable!() }
|
||||
|
||||
fn get_destination_script(&self) -> Script { unreachable!() }
|
||||
fn get_destination_script(&self) -> Result<Script, ()> { unreachable!() }
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!() }
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> { unreachable!() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -543,15 +543,21 @@ pub trait SignerProvider {
|
|||
|
||||
/// Get a script pubkey which we send funds to when claiming on-chain contestable outputs.
|
||||
///
|
||||
/// This method should return a different value each time it is called, to avoid linking
|
||||
/// on-chain funds across channels as controlled to the same user.
|
||||
fn get_destination_script(&self) -> Script;
|
||||
|
||||
/// Get a script pubkey which we will send funds to when closing a channel.
|
||||
/// If this function returns an error, this will result in a channel failing to open.
|
||||
///
|
||||
/// This method should return a different value each time it is called, to avoid linking
|
||||
/// on-chain funds across channels as controlled to the same user.
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript;
|
||||
fn get_destination_script(&self) -> Result<Script, ()>;
|
||||
|
||||
/// Get a script pubkey which we will send funds to when closing a channel.
|
||||
///
|
||||
/// If this function returns an error, this will result in a channel failing to open or close.
|
||||
/// In the event of a failure when the counterparty is initiating a close, this can result in a
|
||||
/// channel force close.
|
||||
///
|
||||
/// This method should return a different value each time it is called, to avoid linking
|
||||
/// on-chain funds across channels as controlled to the same user.
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()>;
|
||||
}
|
||||
|
||||
/// A simple implementation of [`WriteableEcdsaChannelSigner`] that just keeps the private keys in memory.
|
||||
|
@ -1366,12 +1372,12 @@ impl SignerProvider for KeysManager {
|
|||
InMemorySigner::read(&mut io::Cursor::new(reader), self)
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
self.destination_script.clone()
|
||||
fn get_destination_script(&self) -> Result<Script, ()> {
|
||||
Ok(self.destination_script.clone())
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone())
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
Ok(ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1461,11 +1467,11 @@ impl SignerProvider for PhantomKeysManager {
|
|||
self.inner.read_chan_signer(reader)
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
fn get_destination_script(&self) -> Result<Script, ()> {
|
||||
self.inner.get_destination_script()
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
self.inner.get_shutdown_scriptpubkey()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -986,7 +986,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
|
||||
|
||||
let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
|
||||
Some(signer_provider.get_shutdown_scriptpubkey())
|
||||
match signer_provider.get_shutdown_scriptpubkey() {
|
||||
Ok(scriptpubkey) => Some(scriptpubkey),
|
||||
Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get shutdown scriptpubkey".to_owned()}),
|
||||
}
|
||||
} else { None };
|
||||
|
||||
if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey {
|
||||
|
@ -995,6 +998,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
}
|
||||
}
|
||||
|
||||
let destination_script = match signer_provider.get_destination_script() {
|
||||
Ok(script) => script,
|
||||
Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}),
|
||||
};
|
||||
|
||||
let temporary_channel_id = entropy_source.get_secure_random_bytes();
|
||||
|
||||
Ok(Channel {
|
||||
|
@ -1021,7 +1029,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
|
||||
holder_signer,
|
||||
shutdown_scriptpubkey,
|
||||
destination_script: signer_provider.get_destination_script(),
|
||||
destination_script,
|
||||
|
||||
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
|
||||
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
|
||||
|
@ -1333,7 +1341,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
} else { None };
|
||||
|
||||
let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey {
|
||||
Some(signer_provider.get_shutdown_scriptpubkey())
|
||||
match signer_provider.get_shutdown_scriptpubkey() {
|
||||
Ok(scriptpubkey) => Some(scriptpubkey),
|
||||
Err(_) => return Err(ChannelError::Close("Failed to get upfront shutdown scriptpubkey".to_owned())),
|
||||
}
|
||||
} else { None };
|
||||
|
||||
if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey {
|
||||
|
@ -1342,6 +1353,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
}
|
||||
}
|
||||
|
||||
let destination_script = match signer_provider.get_destination_script() {
|
||||
Ok(script) => script,
|
||||
Err(_) => return Err(ChannelError::Close("Failed to get destination script".to_owned())),
|
||||
};
|
||||
|
||||
let mut secp_ctx = Secp256k1::new();
|
||||
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
|
||||
|
||||
|
@ -1368,7 +1384,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
|
||||
holder_signer,
|
||||
shutdown_scriptpubkey,
|
||||
destination_script: signer_provider.get_destination_script(),
|
||||
destination_script,
|
||||
|
||||
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
|
||||
cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
|
||||
|
@ -4355,7 +4371,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
Some(_) => false,
|
||||
None => {
|
||||
assert!(send_shutdown);
|
||||
let shutdown_scriptpubkey = signer_provider.get_shutdown_scriptpubkey();
|
||||
let shutdown_scriptpubkey = match signer_provider.get_shutdown_scriptpubkey() {
|
||||
Ok(scriptpubkey) => scriptpubkey,
|
||||
Err(_) => return Err(ChannelError::Close("Failed to get shutdown scriptpubkey".to_owned())),
|
||||
};
|
||||
if !shutdown_scriptpubkey.is_compatible(their_features) {
|
||||
return Err(ChannelError::Close(format!("Provided a scriptpubkey format not accepted by peer: {}", shutdown_scriptpubkey)));
|
||||
}
|
||||
|
@ -6062,7 +6081,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
|||
let update_shutdown_script = match self.shutdown_scriptpubkey {
|
||||
Some(_) => false,
|
||||
None if !chan_closed => {
|
||||
let shutdown_scriptpubkey = signer_provider.get_shutdown_scriptpubkey();
|
||||
let shutdown_scriptpubkey = match signer_provider.get_shutdown_scriptpubkey() {
|
||||
Ok(scriptpubkey) => scriptpubkey,
|
||||
Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get shutdown scriptpubkey".to_owned() }),
|
||||
};
|
||||
if !shutdown_scriptpubkey.is_compatible(their_features) {
|
||||
return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() });
|
||||
}
|
||||
|
@ -7087,17 +7109,17 @@ mod tests {
|
|||
|
||||
fn read_chan_signer(&self, _data: &[u8]) -> Result<Self::Signer, DecodeError> { panic!(); }
|
||||
|
||||
fn get_destination_script(&self) -> Script {
|
||||
fn get_destination_script(&self) -> Result<Script, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
|
||||
let channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize());
|
||||
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_monitor_claim_key_hash[..]).into_script()
|
||||
Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_monitor_claim_key_hash[..]).into_script())
|
||||
}
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
let secp_ctx = Secp256k1::signing_only();
|
||||
let channel_close_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
|
||||
ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key))
|
||||
Ok(ShutdownScript::new_p2wpkh_from_pubkey(PublicKey::from_secret_key(&secp_ctx, &channel_close_key)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1854,6 +1854,10 @@ where
|
|||
/// Raises [`APIError::APIMisuseError`] when `channel_value_satoshis` > 2**24 or `push_msat` is
|
||||
/// greater than `channel_value_satoshis * 1k` or `channel_value_satoshis < 1000`.
|
||||
///
|
||||
/// Raises [`APIError::ChannelUnavailable`] if the channel cannot be opened due to failing to
|
||||
/// generate a shutdown scriptpubkey or destination script set by
|
||||
/// [`SignerProvider::get_shutdown_scriptpubkey`] or [`SignerProvider::get_destination_script`].
|
||||
///
|
||||
/// Note that we do not check if you are currently connected to the given peer. If no
|
||||
/// connection is available, the outbound `open_channel` message may fail to send, resulting in
|
||||
/// the channel eventually being silently forgotten (dropped on reload).
|
||||
|
@ -2098,6 +2102,11 @@ where
|
|||
///
|
||||
/// May generate a [`SendShutdown`] message event on success, which should be relayed.
|
||||
///
|
||||
/// Raises [`APIError::ChannelUnavailable`] if the channel cannot be closed due to failing to
|
||||
/// generate a shutdown scriptpubkey or destination script set by
|
||||
/// [`SignerProvider::get_shutdown_scriptpubkey`]. A force-closure may be needed to close the
|
||||
/// channel.
|
||||
///
|
||||
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis
|
||||
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
|
||||
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
|
||||
|
@ -2122,6 +2131,11 @@ where
|
|||
///
|
||||
/// May generate a [`SendShutdown`] message event on success, which should be relayed.
|
||||
///
|
||||
/// Raises [`APIError::ChannelUnavailable`] if the channel cannot be closed due to failing to
|
||||
/// generate a shutdown scriptpubkey or destination script set by
|
||||
/// [`SignerProvider::get_shutdown_scriptpubkey`]. A force-closure may be needed to close the
|
||||
/// channel.
|
||||
///
|
||||
/// [`ChannelConfig::force_close_avoidance_max_fee_satoshis`]: crate::util::config::ChannelConfig::force_close_avoidance_max_fee_satoshis
|
||||
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
|
||||
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
|
||||
|
|
|
@ -669,7 +669,7 @@ fn test_unsupported_anysegwit_shutdown_script() {
|
|||
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
|
||||
|
||||
// Check that using an unsupported shutdown script fails and a supported one succeeds.
|
||||
let supported_shutdown_script = chanmon_cfgs[1].keys_manager.get_shutdown_scriptpubkey();
|
||||
let supported_shutdown_script = chanmon_cfgs[1].keys_manager.get_shutdown_scriptpubkey().unwrap();
|
||||
let unsupported_shutdown_script =
|
||||
ShutdownScript::new_witness_program(WitnessVersion::V16, &[0, 40]).unwrap();
|
||||
chanmon_cfgs[1].keys_manager
|
||||
|
|
|
@ -180,8 +180,8 @@ impl SignerProvider for OnlyReadsKeysInterface {
|
|||
))
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script { unreachable!(); }
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { unreachable!(); }
|
||||
fn get_destination_script(&self) -> Result<Script, ()> { Err(()) }
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> { Err(()) }
|
||||
}
|
||||
|
||||
pub struct TestChainMonitor<'a> {
|
||||
|
@ -809,14 +809,14 @@ impl SignerProvider for TestKeysInterface {
|
|||
))
|
||||
}
|
||||
|
||||
fn get_destination_script(&self) -> Script { self.backing.get_destination_script() }
|
||||
fn get_destination_script(&self) -> Result<Script, ()> { self.backing.get_destination_script() }
|
||||
|
||||
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
|
||||
fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
|
||||
match &mut *self.expectations.lock().unwrap() {
|
||||
None => self.backing.get_shutdown_scriptpubkey(),
|
||||
Some(expectations) => match expectations.pop_front() {
|
||||
None => panic!("Unexpected get_shutdown_scriptpubkey"),
|
||||
Some(expectation) => expectation.returns,
|
||||
Some(expectation) => Ok(expectation.returns),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue