-
Notifications
You must be signed in to change notification settings - Fork 11
refactor: use BlockInfo in TransactionRecord
#580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,28 +3,61 @@ | |
| use dashcore::hashes::Hash; | ||
| use key_wallet::transaction_checking::{BlockInfo, TransactionContext}; | ||
| use key_wallet::{Network, Wallet}; | ||
| use std::os::raw::{c_char, c_uint}; | ||
| use std::os::raw::c_char; | ||
| use std::sync::Arc; | ||
|
|
||
| /// Convert FFI block parameters to a `BlockInfo`. | ||
| /// | ||
| /// # Safety | ||
| /// | ||
| /// If `block_hash` is non-null it must point to 32 readable bytes. | ||
| pub(crate) unsafe fn block_info_from_ffi( | ||
| height: u32, | ||
| block_hash: *const u8, | ||
| timestamp: u64, | ||
| ) -> BlockInfo { | ||
| let block_hash = if !block_hash.is_null() { | ||
| let hash_bytes = std::slice::from_raw_parts(block_hash, 32); | ||
| let mut arr = [0u8; 32]; | ||
| arr.copy_from_slice(hash_bytes); | ||
| dashcore::BlockHash::from_byte_array(arr) | ||
| } else { | ||
| dashcore::BlockHash::all_zeros() | ||
| }; | ||
| BlockInfo::new(height, block_hash, timestamp as u32) | ||
| /// FFI-compatible block metadata (height, hash, timestamp). | ||
| #[repr(C)] | ||
| #[derive(Debug, Clone, Copy)] | ||
| pub struct FFIBlockInfo { | ||
| /// Block height | ||
| pub height: u32, | ||
| /// Block hash (32 bytes) | ||
| pub block_hash: [u8; 32], | ||
| /// Unix timestamp | ||
| pub timestamp: u32, | ||
| } | ||
|
|
||
| impl FFIBlockInfo { | ||
| /// All-zeros placeholder used for unconfirmed contexts. | ||
| pub fn empty() -> Self { | ||
| Self { | ||
| height: 0, | ||
| block_hash: [0u8; 32], | ||
| timestamp: 0, | ||
| } | ||
| } | ||
|
|
||
| /// Convert to native `BlockInfo`. | ||
| pub fn to_block_info(&self) -> BlockInfo { | ||
| let block_hash = dashcore::BlockHash::from_byte_array(self.block_hash); | ||
| BlockInfo::new(self.height, block_hash, self.timestamp) | ||
| } | ||
| } | ||
|
|
||
| impl From<BlockInfo> for FFIBlockInfo { | ||
| fn from(info: BlockInfo) -> Self { | ||
| Self { | ||
| height: info.height(), | ||
| block_hash: info.block_hash().to_byte_array(), | ||
| timestamp: info.timestamp(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Convert an `FFIBlockInfo` and context type to a native `TransactionContext`. | ||
| pub(crate) fn transaction_context_from_ffi( | ||
| context_type: FFITransactionContext, | ||
| block_info: &FFIBlockInfo, | ||
| ) -> TransactionContext { | ||
| match context_type { | ||
| FFITransactionContext::Mempool => TransactionContext::Mempool, | ||
| FFITransactionContext::InstantSend => TransactionContext::InstantSend, | ||
| FFITransactionContext::InBlock => TransactionContext::InBlock(block_info.to_block_info()), | ||
| FFITransactionContext::InChainLockedBlock => { | ||
| TransactionContext::InChainLockedBlock(block_info.to_block_info()) | ||
| } | ||
| } | ||
|
Comment on lines
+48
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject the zero placeholder for confirmed contexts.
As per coding guidelines, Also applies to: 793-827 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| /// FFI Network type (single network) | ||
|
|
@@ -760,62 +793,37 @@ impl From<TransactionContext> for FFITransactionContext { | |
| pub struct FFITransactionContextDetails { | ||
| /// The context type | ||
| pub context_type: FFITransactionContext, | ||
| /// Block height (0 for mempool) | ||
| pub height: c_uint, | ||
| /// Block hash (32 bytes, null for mempool or if unknown) | ||
| pub block_hash: *const u8, | ||
| /// Timestamp (0 if unknown) | ||
| pub timestamp: c_uint, | ||
| /// Block info (zeroed for mempool/instant-send contexts) | ||
| pub block_info: FFIBlockInfo, | ||
| } | ||
|
|
||
| impl FFITransactionContextDetails { | ||
| /// Create a mempool context | ||
| pub fn mempool() -> Self { | ||
| FFITransactionContextDetails { | ||
| Self { | ||
| context_type: FFITransactionContext::Mempool, | ||
| height: 0, | ||
| block_hash: std::ptr::null(), | ||
| timestamp: 0, | ||
| block_info: FFIBlockInfo::empty(), | ||
| } | ||
| } | ||
|
|
||
| /// Create an in-block context | ||
| pub fn in_block(height: c_uint, block_hash: *const u8, timestamp: c_uint) -> Self { | ||
| FFITransactionContextDetails { | ||
| pub fn in_block(block_info: FFIBlockInfo) -> Self { | ||
| Self { | ||
| context_type: FFITransactionContext::InBlock, | ||
| height, | ||
| block_hash, | ||
| timestamp, | ||
| block_info, | ||
| } | ||
| } | ||
|
|
||
| /// Create a chain-locked block context | ||
| pub fn in_chain_locked_block(height: c_uint, block_hash: *const u8, timestamp: c_uint) -> Self { | ||
| FFITransactionContextDetails { | ||
| pub fn in_chain_locked_block(block_info: FFIBlockInfo) -> Self { | ||
| Self { | ||
| context_type: FFITransactionContext::InChainLockedBlock, | ||
| height, | ||
| block_hash, | ||
| timestamp, | ||
| block_info, | ||
| } | ||
| } | ||
|
|
||
| /// Convert to the native TransactionContext | ||
| /// Convert to the native `TransactionContext` | ||
| pub fn to_transaction_context(&self) -> TransactionContext { | ||
| match self.context_type { | ||
| FFITransactionContext::Mempool => TransactionContext::Mempool, | ||
| FFITransactionContext::InBlock => { | ||
| let info = unsafe { | ||
| block_info_from_ffi(self.height, self.block_hash, self.timestamp as u64) | ||
| }; | ||
| TransactionContext::InBlock(info) | ||
| } | ||
| FFITransactionContext::InChainLockedBlock => { | ||
| let info = unsafe { | ||
| block_info_from_ffi(self.height, self.block_hash, self.timestamp as u64) | ||
| }; | ||
| TransactionContext::InChainLockedBlock(info) | ||
| } | ||
| FFITransactionContext::InstantSend => TransactionContext::InstantSend, | ||
| } | ||
| transaction_context_from_ffi(self.context_type, &self.block_info) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add a direct test for
managed_core_account_get_transactionsblock export.This function now emits
FFIBlockInfo::empty()for mempool records and a populatedFFIBlockInfofor confirmed ones, but this file still does not assert either behavior. A small unit test here would lock down the new boundary behavior.As per coding guidelines, "Write unit tests for new functionality in Rust code".
🤖 Prompt for AI Agents