mod command_iter;
use cylinder::Signer;
use crate::error::InvalidStateError;
use crate::protocol::{
batch::{BatchBuilder, BatchPair},
command::{Command, CommandPayload},
sabre::ExecuteContractActionBuilder,
transaction::TransactionPair,
};
use crate::protos::IntoBytes;
use crate::workload::{BatchWorkload, ExpectedBatchResult, TransactionWorkload};
#[cfg(feature = "family-command-transaction-builder")]
use super::transaction_builder::CommandTransactionBuilder as CmdTransactionBuilder;
pub use crate::families::command::workload::command_iter::CommandGeneratingIter;
pub struct CommandTransactionWorkload {
generator: CommandGeneratingIter,
signer: Box<dyn Signer>,
}
impl CommandTransactionWorkload {
pub fn new(generator: CommandGeneratingIter, signer: Box<dyn Signer>) -> Self {
Self { generator, signer }
}
}
impl TransactionWorkload for CommandTransactionWorkload {
fn next_transaction(
&mut self,
) -> Result<(TransactionPair, Option<ExpectedBatchResult>), InvalidStateError> {
let (command, address) = self
.generator
.next()
.ok_or_else(|| InvalidStateError::with_message("No command available".to_string()))?;
let command_payload = CommandPayload::new(vec![command.clone()]);
let payload_bytes = command_payload
.into_bytes()
.expect("Unable to get bytes from Command Payload");
let expected_batch_result = match &command {
Command::ReturnInvalid(_) => Some(ExpectedBatchResult::Invalid),
_ => Some(ExpectedBatchResult::Valid),
};
let addresses = match command {
Command::SetState(set_state) => set_state
.state_writes()
.iter()
.map(|b| String::from(b.key()))
.collect::<Vec<String>>(),
Command::DeleteState(delete_state) => delete_state.state_keys().to_vec(),
Command::GetState(get_state) => get_state.state_keys().to_vec(),
_ => vec![address],
};
let txn = ExecuteContractActionBuilder::new()
.with_name(String::from("command"))
.with_version(String::from("1.0"))
.with_inputs(addresses.clone())
.with_outputs(addresses)
.with_payload(payload_bytes)
.into_payload_builder()
.map_err(|err| {
InvalidStateError::with_message(format!(
"Unable to convert execute action into sabre payload: {}",
err
))
})?
.into_transaction_builder()
.map_err(|err| {
InvalidStateError::with_message(format!(
"Unable to convert execute payload into transaction: {}",
err
))
})?
.build_pair(&*self.signer)
.map_err(|err| {
InvalidStateError::with_message(format!(
"Failed to build transaction pair: {}",
err
))
})?;
Ok((txn, expected_batch_result))
}
}
pub struct CommandBatchWorkload {
transaction_workload: CommandTransactionWorkload,
signer: Box<dyn Signer>,
}
impl CommandBatchWorkload {
pub fn new(transaction_workload: CommandTransactionWorkload, signer: Box<dyn Signer>) -> Self {
Self {
transaction_workload,
signer,
}
}
}
impl BatchWorkload for CommandBatchWorkload {
fn next_batch(
&mut self,
) -> Result<(BatchPair, Option<ExpectedBatchResult>), InvalidStateError> {
let (txn, result) = self.transaction_workload.next_transaction()?;
Ok((
BatchBuilder::new()
.with_transactions(vec![txn.take().0])
.build_pair(&*self.signer)
.map_err(|err| {
InvalidStateError::with_message(format!("Failed to build batch pair: {}", err))
})?,
result,
))
}
}
#[cfg(feature = "family-command-transaction-builder")]
#[deprecated(
since = "0.4.1",
note = "Please use families::command::CommandTransactionBuilder"
)]
pub type CommandTransactionBuilder = CmdTransactionBuilder;