use blvm_consensus::*;
use blvm_consensus::transaction::check_tx_inputs;
use blvm_consensus::economic::get_block_subsidy;
use blvm_consensus::block::connect_block;
use blvm_consensus::economic::calculate_fee;
#[test]
fn test_input_value_overflow() {
let mut utxo_set = UtxoSet::default();
let large_value = i64::MAX / 2 + 1;
let outpoint1 = OutPoint { hash: [1; 32], index: 0 };
let utxo1 = UTXO {
value: large_value,
script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint1.clone(), std::sync::Arc::new(utxo1));
let outpoint2 = OutPoint { hash: [2; 32], index: 0 };
let utxo2 = UTXO {
value: large_value, script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint2.clone(), std::sync::Arc::new(utxo2));
let tx = Transaction {
version: 1,
inputs: vec![
TransactionInput {
prevout: outpoint1,
script_sig: vec![].into(),
sequence: 0xffffffff,
},
TransactionInput {
prevout: outpoint2,
script_sig: vec![],
sequence: 0xffffffff,
},
].into(),
outputs: vec![TransactionOutput {
value: 1000,
script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let result = check_tx_inputs(&tx, &utxo_set, 0);
assert!(result.is_err());
if let Err(ConsensusError::TransactionValidation(msg)) = result {
assert!(msg.contains("overflow"), "Error message should mention overflow");
} else {
panic!("Expected TransactionValidation error for overflow");
}
}
#[test]
fn test_output_value_overflow() {
let mut utxo_set = UtxoSet::default();
let outpoint = OutPoint { hash: [1; 32], index: 0 };
let utxo = UTXO {
value: 1000000000,
script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
let large_value = i64::MAX / 2 + 1;
let tx = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: outpoint,
script_sig: vec![].into(),
sequence: 0xffffffff,
}].into(),
outputs: vec![
TransactionOutput {
value: large_value,
script_pubkey: vec![].into(),
},
TransactionOutput {
value: large_value, script_pubkey: vec![].into(),
},
].into(),
lock_time: 0,
};
let result = check_tx_inputs(&tx, &utxo_set, 0);
assert!(result.is_err());
if let Err(ConsensusError::TransactionValidation(msg)) = result {
assert!(msg.contains("overflow"), "Error message should mention overflow");
} else {
panic!("Expected TransactionValidation error for overflow");
}
}
#[test]
fn test_output_exceeds_max_money() {
let mut utxo_set = UtxoSet::default();
let outpoint = OutPoint { hash: [1; 32], index: 0 };
let utxo = UTXO {
value: MAX_MONEY + 1, script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
let tx = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: outpoint,
script_sig: vec![].into(),
sequence: 0xffffffff,
}].into(),
outputs: vec![TransactionOutput {
value: MAX_MONEY + 1, script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let result = check_tx_inputs(&tx, &utxo_set, 0);
match result {
Ok((validation_result, _)) => {
assert!(matches!(validation_result, ValidationResult::Invalid(_)));
},
Err(_) => {
}
}
}
#[test]
fn test_fee_calculation_no_overflow() {
let mut utxo_set = UtxoSet::default();
let input_value = MAX_MONEY / 2;
let output_value = MAX_MONEY / 2 - 1000;
let outpoint = OutPoint { hash: [1; 32], index: 0 };
let utxo = UTXO {
value: input_value,
script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
let tx = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: outpoint,
script_sig: vec![].into(),
sequence: 0xffffffff,
}].into(),
outputs: vec![TransactionOutput {
value: output_value,
script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let result = check_tx_inputs(&tx, &utxo_set, 0);
assert!(result.is_ok());
let (validation_result, fee) = result.unwrap();
assert!(matches!(validation_result, ValidationResult::Valid));
assert_eq!(fee, input_value - output_value);
assert!(fee > 0);
}
#[test]
fn test_coinbase_value_overflow() {
let utxo_set = UtxoSet::default();
let subsidy = get_block_subsidy(0); let large_fee = i64::MAX - subsidy + 1;
let coinbase = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: OutPoint { hash: [0; 32].into(), index: 0xffffffff },
script_sig: vec![0x51],
sequence: 0xffffffff,
}].into(),
outputs: vec![TransactionOutput {
value: MAX_MONEY + 1, script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let block = Block {
header: BlockHeader {
version: 1,
prev_block_hash: [0; 32],
merkle_root: [0; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: vec![coinbase].into(),
};
let witnesses: Vec<segwit::Witness> = block.transactions.iter().map(|_| Vec::new()).collect();
let ctx = block::BlockValidationContext::for_network(crate::types::Network::Mainnet);
let result = connect_block(&block, &witnesses, utxo_set, 0, &ctx);
assert!(result.is_ok());
let (validation_result, _) = result.unwrap();
assert!(matches!(validation_result, ValidationResult::Invalid(_)));
}
#[test]
fn test_total_fees_overflow() {
let mut utxo_set = UtxoSet::default();
let outpoint = OutPoint { hash: [1; 32], index: 0 };
let utxo = UTXO {
value: MAX_MONEY / 2,
script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
let tx = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: outpoint,
script_sig: vec![].into(),
sequence: 0xffffffff,
}].into(),
outputs: vec![TransactionOutput {
value: MAX_MONEY / 2 - 1000,
script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let result = calculate_fee(&tx, &utxo_set);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 1000);
}
#[test]
fn test_max_valid_values() {
let mut utxo_set = UtxoSet::default();
let outpoint = OutPoint { hash: [1; 32], index: 0 };
let utxo = UTXO {
value: MAX_MONEY,
script_pubkey: vec![].into(),
height: 0,
};
utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
let tx = Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: outpoint,
script_sig: vec![].into(),
sequence: 0xffffffff,
}].into(),
outputs: vec![TransactionOutput {
value: MAX_MONEY, script_pubkey: vec![].into(),
}].into(),
lock_time: 0,
};
let result = check_tx_inputs(&tx, &utxo_set, 0);
assert!(result.is_ok());
let (validation_result, fee) = result.unwrap();
assert!(matches!(validation_result, ValidationResult::Valid));
assert_eq!(fee, 0); }