Skip to content

Commit

Permalink
[feature] move events module to sbtc crate (#1144)
Browse files Browse the repository at this point in the history
* move events module to sbtc crate

* remove unnecessary structs from model.rs

* fix imports in tests

* move to another BitcoinBlockHash type

* switch to another BitcoinTxId type

* switch from StacksBlockId to StacksBlockHash

* switch from ScriptBuf to ScriptPubKey

* StacksTxid to StacksTxId

* use less types from sbtc

* revert BurnchainHeaderHash usage

* Conversion between sbtc and signer StacksTxid

* fmt

* use new types in tests

* make inners in wrappers back private

* remove conversions from signer to sbtc types

* switch to local stacks principal

* prettify imports and cargo fmt

* starting switching all conversions to .into()

* switching conversions to .into() in more places

* add local KeyRotationEvent
  • Loading branch information
MCJOHN974 authored Dec 18, 2024
1 parent 9a8cd8d commit 6b7e313
Show file tree
Hide file tree
Showing 13 changed files with 326 additions and 141 deletions.
1 change: 0 additions & 1 deletion emily/handler/src/database/entries/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,6 @@ impl DepositUpdatePackage {
mod tests {
use super::*;
use test_case::test_case;
use testing_emily_client::models::fulfillment;

#[test]
fn deposit_update_should_be_unnecessary_when_event_is_present() {
Expand Down
48 changes: 20 additions & 28 deletions signer/src/stacks/events.rs → sbtc/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use std::collections::BTreeMap;

use bitcoin::hashes::Hash;
use bitcoin::hex::DisplayHex;
use bitcoin::BlockHash as BitcoinBlockHash;
use bitcoin::OutPoint;
use bitcoin::PubkeyHash;
Expand All @@ -19,8 +20,6 @@ use bitcoin::ScriptHash;
use bitcoin::Txid as BitcoinTxid;
use bitcoin::WitnessProgram;
use bitcoin::WitnessVersion;
use bitvec::array::BitArray;
use blockstack_lib::burnchains::Txid as StacksTxid;
use clarity::vm::types::CharType;
use clarity::vm::types::PrincipalData;
use clarity::vm::types::SequenceData;
Expand All @@ -30,6 +29,18 @@ use clarity::vm::Value as ClarityValue;
use secp256k1::PublicKey;
use stacks_common::types::chainstate::StacksBlockId;

use std::fmt::Display;

/// Stacks transaction identifier. Wrapper over a 32 byte array.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct StacksTxid(pub [u8; 32]);

impl Display for StacksTxid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0.to_hex_string(bitcoin::hex::Case::Lower))
}
}

/// This trait adds a function for converting bytes from little-endian byte
/// order into a bitcoin hash types. This is because the signers convert
/// [`bitcoin::Txid`] and [`bitcoin::BlockHash`] bytes into little-endian
Expand Down Expand Up @@ -232,7 +243,7 @@ pub struct WithdrawalAcceptEvent {
/// The bitmap of how the signers voted for the withdrawal request.
/// Here, a 1 (or true) implies that the signer did *not* vote to
/// accept the request.
pub signer_bitmap: BitArray<[u8; 16]>,
pub signer_bitmap: u128,
/// This is the outpoint for the bitcoin transaction that serviced the
/// request.
pub outpoint: OutPoint,
Expand Down Expand Up @@ -263,7 +274,7 @@ pub struct WithdrawalRejectEvent {
/// The bitmap of how the signers voted for the withdrawal request.
/// Here, a 1 (or true) implies that the signer did *not* vote to
/// accept the request.
pub signer_bitmap: BitArray<[u8; 16]>,
pub signer_bitmap: u128,
}

/// This is the event that is emitted from the `rotate-keys`
Expand Down Expand Up @@ -626,7 +637,7 @@ impl RawTupleData {
// This shouldn't error for the reasons noted in
// [`withdrawal_create`].
request_id: u64::try_from(request_id).map_err(EventError::ClarityIntConversion)?,
signer_bitmap: BitArray::new(bitmap.to_le_bytes()),
signer_bitmap: bitmap,
outpoint: OutPoint {
// This shouldn't error, this is set from a proper [`Txid`] in
// a contract call.
Expand Down Expand Up @@ -677,7 +688,7 @@ impl RawTupleData {
// This shouldn't error for the reasons noted in
// [`withdrawal_create`].
request_id: u64::try_from(request_id).map_err(EventError::ClarityIntConversion)?,
signer_bitmap: BitArray::new(bitmap.to_le_bytes()),
signer_bitmap: bitmap,
}))
}

Expand Down Expand Up @@ -733,7 +744,6 @@ mod tests {

use bitcoin::key::CompressedPublicKey;
use bitcoin::key::TweakedPublicKey;
use bitvec::field::BitField as _;
use clarity::vm::types::ListData;
use clarity::vm::types::ListTypeData;
use clarity::vm::types::BUFF_33;
Expand All @@ -749,24 +759,6 @@ mod tests {
block_id: StacksBlockId([0; 32]),
};

#[test]
fn signer_bitmap_conversion() {
// This test checks that converting from an integer to the bitmap
// works the way that we expect.
let bitmap_number: u128 = 3;
let bitmap: BitArray<[u8; 16]> = BitArray::new(bitmap_number.to_le_bytes());

assert_eq!(bitmap.load_le::<u128>(), bitmap_number);

// This is basically a test of the same thing as the above, except
// that we explicitly create the signer bitmap.
let mut bitmap: BitArray<[u8; 16]> = BitArray::ZERO;
bitmap.set(0, true);
bitmap.set(1, true);

assert_eq!(bitmap.load_le::<u128>(), bitmap_number);
}

#[test]
fn complete_deposit_event() {
let amount = 123654789;
Expand Down Expand Up @@ -802,7 +794,7 @@ mod tests {
assert_eq!(event.outpoint.vout, 3);
assert_eq!(
event.sweep_block_hash,
BitcoinBlockHash::from_byte_array([2; 32])
BitcoinBlockHash::from_byte_array([2; 32]),
);
assert_eq!(event.sweep_block_height, 139);
assert_eq!(event.sweep_txid, BitcoinTxid::from_byte_array([3; 32]));
Expand Down Expand Up @@ -922,7 +914,7 @@ mod tests {
// let res = transform_value(value, NetworkKind::Regtest).unwrap();
match RegistryEvent::try_new(value, TX_INFO).unwrap() {
RegistryEvent::WithdrawalAccept(event) => {
let expected_bitmap = BitArray::<[u8; 16]>::new(bitmap.to_le_bytes());
let expected_bitmap = bitmap;
assert_eq!(event.request_id, request_id as u64);
assert_eq!(event.outpoint.txid, BitcoinTxid::from_byte_array([1; 32]));
assert_eq!(event.outpoint.vout, vout as u32);
Expand Down Expand Up @@ -964,7 +956,7 @@ mod tests {
// let res = transform_value(value, NetworkKind::Regtest).unwrap();
match RegistryEvent::try_new(value, TX_INFO).unwrap() {
RegistryEvent::WithdrawalReject(event) => {
let expected_bitmap = BitArray::<[u8; 16]>::new(bitmap.to_le_bytes());
let expected_bitmap = bitmap;
assert_eq!(event.request_id, request_id as u64);
assert_eq!(event.signer_bitmap, expected_bitmap);
}
Expand Down
1 change: 1 addition & 0 deletions sbtc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bitcoin::XOnlyPublicKey;

pub mod deposits;
pub mod error;
pub mod events;

#[cfg(any(test, feature = "testing"))]
pub mod testing;
Expand Down
85 changes: 43 additions & 42 deletions signer/src/api/new_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,24 @@ use emily_client::models::UpdateWithdrawalsResponse;
use emily_client::models::WithdrawalParameters;
use emily_client::models::WithdrawalUpdate;
use futures::FutureExt;
use sbtc::events::RegistryEvent;
use sbtc::events::TxInfo;
use std::sync::OnceLock;

use crate::context::Context;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::metrics::Metrics;
use crate::metrics::STACKS_BLOCKCHAIN;
use crate::stacks::events::CompletedDepositEvent;
use crate::stacks::events::KeyRotationEvent;
use crate::stacks::events::RegistryEvent;
use crate::stacks::events::TxInfo;
use crate::stacks::events::WithdrawalAcceptEvent;
use crate::stacks::events::WithdrawalCreateEvent;
use crate::stacks::events::WithdrawalRejectEvent;
use crate::stacks::webhooks::NewBlockEvent;
use crate::storage::model::BitcoinBlockHash;
use crate::storage::model::CompletedDepositEvent;
use crate::storage::model::KeyRotationEvent;
use crate::storage::model::RotateKeysTransaction;
use crate::storage::model::StacksBlock;
use crate::storage::model::StacksBlockHash;
use crate::storage::model::StacksTxId;
use crate::storage::model::WithdrawalAcceptEvent;
use crate::storage::model::WithdrawalCreateEvent;
use crate::storage::model::WithdrawalRejectEvent;
use crate::storage::DbRead;
use crate::storage::DbWrite;

Expand Down Expand Up @@ -119,10 +117,10 @@ pub async fn new_block_handler(state: State<ApiState<impl Context>>, body: Strin
.filter(|(ev, _)| &ev.contract_identifier == registry_address && ev.topic == "print");

let stacks_chaintip = StacksBlock {
block_hash: StacksBlockHash::from(new_block_event.index_block_hash),
block_hash: new_block_event.index_block_hash.into(),
block_height: new_block_event.block_height,
parent_hash: StacksBlockHash::from(new_block_event.parent_index_block_hash),
bitcoin_anchor: BitcoinBlockHash::from(new_block_event.burn_block_hash),
parent_hash: new_block_event.parent_index_block_hash.into(),
bitcoin_anchor: new_block_event.burn_block_hash.into(),
};
let block_id = new_block_event.index_block_hash;

Expand All @@ -132,30 +130,33 @@ pub async fn new_block_handler(state: State<ApiState<impl Context>>, body: Strin
let mut created_withdrawals = Vec::new();

for (ev, txid) in events {
let tx_info = TxInfo { txid, block_id };
let tx_info = TxInfo {
txid: sbtc::events::StacksTxid(txid.0),
block_id,
};
let res = match RegistryEvent::try_new(ev.value, tx_info) {
Ok(RegistryEvent::CompletedDeposit(event)) => {
handle_completed_deposit(&api.ctx, event, &stacks_chaintip)
handle_completed_deposit(&api.ctx, event.into(), &stacks_chaintip)
.await
.map(|x| completed_deposits.push(x))
}
Ok(RegistryEvent::WithdrawalAccept(event)) => {
handle_withdrawal_accept(&api.ctx, event, &stacks_chaintip)
handle_withdrawal_accept(&api.ctx, event.into(), &stacks_chaintip)
.await
.map(|x| updated_withdrawals.push(x))
}
Ok(RegistryEvent::WithdrawalReject(event)) => {
handle_withdrawal_reject(&api.ctx, event, &stacks_chaintip)
handle_withdrawal_reject(&api.ctx, event.into(), &stacks_chaintip)
.await
.map(|x| updated_withdrawals.push(x))
}
Ok(RegistryEvent::WithdrawalCreate(event)) => {
handle_withdrawal_create(&api.ctx, event, stacks_chaintip.block_height)
handle_withdrawal_create(&api.ctx, event.into(), stacks_chaintip.block_height)
.await
.map(|x| created_withdrawals.push(x))
}
Ok(RegistryEvent::KeyRotation(event)) => {
handle_key_rotation(&api.ctx, event, tx_info.txid.into()).await
handle_key_rotation(&api.ctx, event.into(), tx_info.txid.into()).await
}
Err(error) => {
tracing::error!(%error, "got an error when transforming the event ClarityValue");
Expand Down Expand Up @@ -385,8 +386,8 @@ async fn handle_key_rotation(
) -> Result<(), Error> {
let key_rotation_tx = RotateKeysTransaction {
txid: stacks_txid,
address: event.new_address.into(),
aggregate_key: event.new_aggregate_pubkey.into(),
address: event.new_address,
aggregate_key: event.new_aggregate_pubkey,
signer_set: event.new_keys.into_iter().map(Into::into).collect(),
signatures_required: event.new_signature_threshold,
};
Expand All @@ -401,7 +402,6 @@ mod tests {
use super::*;

use bitcoin::OutPoint;
use bitcoin::ScriptBuf;
use bitvec::array::BitArray;
use clarity::vm::types::PrincipalData;
use emily_client::models::UpdateDepositsResponse;
Expand All @@ -414,6 +414,7 @@ mod tests {

use crate::storage::in_memory::Store;
use crate::storage::model::DepositRequest;
use crate::storage::model::ScriptPubKey;
use crate::storage::model::StacksPrincipal;
use crate::testing::context::*;
use crate::testing::storage::model::TestData;
Expand Down Expand Up @@ -613,12 +614,12 @@ mod tests {

let event = CompletedDepositEvent {
outpoint: deposit_request.outpoint(),
txid: *stacks_txid,
block_id: *stacks_chaintip.block_hash,
txid: stacks_txid.into(),
block_id: stacks_chaintip.block_hash.into(),
amount: deposit_request.amount - btc_fee,
sweep_block_hash: *bitcoin_block.block_hash,
sweep_block_hash: bitcoin_block.block_hash.into(),
sweep_block_height: bitcoin_block.block_height,
sweep_txid: *txid,
sweep_txid: txid.into(),
};
let expectation = DepositUpdate {
bitcoin_tx_output_index: event.outpoint.vout,
Expand Down Expand Up @@ -677,12 +678,12 @@ mod tests {
let outpoint = OutPoint { txid: *txid, vout: 0 };
let event = CompletedDepositEvent {
outpoint: outpoint.clone(),
txid: *stacks_txid,
block_id: *stacks_chaintip.block_hash,
txid: stacks_txid.into(),
block_id: stacks_chaintip.block_hash.into(),
amount: 100,
sweep_block_hash: *bitcoin_block.block_hash,
sweep_block_hash: bitcoin_block.block_hash.into(),
sweep_block_height: bitcoin_block.block_height,
sweep_txid: *txid,
sweep_txid: txid.into(),
};
let res = handle_completed_deposit(&ctx, event, stacks_chaintip).await;
assert!(res.is_err());
Expand Down Expand Up @@ -730,13 +731,13 @@ mod tests {
let event = WithdrawalAcceptEvent {
request_id: 1,
outpoint: OutPoint { txid: *txid, vout: 0 },
txid: *stacks_tx.txid,
block_id: *stacks_tx.block_hash,
txid: stacks_tx.txid.into(),
block_id: stacks_tx.block_hash.into(),
fee: 1,
signer_bitmap: BitArray::<_>::ZERO,
sweep_block_hash: *bitcoin_block.block_hash,
sweep_block_hash: bitcoin_block.block_hash.into(),
sweep_block_height: bitcoin_block.block_height,
sweep_txid: *txid,
sweep_txid: txid.into(),
};

// Expected struct to be added to the accepted_withdrawals vector
Expand Down Expand Up @@ -795,12 +796,12 @@ mod tests {

let event = WithdrawalCreateEvent {
request_id: 1,
block_id: *stacks_first_tx.block_hash,
block_id: stacks_first_tx.block_hash.into(),
amount: 100,
max_fee: 1,
recipient: ScriptBuf::default(),
txid: *stacks_first_tx.txid,
sender: PrincipalData::Standard(StandardPrincipalData::transient()),
recipient: ScriptPubKey::from_bytes(vec![]),
txid: stacks_first_tx.txid,
sender: PrincipalData::Standard(StandardPrincipalData::transient()).into(),
block_height: test_data.bitcoin_blocks[0].block_height,
};

Expand Down Expand Up @@ -857,8 +858,8 @@ mod tests {

let event = WithdrawalRejectEvent {
request_id: 1,
block_id: *stacks_chaintip.block_hash,
txid: *test_data.stacks_transactions[0].txid,
block_id: stacks_chaintip.block_hash.into(),
txid: test_data.stacks_transactions[0].txid,
signer_bitmap: BitArray::<_>::ZERO,
};

Expand Down Expand Up @@ -898,11 +899,11 @@ mod tests {

let txid: StacksTxId = fake::Faker.fake_with_rng(&mut OsRng);
let event = KeyRotationEvent {
new_aggregate_pubkey: SECP256K1.generate_keypair(&mut OsRng).1,
new_aggregate_pubkey: SECP256K1.generate_keypair(&mut OsRng).1.into(),
new_keys: (0..3)
.map(|_| SECP256K1.generate_keypair(&mut OsRng).1)
.map(|_| SECP256K1.generate_keypair(&mut OsRng).1.into())
.collect(),
new_address: PrincipalData::Standard(StandardPrincipalData::transient()),
new_address: PrincipalData::Standard(StandardPrincipalData::transient()).into(),
new_signature_threshold: 3,
};

Expand Down
2 changes: 1 addition & 1 deletion signer/src/request_decider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ where

let msg = SignerWithdrawalDecision {
request_id: withdrawal_request.request_id,
block_hash: withdrawal_request.block_hash.0,
block_hash: withdrawal_request.block_hash.into_bytes(),
accepted: is_accepted,
txid: withdrawal_request.txid,
};
Expand Down
1 change: 0 additions & 1 deletion signer/src/stacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
/// Contains an interface for interacting with a stacks node.
pub mod api;
pub mod contracts;
pub mod events;
/// Contains structs for signing stacks transactions using the signers'
/// multi-sig wallet.
pub mod wallet;
Expand Down
8 changes: 4 additions & 4 deletions signer/src/storage/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use crate::error::Error;
use crate::keys::PublicKey;
use crate::keys::PublicKeyXOnly;
use crate::keys::SignerScriptPubKey as _;
use crate::stacks::events::CompletedDepositEvent;
use crate::stacks::events::WithdrawalAcceptEvent;
use crate::stacks::events::WithdrawalCreateEvent;
use crate::stacks::events::WithdrawalRejectEvent;
use crate::storage::model;
use crate::storage::model::CompletedDepositEvent;
use crate::storage::model::WithdrawalAcceptEvent;
use crate::storage::model::WithdrawalCreateEvent;
use crate::storage::model::WithdrawalRejectEvent;
use crate::DEPOSIT_LOCKTIME_BLOCK_BUFFER;

use super::util::get_utxo;
Expand Down
Loading

0 comments on commit 6b7e313

Please sign in to comment.