Skip to content

Commit

Permalink
feat: utility to create and read batch transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Aug 18, 2023
1 parent 58d350a commit 1917b9c
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 22 deletions.
23 changes: 11 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ members = [
"dan_layer/validator_node_rpc",
"dan_layer/wallet/sdk",
"dan_layer/wallet/storage_sqlite",
"integration_tests"
"integration_tests",
]
#
resolver = "2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use std::{
};

use chrono::Utc;
use lazy_static::lazy_static;
use log::*;
use tari_core::transactions::transaction_components::TemplateType;
use tari_dan_common_types::{optional::Optional, services::template_provider::TemplateProvider};
Expand All @@ -40,7 +39,7 @@ use tari_dan_engine::{
use tari_dan_storage::global::{DbTemplate, DbTemplateType, DbTemplateUpdate, GlobalDb, TemplateStatus};
use tari_dan_storage_sqlite::global::SqliteGlobalDbAdapter;
use tari_engine_types::calculate_template_binary_hash;
use tari_template_builtin::get_template_builtin;
use tari_template_builtin::{get_template_builtin, ACCOUNT_NFT_TEMPLATE_ADDRESS, ACCOUNT_TEMPLATE_ADDRESS};
use tari_template_lib::models::TemplateAddress;

use super::TemplateConfig;
Expand All @@ -54,13 +53,6 @@ use crate::template_manager::interface::{

const LOG_TARGET: &str = "tari::validator_node::template_manager";

lazy_static! {
pub static ref ACCOUNT_TEMPLATE_ADDRESS: TemplateAddress = TemplateAddress::from_array([0; 32]);
pub static ref ACCOUNT_NFT_TEMPLATE_ADDRESS: TemplateAddress = TemplateAddress::from_array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
]);
}

#[derive(Debug, Clone)]
pub struct TemplateManager {
global_db: GlobalDb<SqliteGlobalDbAdapter>,
Expand Down
6 changes: 6 additions & 0 deletions dan_layer/template_lib/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ impl AsRef<[u8]> for RistrettoPublicKeyBytes {
}
}

impl From<[u8; 32]> for RistrettoPublicKeyBytes {
fn from(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}

#[derive(Debug, PartialEq, Eq)]
pub struct InvalidByteLengthError {
size: usize,
Expand Down
20 changes: 20 additions & 0 deletions utilities/transaction_generator/Cargo.toml
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"
41 changes: 41 additions & 0 deletions utilities/transaction_generator/src/cli.rs
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,
}
8 changes: 8 additions & 0 deletions utilities/transaction_generator/src/lib.rs
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::*;
66 changes: 66 additions & 0 deletions utilities/transaction_generator/src/main.rs
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(())
}
31 changes: 31 additions & 0 deletions utilities/transaction_generator/src/transaction_reader.rs
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))
}
81 changes: 81 additions & 0 deletions utilities/transaction_generator/src/transaction_writer.rs
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(())
}

0 comments on commit 1917b9c

Please sign in to comment.