mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
Merge pull request #1336 from antiochp/validate_block_size
Validate block size
This commit is contained in:
commit
b10609bbb1
2 changed files with 52 additions and 13 deletions
|
@ -90,11 +90,20 @@ pub const MAX_BLOCK_WEIGHT: usize = 80_000;
|
|||
|
||||
/// Reused consistently for various max lengths below.
|
||||
/// Max transaction is effectively a full block of data.
|
||||
/// Soft fork down when too high.
|
||||
/// Likely we will need to tweak these all individually, but using a single constant for now.
|
||||
const MAX_INP_OUT_KERN_LEN: usize = 300_000;
|
||||
|
||||
/// Maximum inputs for a block (issue#261)
|
||||
/// Hundreds of inputs + 1 output might be slow to validate (issue#258)
|
||||
pub const MAX_BLOCK_INPUTS: usize = MAX_INP_OUT_KERN_LEN; // soft fork down when too_high
|
||||
/// Maximum inputs for a block.
|
||||
pub const MAX_BLOCK_INPUTS: usize = MAX_INP_OUT_KERN_LEN;
|
||||
|
||||
/// Maximum outputs for a block (max tx + single output for coinbase).
|
||||
/// This is just a starting point - need to discuss this further.
|
||||
pub const MAX_BLOCK_OUTPUTS: usize = MAX_INP_OUT_KERN_LEN + 1;
|
||||
|
||||
/// Maximum kernels for a block (max tx + single output for coinbase).
|
||||
/// This is just a starting point - need to discuss this further.
|
||||
pub const MAX_BLOCK_KERNELS: usize = MAX_INP_OUT_KERN_LEN + 1;
|
||||
|
||||
/// Maximum inputs in a transaction.
|
||||
pub const MAX_TX_INPUTS: usize = MAX_INP_OUT_KERN_LEN;
|
||||
|
@ -105,13 +114,6 @@ pub const MAX_TX_OUTPUTS: usize = MAX_INP_OUT_KERN_LEN;
|
|||
/// Maximum kernels in a transaction.
|
||||
pub const MAX_TX_KERNELS: usize = MAX_INP_OUT_KERN_LEN;
|
||||
|
||||
/// Whether a block exceeds the maximum acceptable weight
|
||||
pub fn exceeds_weight(input_len: usize, output_len: usize, kernel_len: usize) -> bool {
|
||||
input_len * BLOCK_INPUT_WEIGHT
|
||||
+ output_len * BLOCK_OUTPUT_WEIGHT
|
||||
+ kernel_len * BLOCK_KERNEL_WEIGHT > MAX_BLOCK_WEIGHT || input_len > MAX_BLOCK_INPUTS
|
||||
}
|
||||
|
||||
/// Fork every 250,000 blocks for first 2 years, simple number and just a
|
||||
/// little less than 6 months.
|
||||
pub const HARD_FORK_INTERVAL: u64 = 250_000;
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::collections::HashSet;
|
|||
use std::fmt;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use consensus::{self, exceeds_weight, reward, VerifySortOrder, REWARD};
|
||||
use consensus::{self, reward, VerifySortOrder, REWARD};
|
||||
use core::committed::{self, Committed};
|
||||
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
|
||||
use core::id::ShortIdentifiable;
|
||||
|
@ -45,7 +45,13 @@ pub enum Error {
|
|||
InvalidTotalKernelSum,
|
||||
/// Same as above but for the coinbase part of a block, including reward
|
||||
CoinbaseSumMismatch,
|
||||
/// Too many inputs, outputs or kernels in the block
|
||||
/// Restrict number of block inputs.
|
||||
TooManyInputs,
|
||||
/// Restrict number of block outputs.
|
||||
TooManyOutputs,
|
||||
/// Retrict number of block kernels.
|
||||
TooManyKernels,
|
||||
/// Block weight (based on inputs|outputs|kernels) exceeded.
|
||||
WeightExceeded,
|
||||
/// Kernel not valid due to lock_height exceeding block header height
|
||||
KernelLockHeight(u64),
|
||||
|
@ -399,6 +405,13 @@ impl Readable for Block {
|
|||
let outputs = read_and_verify_sorted(reader, output_len)?;
|
||||
let kernels = read_and_verify_sorted(reader, kernel_len)?;
|
||||
|
||||
// TODO - we do not verify the input|output|kernel counts here.
|
||||
// I think should call block.validate() as part of a call to read()
|
||||
// but block.validate() as it stands currently requires the previous sums etc.
|
||||
// So there is no easy way to do this in isolation.
|
||||
// Maybe we need two variations of validate() where one handles the validation
|
||||
// rules that *can* be done in isolation.
|
||||
|
||||
Ok(Block {
|
||||
header: header,
|
||||
inputs: inputs,
|
||||
|
@ -694,7 +707,11 @@ impl Block {
|
|||
prev_kernel_offset: &BlindingFactor,
|
||||
prev_kernel_sum: &Commitment,
|
||||
) -> Result<(Commitment), Error> {
|
||||
// Verify we do not exceed the max number of inputs|outputs|kernels
|
||||
// and that the "weight" based on these does not exceed the max permitted weight.
|
||||
self.verify_size()?;
|
||||
self.verify_weight()?;
|
||||
|
||||
self.verify_sorted()?;
|
||||
self.verify_cut_through()?;
|
||||
self.verify_coinbase()?;
|
||||
|
@ -727,8 +744,28 @@ impl Block {
|
|||
Ok(kernel_sum)
|
||||
}
|
||||
|
||||
// Verify the tx is not too big in terms of
|
||||
// number of inputs|outputs|kernels.
|
||||
fn verify_size(&self) -> Result<(), Error> {
|
||||
if self.inputs.len() > consensus::MAX_BLOCK_INPUTS {
|
||||
return Err(Error::TooManyInputs);
|
||||
}
|
||||
if self.outputs.len() > consensus::MAX_BLOCK_OUTPUTS {
|
||||
return Err(Error::TooManyOutputs);
|
||||
}
|
||||
if self.kernels.len() > consensus::MAX_BLOCK_KERNELS {
|
||||
return Err(Error::TooManyKernels);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_weight(&self) -> Result<(), Error> {
|
||||
if exceeds_weight(self.inputs.len(), self.outputs.len(), self.kernels.len()) {
|
||||
let weight =
|
||||
self.inputs.len() * consensus::BLOCK_INPUT_WEIGHT +
|
||||
self.outputs.len() * consensus::BLOCK_OUTPUT_WEIGHT +
|
||||
self.kernels.len() * consensus::BLOCK_KERNEL_WEIGHT;
|
||||
|
||||
if weight > consensus::MAX_BLOCK_WEIGHT {
|
||||
return Err(Error::WeightExceeded);
|
||||
}
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue