diff --git a/chain/src/chain.rs b/chain/src/chain.rs index c959b0b78..b12ec166c 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -28,7 +28,9 @@ use lru_cache::LruCache; use core::core::hash::{Hash, Hashed, ZERO_HASH}; use core::core::merkle_proof::MerkleProof; use core::core::verifier_cache::VerifierCache; -use core::core::{Block, BlockHeader, BlockSums, Output, OutputIdentifier, Transaction, TxKernel}; +use core::core::{ + Block, BlockHeader, BlockSums, Output, OutputIdentifier, Transaction, TxKernelEntry, +}; use core::global; use core::pow; use error::{Error, ErrorKind}; @@ -966,7 +968,7 @@ impl Chain { } /// as above, for kernels - pub fn get_last_n_kernel(&self, distance: u64) -> Vec<(Hash, TxKernel)> { + pub fn get_last_n_kernel(&self, distance: u64) -> Vec<(Hash, TxKernelEntry)> { let mut txhashset = self.txhashset.write(); txhashset.last_n_kernel(distance) } diff --git a/chain/src/txhashset/rewindable_kernel_view.rs b/chain/src/txhashset/rewindable_kernel_view.rs index e9e996c29..137bdc3c6 100644 --- a/chain/src/txhashset/rewindable_kernel_view.rs +++ b/chain/src/txhashset/rewindable_kernel_view.rs @@ -15,7 +15,7 @@ //! Lightweight readonly view into kernel MMR for convenience. use core::core::pmmr::RewindablePMMR; -use core::core::{BlockHeader, TxKernel}; +use core::core::{BlockHeader, TxKernelEntry}; use error::{Error, ErrorKind}; use grin_store::pmmr::PMMRBackend; @@ -23,7 +23,7 @@ use store::Batch; /// Rewindable (but readonly) view of the kernel set (based on kernel MMR). pub struct RewindableKernelView<'a> { - pmmr: RewindablePMMR<'a, TxKernel, PMMRBackend>, + pmmr: RewindablePMMR<'a, TxKernelEntry, PMMRBackend>, batch: &'a Batch<'a>, header: BlockHeader, } @@ -31,7 +31,7 @@ pub struct RewindableKernelView<'a> { impl<'a> RewindableKernelView<'a> { /// Build a new readonly kernel view. pub fn new( - pmmr: RewindablePMMR<'a, TxKernel, PMMRBackend>, + pmmr: RewindablePMMR<'a, TxKernelEntry, PMMRBackend>, batch: &'a Batch, header: BlockHeader, ) -> RewindableKernelView<'a> { diff --git a/chain/src/txhashset/txhashset.rs b/chain/src/txhashset/txhashset.rs index 23a50631c..f99f63d02 100644 --- a/chain/src/txhashset/txhashset.rs +++ b/chain/src/txhashset/txhashset.rs @@ -29,7 +29,9 @@ use core::core::committed::Committed; use core::core::hash::{Hash, Hashed}; use core::core::merkle_proof::MerkleProof; use core::core::pmmr::{self, ReadonlyPMMR, RewindablePMMR, DBPMMR, PMMR}; -use core::core::{Block, BlockHeader, Input, Output, OutputFeatures, OutputIdentifier, TxKernel}; +use core::core::{ + Block, BlockHeader, Input, Output, OutputFeatures, OutputIdentifier, TxKernel, TxKernelEntry, +}; use core::global; use core::ser::{PMMRIndexHashable, PMMRable}; @@ -119,7 +121,7 @@ pub struct TxHashSet { output_pmmr_h: PMMRHandle, rproof_pmmr_h: PMMRHandle, - kernel_pmmr_h: PMMRHandle, + kernel_pmmr_h: PMMRHandle, // chain store used as index of commitments to MMR positions commit_index: Arc, @@ -205,8 +207,8 @@ impl TxHashSet { } /// as above, for kernels - pub fn last_n_kernel(&mut self, distance: u64) -> Vec<(Hash, TxKernel)> { - let kernel_pmmr: PMMR = + pub fn last_n_kernel(&mut self, distance: u64) -> Vec<(Hash, TxKernelEntry)> { + let kernel_pmmr: PMMR = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos); kernel_pmmr.get_last_n_insertions(distance) } @@ -247,7 +249,7 @@ impl TxHashSet { PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos); let rproof_pmmr: PMMR = PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos); - let kernel_pmmr: PMMR = + let kernel_pmmr: PMMR = PMMR::at(&mut self.kernel_pmmr_h.backend, self.kernel_pmmr_h.last_pos); TxHashSetRoots { @@ -733,7 +735,7 @@ pub struct Extension<'a> { header_pmmr: DBPMMR<'a, BlockHeader, HashOnlyMMRBackend>, output_pmmr: PMMR<'a, OutputIdentifier, PMMRBackend>, rproof_pmmr: PMMR<'a, RangeProof, PMMRBackend>, - kernel_pmmr: PMMR<'a, TxKernel, PMMRBackend>, + kernel_pmmr: PMMR<'a, TxKernelEntry, PMMRBackend>, /// Rollback flag. rollback: bool, @@ -766,7 +768,7 @@ impl<'a> Committed for Extension<'a> { for n in 1..self.kernel_pmmr.unpruned_size() + 1 { if pmmr::is_leaf(n) { if let Some(kernel) = self.kernel_pmmr.get_data(n) { - commitments.push(kernel.excess); + commitments.push(kernel.excess()); } } } @@ -951,14 +953,14 @@ impl<'a> Extension<'a> { /// Push kernel onto MMR (hash and data files). fn apply_kernel(&mut self, kernel: &TxKernel) -> Result<(), Error> { self.kernel_pmmr - .push(kernel.clone()) + .push(TxKernelEntry::from(kernel.clone())) .map_err(&ErrorKind::TxHashSetErr)?; Ok(()) } fn apply_header(&mut self, header: &BlockHeader) -> Result<(), Error> { self.header_pmmr - .push(&header) + .push(header) .map_err(&ErrorKind::TxHashSetErr)?; Ok(()) } diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 1b8010818..c7a41d4e1 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -250,13 +250,67 @@ impl TxKernel { } } -impl FixedLength for TxKernel { +/// Wrapper around a tx kernel used when maintaining them in the MMR. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TxKernelEntry { + /// The underlying tx kernel. + pub kernel: TxKernel, +} + +impl Writeable for TxKernelEntry { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + ser_multiwrite!( + writer, + [write_u8, self.kernel.features.bits()], + [write_u64, self.kernel.fee], + [write_u64, self.kernel.lock_height], + [write_fixed_bytes, &self.kernel.excess] + ); + self.kernel.excess_sig.write(writer)?; + Ok(()) + } +} + +impl Readable for TxKernelEntry { + fn read(reader: &mut Reader) -> Result { + let features = + KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?; + let kernel = TxKernel { + features: features, + fee: reader.read_u64()?, + lock_height: reader.read_u64()?, + excess: Commitment::read(reader)?, + excess_sig: secp::Signature::read(reader)?, + }; + Ok(TxKernelEntry { kernel }) + } +} + +impl TxKernelEntry { + /// The excess on the underlying tx kernel. + pub fn excess(&self) -> Commitment { + self.kernel.excess + } + + /// Verify the underlying tx kernel. + pub fn verify(&self) -> Result<(), Error> { + self.kernel.verify() + } +} + +impl From for TxKernelEntry { + fn from(kernel: TxKernel) -> Self { + TxKernelEntry { kernel } + } +} + +impl FixedLength for TxKernelEntry { const LEN: usize = 17 // features plus fee and lock_height + secp::constants::PEDERSEN_COMMITMENT_SIZE + secp::constants::AGG_SIGNATURE_SIZE; } -impl PMMRable for TxKernel {} +impl PMMRable for TxKernelEntry {} /// TransactionBody is a common abstraction for transaction and block #[derive(Serialize, Deserialize, Debug, Clone)]