From c7f1ce965e56473157ec7dc6675f4c94de8b4f84 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Fri, 6 Oct 2017 03:34:35 +0000 Subject: [PATCH] Block size limit as a max weight --- core/src/consensus.rs | 19 +++++++++++++++++++ core/src/core/block.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/core/src/consensus.rs b/core/src/consensus.rs index c502bc322..66eebb80b 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -62,6 +62,25 @@ pub const CUT_THROUGH_HORIZON: u32 = 48 * 3600 / (BLOCK_TIME_SEC as u32); /// peer-to-peer networking layer only for DoS protection. pub const MAX_MSG_LEN: u64 = 20_000_000; +/// Weight of an input when counted against the max block weigth capacity +pub const BLOCK_INPUT_WEIGHT: usize = 1; + +/// Weight of an output when counted against the max block weight capacity +pub const BLOCK_OUTPUT_WEIGHT: usize = 10; + +/// Weight of a kernel when counted against the max block weight capacity +pub const BLOCK_KERNEL_WEIGHT: usize = 2; + +/// Total maximum block weight +pub const MAX_BLOCK_WEIGHT: usize = 80_000; + +/// 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 +} + /// The minimum mining difficulty we'll allow pub const MINIMUM_DIFFICULTY: u64 = 10; diff --git a/core/src/core/block.rs b/core/src/core/block.rs index fef3450ad..769c03cc7 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -20,8 +20,7 @@ use std::collections::HashSet; use core::Committed; use core::{Input, Output, Proof, TxKernel, Transaction, COINBASE_KERNEL, COINBASE_OUTPUT}; -use consensus::{REWARD, reward}; -use consensus::MINIMUM_DIFFICULTY; +use consensus::{MINIMUM_DIFFICULTY, REWARD, reward, exceeds_weight}; use core::hash::{Hash, Hashed, ZERO_HASH}; use core::target::Difficulty; use ser::{self, Readable, Reader, Writeable, Writer}; @@ -46,6 +45,8 @@ pub enum Error { CoinbaseSumMismatch, /// Kernel fee can't be odd, due to half fee burning OddKernelFee, + /// Too many inputs, outputs or kernels in the block + WeightExceeded, /// Underlying Secp256k1 error (signature validation or invalid public /// key typically) Secp(secp::Error), @@ -425,6 +426,9 @@ impl Block { /// additional data. Includes commitment sums and kernels, Merkle /// trees, reward, etc. pub fn validate(&self, secp: &Secp256k1) -> Result<(), Error> { + if exceeds_weight(self.inputs.len(), self.outputs.len(), self.kernels.len()) { + return Err(Error::WeightExceeded); + } self.verify_coinbase(secp)?; self.verify_kernels(secp, false)?; Ok(()) @@ -527,6 +531,8 @@ mod test { use core::build::{self, input, output, with_fee}; use core::test::tx2i1o; use keychain::{Identifier, Keychain}; + use consensus::*; + use std::time::Instant; use secp; @@ -545,6 +551,30 @@ mod test { .unwrap() } + // Too slow for now #[test] + fn too_large_block() { + let keychain = Keychain::from_random_seed().unwrap(); + let max_out = MAX_BLOCK_WEIGHT / BLOCK_OUTPUT_WEIGHT; + + let mut pks = vec![]; + for n in 0..(max_out+1) { + pks.push(keychain.derive_pubkey(n as u32).unwrap()); + } + + let mut parts = vec![]; + for _ in 0..max_out { + parts.push(output(5, pks.pop().unwrap())); + } + + let now = Instant::now(); + parts.append(&mut vec![input(500000, pks.pop().unwrap()), with_fee(2)]); + let mut tx = build::transaction(parts, &keychain).map(|(tx, _)| tx).unwrap(); + println!("Build tx: {}", now.elapsed().as_secs()); + + let b = new_block(vec![&mut tx], &keychain); + assert!(b.validate(&keychain.secp()).is_err()); + } + #[test] // builds a block with a tx spending another and check if merging occurred fn compactable_block() {