forked from tari-project/tari-dan
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: utility to create and read batch transactions
- Loading branch information
Showing
10 changed files
with
266 additions
and
22 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Exclude deps from workspace | ||
[workspace] | ||
|
||
[package] | ||
name = "transaction_generator" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
tari_template_lib = { path = "../../dan_layer/template_lib" } | ||
tari_transaction = { path = "../../dan_layer/transaction" } | ||
tari_engine_types = { path = "../../dan_layer/engine_types" } | ||
tari_template_builtin = { path = "../../dan_layer/template_builtin" } | ||
tari_crypto = "0.17" | ||
|
||
anyhow = "1.0.72" | ||
bincode = { version = "2.0.0-rc.3", features = ["serde"] } | ||
bytes = "0.4" | ||
clap = { version = "4.3.21", features = ["derive"] } | ||
rayon = "1.7.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright 2023 The Tari Project | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
use std::path::PathBuf; | ||
|
||
use clap::{Args, Parser, Subcommand}; | ||
|
||
#[derive(Parser, Debug)] | ||
#[clap(author, version, about, long_about = None)] | ||
#[clap(propagate_version = true)] | ||
pub struct Cli { | ||
#[clap(subcommand)] | ||
pub sub_command: SubCommand, | ||
} | ||
|
||
impl Cli { | ||
pub fn init() -> Self { | ||
Self::parse() | ||
} | ||
} | ||
|
||
#[derive(Subcommand, Debug)] | ||
pub enum SubCommand { | ||
Write(WriteArgs), | ||
Read(ReadArgs), | ||
} | ||
|
||
#[derive(Args, Debug)] | ||
pub struct WriteArgs { | ||
#[clap(long, short = 'n')] | ||
pub num_transactions: u64, | ||
#[clap(long, short = 'o')] | ||
pub output_file: PathBuf, | ||
#[clap(long)] | ||
pub overwrite: bool, | ||
} | ||
#[derive(Args, Debug)] | ||
pub struct ReadArgs { | ||
#[clap(long, short = 'f')] | ||
pub input_file: PathBuf, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Copyright 2023 The Tari Project | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
mod transaction_reader; | ||
mod transaction_writer; | ||
|
||
pub use transaction_reader::*; | ||
pub use transaction_writer::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2023 The Tari Project | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
mod cli; | ||
mod transaction_writer; | ||
|
||
use std::io::{stdout, Seek, SeekFrom, Write}; | ||
|
||
use cli::Cli; | ||
use tari_crypto::ristretto::RistrettoSecretKey; | ||
use tari_template_lib::models::Amount; | ||
use transaction_generator::{read_number_of_transactions, read_transactions}; | ||
|
||
use crate::{cli::SubCommand, transaction_writer::write_transactions}; | ||
|
||
fn main() -> anyhow::Result<()> { | ||
let cli = Cli::init(); | ||
match cli.sub_command { | ||
SubCommand::Write(args) => { | ||
let fee_amount = Amount(1000); | ||
let signer_private_key = RistrettoSecretKey::default(); | ||
|
||
if !args.overwrite && args.output_file.exists() { | ||
anyhow::bail!("Output file {} already exists", args.output_file.display()); | ||
} | ||
|
||
let timer = std::time::Instant::now(); | ||
println!("Generating and writing {} transactions", args.num_transactions,); | ||
|
||
let mut file = std::fs::File::create(&args.output_file)?; | ||
write_transactions( | ||
args.num_transactions, | ||
signer_private_key, | ||
fee_amount, | ||
&|_| { | ||
print!("."); | ||
stdout().flush().unwrap() | ||
}, | ||
&mut file, | ||
)?; | ||
println!(); | ||
let size = file.metadata()?.len() / 1024 / 1024; | ||
println!( | ||
"Wrote {} transactions to {} ({} MiB) in {:.2?}", | ||
args.num_transactions, | ||
args.output_file.display(), | ||
size, | ||
timer.elapsed() | ||
); | ||
}, | ||
SubCommand::Read(args) => { | ||
let mut file = std::fs::File::open(args.input_file)?; | ||
|
||
let num_transactions = read_number_of_transactions(&mut file)?; | ||
println!("Number of transactions: {}", num_transactions); | ||
file.seek(SeekFrom::Start(0))?; | ||
let receiver = read_transactions(file)?; | ||
|
||
while let Ok(transaction) = receiver.recv() { | ||
println!("Read transaction: {}", transaction.id()); | ||
} | ||
}, | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2023 The Tari Project | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
use std::{io::Read, sync::mpsc, thread}; | ||
|
||
use tari_transaction::Transaction; | ||
|
||
pub fn read_transactions<R: Read + Send + 'static>(mut reader: R) -> anyhow::Result<mpsc::Receiver<Transaction>> { | ||
let (sender, receiver) = mpsc::sync_channel(1000); | ||
thread::spawn(move || { | ||
let mut remaining = read_number_of_transactions(&mut reader).unwrap(); | ||
|
||
while remaining > 0 { | ||
let mut len_bytes = [0u8; 4]; | ||
reader.read_exact(&mut len_bytes).unwrap(); | ||
let len = u32::from_le_bytes(len_bytes) as u64; | ||
let mut limited_reader = (&mut reader).take(len); | ||
let transaction: Transaction = | ||
bincode::serde::decode_from_std_read(&mut limited_reader, bincode::config::standard()).unwrap(); | ||
sender.send(transaction).unwrap(); | ||
remaining -= 1; | ||
} | ||
}); | ||
Ok(receiver) | ||
} | ||
|
||
pub fn read_number_of_transactions<R: Read>(reader: &mut R) -> anyhow::Result<u64> { | ||
let mut len_bytes = [0u8; 8]; | ||
reader.read_exact(&mut len_bytes).unwrap(); | ||
Ok(u64::from_le_bytes(len_bytes)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// Copyright 2023 The Tari Project | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
use std::{io::Write, sync::mpsc, thread}; | ||
|
||
use bytes::{BufMut, Bytes, BytesMut}; | ||
use rayon::iter::{ParallelBridge, ParallelIterator}; | ||
use tari_crypto::ristretto::RistrettoSecretKey; | ||
use tari_engine_types::{component::new_component_address_from_parts, instruction::Instruction}; | ||
use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS; | ||
use tari_template_lib::{ | ||
args, | ||
models::{Amount, NonFungibleAddress}, | ||
}; | ||
use tari_transaction::Transaction; | ||
|
||
pub fn write_transactions<W: Write>( | ||
num_transactions: u64, | ||
signer_private_key: RistrettoSecretKey, | ||
fee_amount: Amount, | ||
on_progress: &dyn Fn(usize), | ||
writer: &mut W, | ||
) -> anyhow::Result<()> { | ||
let (sender, receiver) = mpsc::sync_channel(1000); | ||
|
||
thread::spawn(move || { | ||
(0..num_transactions).par_bridge().for_each_with(sender, |sender, n| { | ||
let mut owner_pk = [0u8; 32]; | ||
owner_pk[24..].copy_from_slice(&n.to_le_bytes()); | ||
let owner_token = NonFungibleAddress::from_public_key(owner_pk.into()); | ||
|
||
let transaction = Transaction::builder() | ||
.with_fee_instructions(vec![ | ||
Instruction::CreateFreeTestCoins { | ||
revealed_amount: Amount::new(1000), | ||
output: None, | ||
}, | ||
Instruction::PutLastInstructionOutputOnWorkspace { | ||
key: b"free_coins".to_vec(), | ||
}, | ||
Instruction::CallFunction { | ||
template_address: *ACCOUNT_TEMPLATE_ADDRESS, | ||
function: "create_with_bucket".to_string(), | ||
args: args![owner_token, Workspace("free_coins")], | ||
}, | ||
Instruction::CallMethod { | ||
component_address: new_component_address_from_parts( | ||
&ACCOUNT_TEMPLATE_ADDRESS, | ||
&owner_pk.into(), | ||
), | ||
method: "pay_fee".to_string(), | ||
args: args![fee_amount], | ||
}, | ||
]) | ||
.sign(&signer_private_key) | ||
.build(); | ||
|
||
let buf = bincode::serde::encode_to_vec(&transaction, bincode::config::standard()).unwrap(); | ||
let buf = Bytes::from(buf); | ||
let output = BytesMut::with_capacity(buf.len() + 4); | ||
let len = (u32::try_from(buf.len()).unwrap()).to_le_bytes(); | ||
let mut writer = output.writer(); | ||
writer.write_all(&len).unwrap(); | ||
writer.write_all(&buf).unwrap(); | ||
sender.send(writer.into_inner().freeze()).unwrap(); | ||
}); | ||
}); | ||
|
||
let len_bytes = num_transactions.to_le_bytes(); | ||
bincode::serde::encode_into_std_write(len_bytes, writer, bincode::config::standard()).unwrap(); | ||
let mut count = 0; | ||
while let Ok(buf) = receiver.recv() { | ||
writer.write_all(&buf)?; | ||
count += 1; | ||
if count % 10000 == 0 { | ||
on_progress(count); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |