From bd03528d335592efd667750fe2421efb274ac398 Mon Sep 17 00:00:00 2001 From: Antioch Peverell <30642645+antiochp@users.noreply.github.com> Date: Sun, 26 Aug 2018 11:43:44 +0100 Subject: [PATCH] lightweight validation during deserialization (#1422) * introduce validate_read (for lightweight validation when reading) * rustfmt --- core/src/core/block.rs | 20 ++++++++++++++++++-- core/src/core/compact_block.rs | 10 ++++++---- core/src/core/transaction.rs | 29 +++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 7d036baf1..e8f811a8d 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -301,8 +301,12 @@ impl Readable for Block { let body = TransactionBody::read(reader)?; - // Now validate the body and treat any validation error as corrupted data. - body.validate(true).map_err(|_| ser::Error::CorruptedData)?; + // Now "lightweight" validation of the block. + // Treat any validation issues as data corruption. + // An example of this would be reading a block + // that exceeded the allowed number of inputs. + body.validate_read(true) + .map_err(|_| ser::Error::CorruptedData)?; Ok(Block { header: header, @@ -528,6 +532,18 @@ impl Block { }) } + /// "Lightweight" validation that we can perform quickly during read/deserialization. + /// Subset of full validation that skips expensive verification steps, specifically - + /// * rangeproof verification (on the body) + /// * kernel signature verification (on the body) + /// * coinbase sum verification + /// * kernel sum verification + pub fn validate_read(&self) -> Result<(), Error> { + self.body.validate_read(true)?; + self.verify_kernel_lock_heights()?; + Ok(()) + } + /// Validates all the elements in a block that can be checked without /// additional data. Includes commitment sums and kernels, Merkle /// trees, reward, etc. diff --git a/core/src/core/compact_block.rs b/core/src/core/compact_block.rs index d1f37ce7a..eb0b1b1c7 100644 --- a/core/src/core/compact_block.rs +++ b/core/src/core/compact_block.rs @@ -68,7 +68,8 @@ impl CompactBlockBody { self.kern_ids.sort(); } - fn validate(&self) -> Result<(), Error> { + /// "Lightweight" validation. + fn validate_read(&self) -> Result<(), Error> { self.verify_sorted()?; Ok(()) } @@ -138,8 +139,9 @@ pub struct CompactBlock { } impl CompactBlock { - fn validate(&self) -> Result<(), Error> { - self.body.validate()?; + /// "Lightweight" validation. + fn validate_read(&self) -> Result<(), Error> { + self.body.validate_read()?; Ok(()) } @@ -225,7 +227,7 @@ impl Readable for CompactBlock { }; // Now validate the compact block and treat any validation error as corrupted data. - cb.validate().map_err(|_| ser::Error::CorruptedData)?; + cb.validate_read().map_err(|_| ser::Error::CorruptedData)?; Ok(cb) } diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 32b9ff194..509dbe40b 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -544,6 +544,17 @@ impl TransactionBody { Ok(()) } + /// "Lightweight" validation that we can perform quickly during read/deserialization. + /// Subset of full validation that skips expensive verification steps, specifically - + /// * rangeproof verification + /// * kernel signature verification + pub fn validate_read(&self, with_reward: bool) -> Result<(), Error> { + self.verify_weight(with_reward)?; + self.verify_sorted()?; + self.verify_cut_through()?; + Ok(()) + } + /// Validates all relevant parts of a transaction body. Checks the /// excess value against the signature as well as range proofs for each /// output. @@ -598,11 +609,12 @@ impl Readable for Transaction { let body = TransactionBody::read(reader)?; let tx = Transaction { offset, body }; - // Now validate the tx. + // Now "lightweight" validation of the tx. // Treat any validation issues as data corruption. // An example of this would be reading a tx // that exceeded the allowed number of inputs. - tx.validate(false).map_err(|_| ser::Error::CorruptedData)?; + tx.validate_read(false) + .map_err(|_| ser::Error::CorruptedData)?; Ok(tx) } @@ -732,6 +744,19 @@ impl Transaction { self.body.lock_height() } + /// "Lightweight" validation that we can perform quickly during read/deserialization. + /// Subset of full validation that skips expensive verification steps, specifically - + /// * rangeproof verification (on the body) + /// * kernel signature verification (on the body) + /// * kernel sum verification + pub fn validate_read(&self, with_reward: bool) -> Result<(), Error> { + self.body.validate_read(with_reward)?; + if !with_reward { + self.body.verify_features()?; + } + Ok(()) + } + /// Validates all relevant parts of a fully built transaction. Checks the /// excess value against the signature as well as range proofs for each /// output.