Skip to content

Commit

Permalink
feat(rpc): extend getBridgeDuties to return withdrawal duties (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajil1213 authored Sep 30, 2024
1 parent 129ad9d commit 06fc7fa
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 82 deletions.
24 changes: 19 additions & 5 deletions crates/bridge-tx-builder/src/withdrawal.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Provides types/traits associated with the withdrawal process.
use alpen_express_primitives::{
bridge::{OperatorIdx, TxSigningData},
bridge::{BitcoinBlockHeight, OperatorIdx, TxSigningData},
l1::{BitcoinPsbt, TaprootSpendPath, XOnlyPk},
};
use bitcoin::{Amount, FeeRate, OutPoint, Psbt, Transaction, TxOut};
Expand All @@ -21,7 +21,7 @@ use crate::{
///
/// It has all the information required to create a transaction for fulfilling a user's withdrawal
/// request and pay operator fees.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CooperativeWithdrawalInfo {
/// The [`OutPoint`] of the UTXO in the Bridge Address that is to be used to service the
/// withdrawal request.
Expand All @@ -33,6 +33,12 @@ pub struct CooperativeWithdrawalInfo {

/// The index of the operator that is assigned the withdrawal.
assigned_operator_idx: OperatorIdx,

/// The bitcoin block height before which the withdrawal has to be processed.
///
/// Any withdrawal request whose `exec_deadline` is before the current bitcoin block height is
/// considered stale and must be ignored.
exec_deadline: BitcoinBlockHeight,
}

impl TxKind for CooperativeWithdrawalInfo {
Expand Down Expand Up @@ -65,14 +71,21 @@ impl CooperativeWithdrawalInfo {
deposit_outpoint: OutPoint,
user_pk: XOnlyPk,
assigned_operator_idx: OperatorIdx,
exec_deadline: BitcoinBlockHeight,
) -> Self {
Self {
deposit_outpoint,
user_pk,
assigned_operator_idx,
exec_deadline,
}
}

/// Check if the passed bitcoin block height is greater than the deadline for the withdrawal.
pub fn is_expired_at(&self, block_height: BitcoinBlockHeight) -> bool {
self.exec_deadline < block_height
}

fn create_prevout<T: BuildContext>(&self, build_context: &T) -> BridgeTxBuilderResult<TxOut> {
// We are not committing to any script path as the internal key should already be
// randomized due to MuSig2 aggregation. See: <https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-23>
Expand Down Expand Up @@ -195,7 +208,7 @@ mod tests {
let assigned_operator_idx = assigned_operator_idx as OperatorIdx;

let withdrawal_info =
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx);
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx, 0);

let build_context = TxBuildContext::new(
Network::Regtest,
Expand Down Expand Up @@ -255,6 +268,7 @@ mod tests {
deposit_outpoint,
invalid_user_pk,
assigned_operator_idx,
0,
);

let build_context =
Expand Down Expand Up @@ -293,7 +307,7 @@ mod tests {
let assigned_operator_idx = assigned_operator_idx as OperatorIdx;

let withdrawal_info =
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx);
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx, 0);

let build_context =
TxBuildContext::new(Network::Regtest, pubkey_table, assigned_operator_idx);
Expand Down Expand Up @@ -334,7 +348,7 @@ mod tests {
let assigned_operator_idx = assigned_operator_idx as OperatorIdx;

let withdrawal_info =
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx);
CooperativeWithdrawalInfo::new(deposit_outpoint, user_pk, assigned_operator_idx, 0);

let build_context =
TxBuildContext::new(Network::Regtest, pubkey_table, assigned_operator_idx);
Expand Down
4 changes: 2 additions & 2 deletions crates/chaintsn/src/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ fn next_rand_op_pos(rng: &mut SlotRng, num: u32) -> u32 {

#[cfg(test)]
mod tests {
use alpen_express_primitives::{buf::Buf32, params::OperatorConfig};
use alpen_express_primitives::{buf::Buf32, l1::BitcoinAmount, params::OperatorConfig};
use alpen_express_state::{
block::{ExecSegment, L1Segment, L2BlockBody},
bridge_state::OperatorTable,
Expand Down Expand Up @@ -381,7 +381,7 @@ mod tests {
let maturation_queue = header_record.maturation_queue();

let mut state_cache = StateCache::new(chs);
let amt = 100_000_000_000;
let amt: BitcoinAmount = ArbitraryGenerator::new().generate();

let new_payloads_with_deposit_update_tx: Vec<L1HeaderPayload> =
(1..=params.rollup().l1_reorg_safe_depth + 1)
Expand Down
3 changes: 3 additions & 0 deletions crates/primitives/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ use crate::{
/// mathematical operations on it while managing the operator table.
pub type OperatorIdx = u32;

/// The bitcoin block height that a withdrawal command references.
pub type BitcoinBlockHeight = u64;

/// A table that maps [`OperatorIdx`] to the corresponding [`PublicKey`].
///
/// We use a [`PublicKey`] instead of an [`bitcoin::secp256k1::XOnlyPublicKey`] for convenience
Expand Down
2 changes: 2 additions & 0 deletions crates/primitives/src/l1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ use crate::{buf::Buf32, constants::HASH_SIZE, errors::ParseError};
Arbitrary,
BorshDeserialize,
BorshSerialize,
Serialize,
Deserialize,
)]
pub struct L1TxRef(u64, u32);

Expand Down
4 changes: 2 additions & 2 deletions crates/rpc/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
use alpen_express_db::types::L1TxStatus;
use alpen_express_primitives::bridge::{OperatorIdx, PublickeyTable};
use alpen_express_rpc_types::{
types::{BlockHeader, ClientStatus, DepositEntry, ExecUpdate, L1Status},
types::{BlockHeader, ClientStatus, ExecUpdate, L1Status},
BridgeDuties, HexBytes, HexBytes32, NodeSyncStatus, RawBlockWitness, RpcCheckpointInfo,
};
use alpen_express_state::id::L2BlockId;
use alpen_express_state::{bridge_state::DepositEntry, id::L2BlockId};
use bitcoin::Txid;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};

Expand Down
21 changes: 0 additions & 21 deletions crates/rpc/types/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,6 @@ pub struct ExecUpdate {
pub da_blobs: Vec<DaBlob>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DepositState {
Created,
Accepted,
Dispatched,
Executed,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DepositEntry {
/// The index of the deposit, used to identify or track the deposit within the system.
pub deposit_idx: u32,

/// The amount of currency deposited.
pub amt: u64,

/// Deposit state.
pub state: DepositState,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NodeSyncStatus {
/// Current head L2 slot known to this node
Expand Down
4 changes: 2 additions & 2 deletions crates/state/src/bridge_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ pub struct DepositIntent {
}

impl DepositIntent {
pub fn new(amt: u64, dest_ident: &[u8]) -> Self {
pub fn new(amt: BitcoinAmount, dest_ident: &[u8]) -> Self {
Self {
amt: BitcoinAmount::from_sat(amt),
amt,
dest_ident: dest_ident.to_vec(),
}
}
Expand Down
43 changes: 30 additions & 13 deletions crates/state/src/bridge_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@
//! extended to a more sophisticated design when we have that specced out.
use alpen_express_primitives::{
bridge::OperatorIdx,
bridge::{BitcoinBlockHeight, OperatorIdx},
buf::Buf32,
l1::{self, BitcoinAmount, OutputRef, XOnlyPk},
operator::{OperatorKeyProvider, OperatorPubkeys},
};
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};

/// The bitcoin block height that a withdrawal command references.
pub type BitcoinBlockHeight = u64;

/// Entry for an operator.
///
/// Each operator has:
Expand Down Expand Up @@ -260,7 +257,7 @@ impl DepositsTable {
self.deposits.get(pos as usize)
}

pub fn add_deposits(&mut self, tx_ref: &OutputRef, operators: &[u32], amt: u64) {
pub fn add_deposits(&mut self, tx_ref: &OutputRef, operators: &[u32], amt: BitcoinAmount) {
// TODO: work out what we want to do with pending update transaction
let deposit_entry = DepositEntry::new(self.next_idx(), tx_ref, operators, amt, Vec::new());

Expand All @@ -271,10 +268,14 @@ impl DepositsTable {
pub fn next_idx(&self) -> u32 {
self.next_idx
}

pub fn deposits(&self) -> impl Iterator<Item = &DepositEntry> {
self.deposits.iter()
}
}

/// Container for the state machine of a deposit factory.
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct DepositEntry {
deposit_idx: u32,

Expand All @@ -285,8 +286,8 @@ pub struct DepositEntry {
// TODO convert this to a windowed bitmap or something
notary_operators: Vec<OperatorIdx>,

/// Deposit amount, in the native asset. For Bitcoin this is sats.
amt: u64,
/// Deposit amount, in the native asset.
amt: BitcoinAmount,

/// Refs to txs in the maturation queue that will update the deposit entry
/// when they mature. This is here so that we don't have to scan a
Expand All @@ -309,7 +310,7 @@ impl DepositEntry {
idx: u32,
output: &OutputRef,
operators: &[OperatorIdx],
amt: u64,
amt: BitcoinAmount,
pending_update_txs: Vec<l1::L1TxRef>,
) -> Self {
Self {
Expand Down Expand Up @@ -346,16 +347,21 @@ impl DepositEntry {
&mut self.state
}

pub fn amt(&self) -> u64 {
pub fn amt(&self) -> BitcoinAmount {
self.amt
}

pub fn output(&self) -> &OutputRef {
&self.output
}

pub fn set_state(&mut self, new_state: DepositState) {
self.state = new_state;
}
}

#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DepositState {
/// Deposit utxo has been recognized.
Created(CreatedState),
Expand All @@ -376,7 +382,7 @@ pub struct CreatedState {
dest_ident: Vec<u8>,
}

#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct DispatchedState {
/// Configuration for outputs to be written to.
cmd: DispatchCommand,
Expand Down Expand Up @@ -431,7 +437,13 @@ impl DispatchedState {
/// outputs we're trying to withdraw to.
///
/// May also include future information to deal with fee accounting.
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
///
/// # Note
///
/// This is mostly here in order to support withdrawal batching (i.e., sub-denomination withdrawal
/// amounts that can be batched and then serviced together). At the moment, the underlying `Vec` of
/// [`WithdrawOutput`] always has a single element.
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct DispatchCommand {
/// The table of withdrawal outputs.
withdraw_outputs: Vec<WithdrawOutput>,
Expand All @@ -449,6 +461,7 @@ impl DispatchCommand {

/// An output constructed from [`crate::bridge_ops::WithdrawalIntent`].
#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct WithdrawOutput {
/// Taproot Schnorr XOnlyPubkey with the merkle root information.
dest_addr: XOnlyPk,
Expand All @@ -461,4 +474,8 @@ impl WithdrawOutput {
pub fn new(dest_addr: XOnlyPk, amt: BitcoinAmount) -> Self {
Self { dest_addr, amt }
}

pub fn dest_addr(&self) -> &XOnlyPk {
&self.dest_addr
}
}
9 changes: 6 additions & 3 deletions crates/state/src/state_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
//! decide to expand the chain state in the future such that we can't keep it
//! entire in memory.
use alpen_express_primitives::{bridge::OperatorIdx, buf::Buf32};
use alpen_express_primitives::{
bridge::{BitcoinBlockHeight, OperatorIdx},
buf::Buf32,
};
use borsh::{BorshDeserialize, BorshSerialize};
use tracing::*;

use crate::{
bridge_ops::DepositIntent,
bridge_state::{BitcoinBlockHeight, DepositState, DispatchCommand, DispatchedState},
bridge_state::{DepositState, DispatchCommand, DispatchedState},
chain_state::ChainState,
header::L2Header,
id::L2BlockId,
Expand Down Expand Up @@ -138,7 +141,7 @@ fn apply_op_to_chainstate(op: &StateOp, state: &mut ChainState) {
let (_, deposit_txs, _) = matured_block.into_parts();
for tx in deposit_txs {
if let Deposit(deposit_info) = tx.tx().protocol_operation() {
println!("we got some deposit_txs");
trace!("we got some deposit_txs");
let amt = deposit_info.amt;
let deposit_intent = DepositIntent::new(amt, &deposit_info.address);
deposits.push_back(deposit_intent);
Expand Down
6 changes: 3 additions & 3 deletions crates/state/src/tx.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alpen_express_primitives::l1::OutputRef;
use alpen_express_primitives::l1::{BitcoinAmount, OutputRef};
use arbitrary::Arbitrary;
use borsh::{BorshDeserialize, BorshSerialize};

Expand All @@ -16,8 +16,8 @@ pub enum ProtocolOperation {

#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Arbitrary)]
pub struct DepositInfo {
/// amount in satoshis
pub amt: u64,
/// Bitcoin amount
pub amt: BitcoinAmount,

/// outpoint
pub outpoint: OutputRef,
Expand Down
4 changes: 2 additions & 2 deletions crates/tx-parser/src/deposit/deposit_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn extract_deposit_info(tx: &Transaction, config: &DepositTxConfig) -> Optio

// Construct and return the DepositInfo
Some(DepositInfo {
amt: output_0.value.to_sat(),
amt: output_0.value.into(),
address: ee_address.to_vec(),
outpoint: OutputRef::from(prev_out.previous_output),
})
Expand Down Expand Up @@ -103,7 +103,7 @@ mod tests {
assert!(out.is_some());
let out = out.unwrap();

assert_eq!(out.amt, amt.to_sat());
assert_eq!(out.amt, amt.into());
assert_eq!(out.address, ee_addr);
}
}
7 changes: 5 additions & 2 deletions crates/tx-parser/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ mod test {
use alpen_express_btcio::test_utils::{
build_reveal_transaction_test, generate_inscription_script_test,
};
use alpen_express_primitives::l1::BitcoinAmount;
use alpen_express_state::{
batch::SignedBatchCheckpoint,
tx::{InscriptionData, ProtocolOperation},
Expand Down Expand Up @@ -266,7 +267,8 @@ mod test {
if let ProtocolOperation::Deposit(deposit_info) = &result[0].proto_op() {
assert_eq!(deposit_info.address, ee_addr, "EE address should match");
assert_eq!(
deposit_info.amt, config.deposit_quantity,
deposit_info.amt,
BitcoinAmount::from_sat(config.deposit_quantity),
"Deposit amount should match"
);
} else {
Expand Down Expand Up @@ -389,7 +391,8 @@ mod test {
i
);
assert_eq!(
deposit_info.amt, config.deposit_quantity,
deposit_info.amt,
BitcoinAmount::from_sat(config.deposit_quantity),
"Deposit amount should match for transaction {}",
i
);
Expand Down
Loading

0 comments on commit 06fc7fa

Please sign in to comment.