mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31: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.
|
/// Reused consistently for various max lengths below.
|
||||||
/// Max transaction is effectively a full block of data.
|
/// 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;
|
const MAX_INP_OUT_KERN_LEN: usize = 300_000;
|
||||||
|
|
||||||
/// Maximum inputs for a block (issue#261)
|
/// Maximum inputs for a block.
|
||||||
/// Hundreds of inputs + 1 output might be slow to validate (issue#258)
|
pub const MAX_BLOCK_INPUTS: usize = MAX_INP_OUT_KERN_LEN;
|
||||||
pub const MAX_BLOCK_INPUTS: usize = MAX_INP_OUT_KERN_LEN; // soft fork down when too_high
|
|
||||||
|
/// 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.
|
/// Maximum inputs in a transaction.
|
||||||
pub const MAX_TX_INPUTS: usize = MAX_INP_OUT_KERN_LEN;
|
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.
|
/// Maximum kernels in a transaction.
|
||||||
pub const MAX_TX_KERNELS: usize = MAX_INP_OUT_KERN_LEN;
|
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
|
/// Fork every 250,000 blocks for first 2 years, simple number and just a
|
||||||
/// little less than 6 months.
|
/// little less than 6 months.
|
||||||
pub const HARD_FORK_INTERVAL: u64 = 250_000;
|
pub const HARD_FORK_INTERVAL: u64 = 250_000;
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::FromIterator;
|
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::committed::{self, Committed};
|
||||||
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
|
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
|
||||||
use core::id::ShortIdentifiable;
|
use core::id::ShortIdentifiable;
|
||||||
|
@ -45,7 +45,13 @@ pub enum Error {
|
||||||
InvalidTotalKernelSum,
|
InvalidTotalKernelSum,
|
||||||
/// Same as above but for the coinbase part of a block, including reward
|
/// Same as above but for the coinbase part of a block, including reward
|
||||||
CoinbaseSumMismatch,
|
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,
|
WeightExceeded,
|
||||||
/// Kernel not valid due to lock_height exceeding block header height
|
/// Kernel not valid due to lock_height exceeding block header height
|
||||||
KernelLockHeight(u64),
|
KernelLockHeight(u64),
|
||||||
|
@ -399,6 +405,13 @@ impl Readable for Block {
|
||||||
let outputs = read_and_verify_sorted(reader, output_len)?;
|
let outputs = read_and_verify_sorted(reader, output_len)?;
|
||||||
let kernels = read_and_verify_sorted(reader, kernel_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 {
|
Ok(Block {
|
||||||
header: header,
|
header: header,
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
|
@ -694,7 +707,11 @@ impl Block {
|
||||||
prev_kernel_offset: &BlindingFactor,
|
prev_kernel_offset: &BlindingFactor,
|
||||||
prev_kernel_sum: &Commitment,
|
prev_kernel_sum: &Commitment,
|
||||||
) -> Result<(Commitment), Error> {
|
) -> 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_weight()?;
|
||||||
|
|
||||||
self.verify_sorted()?;
|
self.verify_sorted()?;
|
||||||
self.verify_cut_through()?;
|
self.verify_cut_through()?;
|
||||||
self.verify_coinbase()?;
|
self.verify_coinbase()?;
|
||||||
|
@ -727,8 +744,28 @@ impl Block {
|
||||||
Ok(kernel_sum)
|
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> {
|
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);
|
return Err(Error::WeightExceeded);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue