Skip to content

Commit 7cfcb0b

Browse files
WIP further file structure work
1 parent 97262a3 commit 7cfcb0b

File tree

19 files changed

+2611
-1634
lines changed

19 files changed

+2611
-1634
lines changed

src/core/block.rs

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
use std::{ffi::c_void, marker::PhantomData};
2+
3+
use libbitcoinkernel_sys::{
4+
btck_Block, btck_BlockSpentOutputs, btck_BlockTreeEntry, btck_TransactionSpentOutputs,
5+
btck_block_copy, btck_block_count_transactions, btck_block_create, btck_block_destroy,
6+
btck_block_get_hash, btck_block_get_transaction_at, btck_block_hash_destroy,
7+
btck_block_spent_outputs_copy, btck_block_spent_outputs_count,
8+
btck_block_spent_outputs_destroy, btck_block_spent_outputs_get_transaction_spent_outputs_at,
9+
btck_block_to_bytes, btck_block_tree_entry_destroy, btck_block_tree_entry_get_block_hash,
10+
btck_block_tree_entry_get_height, btck_block_tree_entry_get_previous,
11+
btck_transaction_spent_outputs_copy, btck_transaction_spent_outputs_count,
12+
btck_transaction_spent_outputs_destroy, btck_transaction_spent_outputs_get_coin_at,
13+
};
14+
15+
use crate::{c_serialize, state::ChainstateManager, KernelError, RefType};
16+
17+
use super::transaction::{Coin, Transaction};
18+
19+
/// A block tree entry that is tied to a specific [`ChainstateManager`].
20+
///
21+
/// Internally the [`ChainstateManager`] keeps an in-memory of the current block
22+
/// tree once it is loaded. The [`BlockTreeEntry`] points to an entry in this tree.
23+
/// It is only valid as long as the [`ChainstateManager`] it was retrieved from
24+
/// remains in scope.
25+
#[derive(Debug)]
26+
pub struct BlockTreeEntry {
27+
inner: *mut btck_BlockTreeEntry,
28+
marker: PhantomData<ChainstateManager>,
29+
}
30+
31+
unsafe impl Send for BlockTreeEntry {}
32+
unsafe impl Sync for BlockTreeEntry {}
33+
34+
impl BlockTreeEntry {
35+
/// Creates a BlockTreeEntry from an FFI pointer for internal library use.
36+
pub(crate) fn from_ptr(inner: *mut btck_BlockTreeEntry) -> Self {
37+
Self {
38+
inner,
39+
marker: PhantomData,
40+
}
41+
}
42+
43+
/// Move to the previous entry in the block tree. E.g. from height n to
44+
/// height n-1.
45+
pub fn prev(self) -> Result<BlockTreeEntry, KernelError> {
46+
let inner = unsafe { btck_block_tree_entry_get_previous(self.inner) };
47+
48+
if inner.is_null() {
49+
return Err(KernelError::OutOfBounds);
50+
}
51+
52+
Ok(BlockTreeEntry {
53+
inner,
54+
marker: self.marker,
55+
})
56+
}
57+
58+
/// Returns the current height associated with this BlockTreeEntry.
59+
pub fn height(&self) -> i32 {
60+
unsafe { btck_block_tree_entry_get_height(self.inner) }
61+
}
62+
63+
/// Returns the current block hash associated with this BlockTreeEntry.
64+
pub fn block_hash(&self) -> BlockHash {
65+
let hash = unsafe { btck_block_tree_entry_get_block_hash(self.inner) };
66+
let res = BlockHash {
67+
hash: unsafe { (&*hash).hash },
68+
};
69+
unsafe { btck_block_hash_destroy(hash) };
70+
res
71+
}
72+
73+
/// Get the inner FFI pointer for internal library use
74+
pub(crate) fn as_ptr(&self) -> *mut btck_BlockTreeEntry {
75+
self.inner
76+
}
77+
}
78+
79+
impl Drop for BlockTreeEntry {
80+
fn drop(&mut self) {
81+
unsafe { btck_block_tree_entry_destroy(self.inner) };
82+
}
83+
}
84+
85+
/// A type for a Block hash.
86+
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
87+
pub struct BlockHash {
88+
pub hash: [u8; 32],
89+
}
90+
91+
/// A Bitcoin block containing a header and transactions.
92+
///
93+
/// Blocks can be created from raw serialized data or retrieved from the blockchain.
94+
/// They represent the fundamental units of the Bitcoin blockchain structure.
95+
pub struct Block {
96+
inner: *mut btck_Block,
97+
}
98+
99+
unsafe impl Send for Block {}
100+
unsafe impl Sync for Block {}
101+
102+
impl Block {
103+
/// Creates a Block from an FFI pointer for internal library use.
104+
pub(crate) fn from_ptr(inner: *mut btck_Block) -> Self {
105+
Self { inner }
106+
}
107+
108+
/// Returns the hash of this block.
109+
///
110+
/// This is the double SHA256 hash of the block header, which serves as
111+
/// the block's unique identifier.
112+
pub fn hash(&self) -> BlockHash {
113+
let hash = unsafe { btck_block_get_hash(self.inner) };
114+
let res = BlockHash {
115+
hash: unsafe { (&*hash).hash },
116+
};
117+
unsafe { btck_block_hash_destroy(hash) };
118+
res
119+
}
120+
121+
/// Returns the number of transactions in this block.
122+
pub fn transaction_count(&self) -> usize {
123+
unsafe { btck_block_count_transactions(self.inner) as usize }
124+
}
125+
126+
/// Returns the transaction at the specified index.
127+
///
128+
/// # Arguments
129+
/// * `index` - The zero-based index of the transaction (0 is the coinbase)
130+
///
131+
/// # Errors
132+
/// Returns [`KernelError::OutOfBounds`] if the index is invalid.
133+
pub fn transaction(&self, index: usize) -> Result<Transaction, KernelError> {
134+
if index >= self.transaction_count() {
135+
return Err(KernelError::OutOfBounds);
136+
}
137+
let tx = unsafe { btck_block_get_transaction_at(self.inner, index) };
138+
Ok(Transaction::from_ptr(tx))
139+
}
140+
141+
/// Consensus encodes the block to Bitcoin wire format.
142+
pub fn consensus_encode(&self) -> Result<Vec<u8>, KernelError> {
143+
c_serialize(|callback, user_data| unsafe {
144+
btck_block_to_bytes(self.inner, Some(callback), user_data)
145+
})
146+
}
147+
148+
/// Get the inner FFI pointer for internal library use
149+
pub(crate) fn as_ptr(&self) -> *mut btck_Block {
150+
self.inner
151+
}
152+
}
153+
154+
impl TryFrom<Block> for Vec<u8> {
155+
type Error = KernelError;
156+
157+
fn try_from(block: Block) -> Result<Self, KernelError> {
158+
block.consensus_encode()
159+
}
160+
}
161+
162+
impl TryFrom<&[u8]> for Block {
163+
type Error = KernelError;
164+
165+
fn try_from(raw_block: &[u8]) -> Result<Self, Self::Error> {
166+
let inner =
167+
unsafe { btck_block_create(raw_block.as_ptr() as *const c_void, raw_block.len()) };
168+
if inner.is_null() {
169+
return Err(KernelError::Internal(
170+
"Failed to de-serialize Block.".to_string(),
171+
));
172+
}
173+
Ok(Block { inner })
174+
}
175+
}
176+
177+
impl Clone for Block {
178+
fn clone(&self) -> Self {
179+
Block {
180+
inner: unsafe { btck_block_copy(self.inner) },
181+
}
182+
}
183+
}
184+
185+
impl Drop for Block {
186+
fn drop(&mut self) {
187+
unsafe { btck_block_destroy(self.inner) };
188+
}
189+
}
190+
191+
/// Spent output data for all transactions in a block.
192+
///
193+
/// This contains the previous outputs that were consumed by all transactions
194+
/// in a specific block.
195+
pub struct BlockSpentOutputs {
196+
inner: *mut btck_BlockSpentOutputs,
197+
}
198+
199+
unsafe impl Send for BlockSpentOutputs {}
200+
unsafe impl Sync for BlockSpentOutputs {}
201+
202+
impl BlockSpentOutputs {
203+
/// Creates BlockSpentOutputs from an FFI pointer for internal library use.
204+
pub(crate) fn from_ptr(inner: *mut btck_BlockSpentOutputs) -> Self {
205+
Self { inner }
206+
}
207+
208+
/// Returns the number of transactions that have spent output data.
209+
///
210+
/// Note: This excludes the coinbase transaction, which has no inputs.
211+
pub fn count(&self) -> usize {
212+
unsafe { btck_block_spent_outputs_count(self.inner) }
213+
}
214+
215+
/// Returns a reference to the spent outputs for a specific transaction in the block.
216+
///
217+
/// # Arguments
218+
/// * `transaction_index` - The index of the transaction (0-based, excluding coinbase)
219+
///
220+
/// # Returns
221+
/// * `Ok(RefType<TransactionSpentOutputs, BlockSpentOutputs>)` - A reference to the transaction's spent outputs
222+
/// * `Err(KernelError::OutOfBounds)` - If the index is invalid
223+
pub fn transaction_spent_outputs(
224+
&self,
225+
transaction_index: usize,
226+
) -> Result<RefType<'_, TransactionSpentOutputs, BlockSpentOutputs>, KernelError> {
227+
let tx_out_ptr = unsafe {
228+
btck_block_spent_outputs_get_transaction_spent_outputs_at(self.inner, transaction_index)
229+
};
230+
if tx_out_ptr.is_null() {
231+
return Err(KernelError::OutOfBounds);
232+
}
233+
Ok(RefType::new(TransactionSpentOutputs { inner: tx_out_ptr }))
234+
}
235+
}
236+
237+
impl Clone for BlockSpentOutputs {
238+
fn clone(&self) -> Self {
239+
BlockSpentOutputs {
240+
inner: unsafe { btck_block_spent_outputs_copy(self.inner) },
241+
}
242+
}
243+
}
244+
245+
impl Drop for BlockSpentOutputs {
246+
fn drop(&mut self) {
247+
unsafe { btck_block_spent_outputs_destroy(self.inner) };
248+
}
249+
}
250+
251+
/// Spent output data for a single transaction.
252+
///
253+
/// Contains all the coins (UTXOs) that were consumed by a specific transaction's
254+
/// inputs, in the same order as the transaction's inputs.
255+
pub struct TransactionSpentOutputs {
256+
inner: *mut btck_TransactionSpentOutputs,
257+
}
258+
259+
unsafe impl Send for TransactionSpentOutputs {}
260+
unsafe impl Sync for TransactionSpentOutputs {}
261+
262+
impl TransactionSpentOutputs {
263+
/// Returns the number of coins spent by this transaction.
264+
pub fn count(&self) -> usize {
265+
unsafe { btck_transaction_spent_outputs_count(self.inner) }
266+
}
267+
268+
/// Returns a reference to the coin at the specified input index.
269+
///
270+
/// # Arguments
271+
/// * `coin_index` - The index corresponding to the transaction input
272+
///
273+
/// # Returns
274+
/// * `Ok(RefType<Coin, TransactionSpentOutputs>)` - A reference to the coin
275+
/// * `Err(KernelError::OutOfBounds)` - If the index is invalid
276+
pub fn coin(
277+
&self,
278+
coin_index: usize,
279+
) -> Result<RefType<'_, Coin, TransactionSpentOutputs>, KernelError> {
280+
let coin_ptr = unsafe {
281+
btck_transaction_spent_outputs_get_coin_at(self.inner as *const _, coin_index)
282+
};
283+
if coin_ptr.is_null() {
284+
return Err(KernelError::OutOfBounds);
285+
}
286+
287+
Ok(RefType::new(Coin::from_ptr(coin_ptr)))
288+
}
289+
}
290+
291+
impl Clone for TransactionSpentOutputs {
292+
fn clone(&self) -> Self {
293+
TransactionSpentOutputs {
294+
inner: unsafe { btck_transaction_spent_outputs_copy(self.inner) },
295+
}
296+
}
297+
}
298+
299+
impl Drop for TransactionSpentOutputs {
300+
fn drop(&mut self) {
301+
unsafe { btck_transaction_spent_outputs_destroy(self.inner) };
302+
}
303+
}

src/core/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub mod block;
2+
pub mod script;
3+
pub mod transaction;
4+
pub mod verify;
5+
6+
pub use block::{Block, BlockHash, BlockSpentOutputs, BlockTreeEntry, TransactionSpentOutputs};
7+
pub use script::ScriptPubkey;
8+
pub use transaction::{Coin, Transaction, TxOut};
9+
pub use verify::{
10+
verify, ScriptVerifyError, ScriptVerifyStatus, VERIFY_ALL, VERIFY_ALL_PRE_TAPROOT,
11+
VERIFY_CHECKLOCKTIMEVERIFY, VERIFY_CHECKSEQUENCEVERIFY, VERIFY_DERSIG, VERIFY_NONE,
12+
VERIFY_NULLDUMMY, VERIFY_P2SH, VERIFY_TAPROOT, VERIFY_WITNESS,
13+
};

src/core/script.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use std::ffi::c_void;
2+
3+
use libbitcoinkernel_sys::{
4+
btck_ScriptPubkey, btck_script_pubkey_copy, btck_script_pubkey_create,
5+
btck_script_pubkey_destroy, btck_script_pubkey_to_bytes,
6+
};
7+
8+
use crate::{c_serialize, KernelError};
9+
10+
/// A single script pubkey containing spending conditions for a transaction output.
11+
///
12+
/// Script pubkeys can be created from raw script bytes or retrieved from existing
13+
/// transaction outputs.
14+
#[derive(Debug)]
15+
pub struct ScriptPubkey {
16+
inner: *mut btck_ScriptPubkey,
17+
}
18+
19+
unsafe impl Send for ScriptPubkey {}
20+
unsafe impl Sync for ScriptPubkey {}
21+
22+
impl ScriptPubkey {
23+
/// Creates a ScriptPubkey from an FFI pointer for internal library use.
24+
pub(crate) fn from_ptr(inner: *mut btck_ScriptPubkey) -> Self {
25+
Self { inner }
26+
}
27+
28+
/// Serializes the script to raw bytes.
29+
pub fn to_bytes(&self) -> Vec<u8> {
30+
c_serialize(|callback, user_data| unsafe {
31+
btck_script_pubkey_to_bytes(self.inner, Some(callback), user_data)
32+
})
33+
.expect("Script pubkey to_bytes should never fail")
34+
}
35+
36+
/// Get the inner FFI pointer for internal library use
37+
pub(crate) fn as_ptr(&self) -> *mut btck_ScriptPubkey {
38+
self.inner
39+
}
40+
}
41+
42+
impl From<ScriptPubkey> for Vec<u8> {
43+
fn from(pubkey: ScriptPubkey) -> Self {
44+
pubkey.to_bytes()
45+
}
46+
}
47+
48+
impl TryFrom<&[u8]> for ScriptPubkey {
49+
type Error = KernelError;
50+
51+
fn try_from(raw_script_pubkey: &[u8]) -> Result<Self, Self::Error> {
52+
let inner = unsafe {
53+
btck_script_pubkey_create(
54+
raw_script_pubkey.as_ptr() as *const c_void,
55+
raw_script_pubkey.len(),
56+
)
57+
};
58+
if inner.is_null() {
59+
return Err(KernelError::Internal(
60+
"Failed to decode raw script pubkey".to_string(),
61+
));
62+
}
63+
Ok(ScriptPubkey { inner })
64+
}
65+
}
66+
67+
impl Clone for ScriptPubkey {
68+
fn clone(&self) -> Self {
69+
ScriptPubkey {
70+
inner: unsafe { btck_script_pubkey_copy(self.inner) },
71+
}
72+
}
73+
}
74+
75+
impl Drop for ScriptPubkey {
76+
fn drop(&mut self) {
77+
unsafe { btck_script_pubkey_destroy(self.inner) }
78+
}
79+
}

0 commit comments

Comments
 (0)