Make tx weight safer (#2180)

Currently it fails on fuzz tests. Also type conversion to i32 is
dangerous per se
This commit is contained in:
hashmap 2018-12-18 20:19:19 +01:00 committed by Ignotus Peverell
parent 590ea33484
commit 0d44c5405f

View file

@ -365,8 +365,7 @@ impl Readable for TransactionBody {
// quick block weight check before proceeding
let tx_block_weight =
TransactionBody::weight(input_len as usize, output_len as usize, kernel_len as usize)
as usize;
TransactionBody::weight(input_len as usize, output_len as usize, kernel_len as usize);
if tx_block_weight > consensus::MAX_BLOCK_WEIGHT {
return Err(ser::Error::TooLargeReadErr);
@ -500,29 +499,33 @@ impl TransactionBody {
}
/// Calculate transaction weight
pub fn body_weight(&self) -> u32 {
pub fn body_weight(&self) -> usize {
TransactionBody::weight(self.inputs.len(), self.outputs.len(), self.kernels.len())
}
/// Calculate weight of transaction using block weighing
pub fn body_weight_as_block(&self) -> u32 {
pub fn body_weight_as_block(&self) -> usize {
TransactionBody::weight_as_block(self.inputs.len(), self.outputs.len(), self.kernels.len())
}
/// Calculate transaction weight from transaction details. This is non
/// consensus critical and compared to block weight, incentivizes spending
/// more outputs (to lower the fee).
pub fn weight(input_len: usize, output_len: usize, kernel_len: usize) -> u32 {
let body_weight = -(input_len as i32) + (4 * output_len as i32) + kernel_len as i32;
max(body_weight, 1) as u32
pub fn weight(input_len: usize, output_len: usize, kernel_len: usize) -> usize {
let body_weight = output_len
.saturating_mul(4)
.saturating_add(kernel_len)
.saturating_sub(input_len);
max(body_weight, 1)
}
/// Calculate transaction weight using block weighing from transaction
/// details. Consensus critical and uses consensus weight values.
pub fn weight_as_block(input_len: usize, output_len: usize, kernel_len: usize) -> u32 {
(input_len * consensus::BLOCK_INPUT_WEIGHT
+ output_len * consensus::BLOCK_OUTPUT_WEIGHT
+ kernel_len * consensus::BLOCK_KERNEL_WEIGHT) as u32
pub fn weight_as_block(input_len: usize, output_len: usize, kernel_len: usize) -> usize {
input_len
.saturating_mul(consensus::BLOCK_INPUT_WEIGHT)
.saturating_add(output_len.saturating_mul(consensus::BLOCK_OUTPUT_WEIGHT))
.saturating_add(kernel_len.saturating_mul(consensus::BLOCK_KERNEL_WEIGHT))
}
/// Lock height of a body is the max lock height of the kernels.
@ -543,7 +546,7 @@ impl TransactionBody {
self.inputs.len(),
self.outputs.len() + reserve,
self.kernels.len() + reserve,
) as usize;
);
if tx_block_weight > consensus::MAX_BLOCK_WEIGHT {
return Err(Error::TooHeavy);
@ -863,17 +866,17 @@ impl Transaction {
}
/// Calculate transaction weight
pub fn tx_weight(&self) -> u32 {
pub fn tx_weight(&self) -> usize {
self.body.body_weight()
}
/// Calculate transaction weight as a block
pub fn tx_weight_as_block(&self) -> u32 {
pub fn tx_weight_as_block(&self) -> usize {
self.body.body_weight_as_block()
}
/// Calculate transaction weight from transaction details
pub fn weight(input_len: usize, output_len: usize, kernel_len: usize) -> u32 {
pub fn weight(input_len: usize, output_len: usize, kernel_len: usize) -> usize {
TransactionBody::weight(input_len, output_len, kernel_len)
}
}