From 38433e95f12d07841868728fe2e753542843131e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 10 Jun 2024 14:56:44 +0300 Subject: [PATCH] ledger: Add new macros to manipulate struct fields. --- src/client/rpc_api.rs | 20 +++++++++++++ src/ledger/mod.rs | 60 ++++++++++++++++++++++++++++---------- src/ledger/transactions.rs | 26 ++++++++++++----- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/client/rpc_api.rs b/src/client/rpc_api.rs index 762284b..ad17ef0 100644 --- a/src/client/rpc_api.rs +++ b/src/client/rpc_api.rs @@ -344,6 +344,7 @@ mod tests { } #[test] + #[ignore = "not implemented"] fn generate_to_address() { let rpc = Client::new("", bitcoincore_rpc::Auth::None).unwrap(); @@ -364,8 +365,27 @@ mod tests { assert!(false); }; + // Generating blocks should add funds to wallet. rpc.generate_to_address(101, &address).unwrap(); + // Wallet has funds now. It should not be rejected. + // let txin = TxIn { + // previous_output: OutPoint { + // txid: rpc.ledger.get_utxos()[0], + // vout: 0, + // }, + // ..Default::default() + // }; + let txout = TxOut { + value: Amount::from_sat(1), + script_pubkey: address.script_pubkey(), + }; + let tx = Transaction { + version: bitcoin::transaction::Version(2), + lock_time: absolute::LockTime::from_consensus(0), + input: vec![], + output: vec![txout], + }; if let Err(_) = rpc.database.lock().unwrap().verify_transaction(&tx) { assert!(false); }; diff --git a/src/ledger/mod.rs b/src/ledger/mod.rs index 809f7d1..1a7050a 100644 --- a/src/ledger/mod.rs +++ b/src/ledger/mod.rs @@ -5,49 +5,77 @@ //! This crate is designed to be used as immutable, because of the `RpcApi`'s //! immutable nature. -use bitcoin::{Address, TxOut}; -use std::cell::Cell; +use bitcoin::{Address, Transaction, TxOut}; +use bitcoin_simulator::database::Database; +use std::{ + cell::Cell, + sync::{Arc, Mutex}, +}; mod transactions; +/// Adds a new item to a `Vec` member, guarded by a `Cell`. +#[macro_export] +macro_rules! add_item { + ($member:expr, $item:expr) => { + // Update item list. + let mut items = $member.take(); + items.push($item); + + // Commit new change. + $member.set(items); + }; +} +/// Returns item `Vec` of a member, guarded by a `Cell`. +#[macro_export] +macro_rules! get_item { + ($member:expr) => { + let items = $member.take(); + $member.set(items.clone()); + + return items; + }; +} + /// Mock Bitcoin ledger. -#[derive(Default)] pub struct Ledger { + /// Private database interface. Data will be written to this temporary + /// database. Note: It is wrapped around an `Arc>`. This will help + /// to use this mock in an asynchronous environment, like `async` or threads. + database: Arc>, /// User's addresses. addresses: Cell>, /// User's unspent transaction outputs. utxos: Cell>, + /// User's transactions. + transactions: Cell>, } impl Ledger { /// Creates a new empty ledger. pub fn new() -> Self { Self { - ..Default::default() + database: Arc::new(Mutex::new(Database::connect_temporary_database().unwrap())), + addresses: Cell::new(Vec::new()), + utxos: Cell::new(Vec::new()), + transactions: Cell::new(Vec::new()), } } - /// Adds a new address for user. + /// Adds a new address for the user. pub fn add_address(&self, address: Address) { - let mut addresses = self.addresses.take(); - addresses.push(address); - - self.addresses.set(addresses); + add_item!(self.addresses, address); } - /// Returns address of the user. + /// Returns addresses of the user. pub fn get_addresses(&self) -> Vec
{ - let addresses = self.addresses.take(); - self.addresses.set(addresses.clone()); - - addresses + get_item!(self.addresses); } } #[cfg(test)] mod tests { - use crate::test_common; - use super::*; + use crate::test_common; #[test] fn new() { diff --git a/src/ledger/transactions.rs b/src/ledger/transactions.rs index c0fcc1b..783ee1a 100644 --- a/src/ledger/transactions.rs +++ b/src/ledger/transactions.rs @@ -1,22 +1,32 @@ //! # Transaction Related Ledger Operations use super::Ledger; -use bitcoin::TxOut; +use crate::{add_item, get_item}; +use bitcoin::{Transaction, TxOut}; impl Ledger { /// Adds a new UTXO to user's UTXO's. pub fn add_utxo(&self, utxo: TxOut) { - let mut utxos = self.utxos.take(); - utxos.push(utxo); - - self.utxos.set(utxos); + add_item!(self.utxos, utxo); } /// Returns UTXO's of the user. pub fn get_utxos(&self) -> Vec { - let utxos = self.utxos.take(); - self.utxos.set(utxos.clone()); + get_item!(self.utxos); + } - utxos + /// Adds transaction to current block, without checking anything. + pub fn add_transaction_unconditionally(&self, transaction: Transaction) { + self.database + .lock() + .unwrap() + .insert_transaction_unconditionally(&transaction) + .unwrap(); + + add_item!(self.transactions, transaction); + } + /// Returns user's list of transactions. + pub fn get_transactions(&self) -> Vec { + get_item!(self.transactions); } }