use bee_block::{
address::{Address, Ed25519Address},
input::{Input, TreasuryInput, UtxoInput},
output::{unlock_condition::AddressUnlockCondition, BasicOutput, Output, TreasuryOutput},
payload::{
milestone::MilestoneId,
transaction::{RegularTransactionEssence, TransactionId},
Payload,
},
protocol::protocol_parameters,
rand::{
bytes::rand_bytes_array,
output::rand_inputs_commitment,
payload::{rand_tagged_data_payload, rand_treasury_transaction_payload},
},
Error,
};
use packable::bounded::TryIntoBoundedU16Error;
const TRANSACTION_ID: &str = "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649";
const ED25519_ADDRESS_1: &str = "0xd56da1eb7726ed482dfe9d457cf548c2ae2a6ce3e053dbf82f11223be476adb9";
const ED25519_ADDRESS_2: &str = "0xefda4275375ac3675abff85235fd25a1522a2044cc6027a31b310857246f18c0";
#[test]
fn kind() {
assert_eq!(RegularTransactionEssence::KIND, 1);
}
#[test]
fn build_valid() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input1, input2])
.add_output(output)
.finish(&protocol_parameters);
assert!(essence.is_ok());
}
#[test]
fn build_valid_with_payload() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let payload = Payload::from(rand_tagged_data_payload());
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input1, input2])
.add_output(output)
.with_payload(payload)
.finish(&protocol_parameters);
assert!(essence.is_ok());
}
#[test]
fn build_valid_add_inputs_outputs() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input1, input2])
.add_output(output)
.finish(&protocol_parameters);
assert!(essence.is_ok());
}
#[test]
fn build_invalid_payload_kind() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let payload = rand_treasury_transaction_payload(protocol_parameters.token_supply());
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input1, input2])
.add_output(output)
.with_payload(payload.into())
.finish(&protocol_parameters);
assert!(matches!(essence, Err(Error::InvalidPayloadKind(4))));
}
#[test]
fn build_invalid_input_count_low() {
let protocol_parameters = protocol_parameters();
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_output(output)
.finish(&protocol_parameters);
assert!(matches!(
essence,
Err(Error::InvalidInputCount(TryIntoBoundedU16Error::Invalid(0)))
));
}
#[test]
fn build_invalid_input_count_high() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input; 129])
.add_output(output)
.finish(&protocol_parameters);
assert!(matches!(
essence,
Err(Error::InvalidInputCount(TryIntoBoundedU16Error::Invalid(129)))
));
}
#[test]
fn build_invalid_output_count_low() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_input(input)
.finish(&protocol_parameters);
assert!(matches!(
essence,
Err(Error::InvalidOutputCount(TryIntoBoundedU16Error::Invalid(0)))
));
}
#[test]
fn build_invalid_output_count_high() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_input(input)
.with_outputs(vec![output; 129])
.finish(&protocol_parameters);
assert!(matches!(
essence,
Err(Error::InvalidOutputCount(TryIntoBoundedU16Error::Invalid(129)))
));
}
#[test]
fn build_invalid_duplicate_utxo() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input; 2])
.add_output(output)
.finish(&protocol_parameters);
assert!(matches!(essence, Err(Error::DuplicateUtxo(_))));
}
#[test]
fn build_invalid_input_kind() {
let protocol_parameters = protocol_parameters();
let input = Input::Treasury(TreasuryInput::new(MilestoneId::new(rand_bytes_array())));
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let output = Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_input(input)
.add_output(output)
.finish(&protocol_parameters);
assert!(matches!(essence, Err(Error::InvalidInputKind(1))));
}
#[test]
fn build_invalid_output_kind() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let amount = 1_000_000;
let output = Output::Treasury(TreasuryOutput::new(amount, protocol_parameters.token_supply()).unwrap());
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_input(input)
.add_output(output)
.finish(&protocol_parameters);
assert!(matches!(essence, Err(Error::InvalidOutputKind(2))));
}
#[test]
fn build_invalid_accumulated_output() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let bytes1: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address1 = Address::from(Ed25519Address::new(bytes1));
let amount1 = protocol_parameters.token_supply() - 1_000_000;
let output1 = Output::Basic(
BasicOutput::build_with_amount(amount1)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address1).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let bytes2: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_2).unwrap();
let address2 = Address::from(Ed25519Address::new(bytes2));
let amount2 = 2_000_000;
let output2 = Output::Basic(
BasicOutput::build_with_amount(amount2)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address2).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
);
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.add_input(input)
.with_outputs(vec![output1, output2])
.finish(&protocol_parameters);
assert!(matches!(essence, Err(Error::InvalidTransactionAmountSum(_))));
}
#[test]
fn getters() {
let protocol_parameters = protocol_parameters();
let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap());
let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0).unwrap());
let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1).unwrap());
let bytes: [u8; 32] = prefix_hex::decode(ED25519_ADDRESS_1).unwrap();
let address = Address::from(Ed25519Address::new(bytes));
let amount = 1_000_000;
let outputs = vec![Output::Basic(
BasicOutput::build_with_amount(amount)
.unwrap()
.add_unlock_condition(AddressUnlockCondition::new(address).into())
.finish(protocol_parameters.token_supply())
.unwrap(),
)];
let payload = Payload::from(rand_tagged_data_payload());
let essence = RegularTransactionEssence::builder(rand_inputs_commitment())
.with_inputs(vec![input1, input2])
.with_outputs(outputs.clone())
.with_payload(payload.clone())
.finish(&protocol_parameters)
.unwrap();
assert_eq!(essence.outputs(), outputs.as_slice());
assert_eq!(essence.payload().unwrap(), &payload);
}