Skip to content

Commit

Permalink
verify shutdown fee for shutdown command
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Jun 14, 2024
1 parent 469d606 commit 1d48914
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 39 deletions.
104 changes: 78 additions & 26 deletions src/ckb/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ use std::{
};

use crate::{
ckb::types::Shutdown,
ckb::{
config::{DEFAULT_UDT_MINIMAL_CKB_AMOUNT, MIN_OCCUPIED_CAPACITY},
types::Shutdown,
},
ckb_chain::{
contracts::{get_cell_deps_by_contracts, get_script_by_contract, Contract},
FundingRequest, FundingUdtInfo,
Expand All @@ -41,7 +44,7 @@ use crate::{
};

use super::{
config::{CKB_SHANNONS, DEFAULT_MIN_SHUTDOWN_FEE},
config::MIN_UDT_OCCUPIED_CAPACITY,
key::blake2b_hash_with_salt,
network::PCNMessageWithPeerId,
serde_utils::EntityHex,
Expand Down Expand Up @@ -89,7 +92,7 @@ pub enum ChannelCommand {
CommitmentSigned(),
AddTlc(AddTlcCommand, RpcReplyPort<Result<AddTlcResponse, String>>),
RemoveTlc(RemoveTlcCommand, RpcReplyPort<Result<(), String>>),
Shutdown(ShutdownCommand),
Shutdown(ShutdownCommand, RpcReplyPort<Result<(), String>>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -136,7 +139,6 @@ pub const DEFAULT_MAX_TLC_VALUE_IN_FLIGHT: u128 = u128::MAX;
pub const DEFAULT_MAX_ACCEPT_TLCS: u64 = u64::MAX;
pub const DEFAULT_MIN_TLC_VALUE: u128 = 0;
pub const DEFAULT_TO_LOCAL_DELAY_BLOCKS: u64 = 10;
pub const DEFAULT_UDT_MINIMAL_CKB_AMOUNT: u64 = 142 * CKB_SHANNONS + DEFAULT_MIN_SHUTDOWN_FEE; // 143 CKB for minimal UDT amount

#[derive(Debug)]
pub struct TxUpdateCommand {
Expand Down Expand Up @@ -709,6 +711,8 @@ impl<S> ChannelActor<S> {
));
}
};

state.verify_shutdown_fee(command.fee)?;
self.network
.send_message(NetworkActorMessage::new_command(
NetworkActorCommand::SendPcnMessage(PCNMessageWithPeerId {
Expand Down Expand Up @@ -875,7 +879,18 @@ impl<S> ChannelActor<S> {
}
}
}
ChannelCommand::Shutdown(command) => self.handle_shutdown_command(state, command),
ChannelCommand::Shutdown(command, reply) => {
match self.handle_shutdown_command(state, command) {
Ok(_) => {
let _ = reply.send(Ok(()));
Ok(())
}
Err(err) => {
let _ = reply.send(Err(err.to_string()));
Err(err)
}
}
}
}
}

Expand Down Expand Up @@ -1797,6 +1812,33 @@ impl ChannelActorState {
&self.get_remote_channel_parameters().pubkeys.funding_pubkey
}

pub fn verify_shutdown_fee(&self, fee: u64) -> ProcessingChannelResult {
let available_max_fee = if self.funding_udt_type_script.is_none() {
self.to_local_amount as u64 - MIN_OCCUPIED_CAPACITY
} else {
self.local_ckb_amount - MIN_UDT_OCCUPIED_CAPACITY
};
if fee > available_max_fee {
return Err(ProcessingChannelError::InvalidParameter(format!(
"Local balance is not enough to pay the fee, you can pay at most {} as fee",
available_max_fee
)));
}

let (shutdown_tx, _) = self.build_shutdown_tx(false)?;
let tx_size = shutdown_tx.data().serialized_size_in_block();
let expected_minimal_fee = tx_size as u64 * self.commitment_fee_rate;
if let Some(fee) = self.local_shutdown_fee {
if fee < expected_minimal_fee {
return Err(ProcessingChannelError::InvalidParameter(format!(
"Shutdown fee is not enough for minimal fee rate, expected fee >= {}",
expected_minimal_fee
)));
}
}
Ok(())
}

pub fn check_state_for_tlc_update(&self) -> ProcessingChannelResult {
match self.state {
ChannelState::ChannelReady(flags) => {
Expand Down Expand Up @@ -2000,7 +2042,7 @@ impl ChannelActorState {
flags | ShuttingDownFlags::DROPPING_PENDING,
));

let (shutdown_tx, message) = self.build_shutdown_tx()?;
let (shutdown_tx, message) = self.build_shutdown_tx(true)?;
let sign_ctx = Musig2SignContext::from(&*self);

// Create our shutdown signature if we haven't already.
Expand Down Expand Up @@ -2638,7 +2680,12 @@ impl ChannelActorState {
&& self.should_local_go_first_in_musig2()
}

pub fn build_shutdown_tx(&self) -> Result<(TransactionView, [u8; 32]), ProcessingChannelError> {
// `apply` = true means we are building the shutdown transaction to be broadcasted
// `apply` = false means we want to mock the shutdown transaction and only for calculating the fee
pub fn build_shutdown_tx(
&self,
apply: bool,
) -> Result<(TransactionView, [u8; 32]), ProcessingChannelError> {
// Don't use get_local_shutdown_script and get_remote_shutdown_script here
// as they will panic if the scripts are not present.
// This function may be called in a state where these scripts are not present.
Expand All @@ -2647,30 +2694,35 @@ impl ChannelActorState {
remote_shutdown_script,
local_shutdown_fee,
remote_shutdown_fee,
) = match (
self.local_shutdown_script.clone(),
self.remote_shutdown_script.clone(),
self.local_shutdown_fee,
self.remote_shutdown_fee,
) {
(
Some(local_shutdown_script),
Some(remote_shutdown_script),
Some(local_shutdown_fee),
Some(remote_shutdown_fee),
) => (
local_shutdown_script,
remote_shutdown_script,
local_shutdown_fee,
remote_shutdown_fee,
),
_ => {
return Err(ProcessingChannelError::InvalidState(format!(
) = if apply {
match (
self.local_shutdown_script.clone(),
self.remote_shutdown_script.clone(),
self.local_shutdown_fee,
self.remote_shutdown_fee,
) {
(
Some(local_shutdown_script),
Some(remote_shutdown_script),
Some(local_shutdown_fee),
Some(remote_shutdown_fee),
) => (
local_shutdown_script,
remote_shutdown_script,
local_shutdown_fee,
remote_shutdown_fee,
),
_ => {
return Err(ProcessingChannelError::InvalidState(format!(
"Shutdown scripts are not present: local_shutdown_script {:?}, remote_shutdown_script {:?}, local_shutdown_fee {:?}, remote_shutdown_fee {:?}",
&self.local_shutdown_script, &self.remote_shutdown_script,
&self.local_shutdown_fee, &self.remote_shutdown_fee
)));
}
}
} else {
let script = get_script_by_contract(Contract::Secp256k1Lock, &[0u8; 20]);
(script.clone(), script.clone(), 0, 0)
};

let mut contracts = vec![Contract::CommitmentLock];
Expand Down
3 changes: 3 additions & 0 deletions src/ckb/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub const CKB_SHANNONS: u64 = 100_000_000;
pub const DEFAULT_MIN_INBOUND_LIQUIDITY: u64 = 100 * CKB_SHANNONS; // 100 CKB for minimal inbound liquidity
pub const DEFAULT_MIN_SHUTDOWN_FEE: u64 = 1 * CKB_SHANNONS; // 1 ckb prepared for shutdown transaction fee
pub const MIN_OCCUPIED_CAPACITY: u64 = 61 * CKB_SHANNONS; // 61 CKB for occupied capacity
pub const MIN_UDT_OCCUPIED_CAPACITY: u64 = 142 * CKB_SHANNONS; // 142 CKB for UDT occupied capacity
pub const DEFAULT_UDT_MINIMAL_CKB_AMOUNT: u64 =
MIN_UDT_OCCUPIED_CAPACITY + DEFAULT_MIN_SHUTDOWN_FEE; // 143 CKB for minimal UDT amount

// See comment in `LdkConfig` for why do we need to specify both name and long,
// and prefix them with `ckb-`/`CKB_`.
Expand Down
34 changes: 23 additions & 11 deletions src/rpc/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,28 @@ where
&self,
params: ShutdownChannelParams,
) -> Result<(), ErrorObjectOwned> {
let message = NetworkActorMessage::Command(NetworkActorCommand::ControlPcnChannel(
ChannelCommandWithId {
channel_id: params.channel_id,
command: ChannelCommand::Shutdown(ShutdownCommand {
close_script: params.close_script.into(),
fee: params.fee,
}),
},
));
self.actor.cast(message).unwrap();
Ok(())
let message = |rpc_reply| -> NetworkActorMessage {
NetworkActorMessage::Command(NetworkActorCommand::ControlPcnChannel(
ChannelCommandWithId {
channel_id: params.channel_id,
command: ChannelCommand::Shutdown(
ShutdownCommand {
close_script: params.close_script.clone().into(),
fee: params.fee,
},
rpc_reply,
),
},
))
};

match call!(self.actor, message).unwrap() {
Ok(_response) => Ok(()),
Err(e) => Err(ErrorObjectOwned::owned(
CALL_EXECUTION_FAILED_CODE,
e,
Some(params),
)),
}
}
}
2 changes: 1 addition & 1 deletion tests/bruno/e2e/udt/08-node1-send-shutdown-channel.bru
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ body:json {
"hash_type": "data",
"args": "0x0101010101010101010101010101010101010101"
},
"fee": "0xbebc200"
"fee": "0x5F5E100"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion tests/bruno/e2e/udt/09-node2-send-shutdown-channel.bru
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ body:json {
"hash_type": "data",
"args": "0x0101010101010101010101010101010101010101"
},
"fee": "0xbebc200"
"fee": "0x5F5E100"
}
]
}
Expand Down

0 comments on commit 1d48914

Please sign in to comment.