Consolidate validation in Block and Transaction (#1354)

* Consolidate validation in Block and Transaction

Introduce TransactionBody which is included into block and tx.
Fixes #1333
This commit is contained in:
hashmap
2018-08-15 23:14:48 +02:00
committed by GitHub
parent 37fa413329
commit 99a66c1960
20 changed files with 570 additions and 476 deletions
+27 -29
View File
@@ -12,25 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate chrono;
extern crate grin_core;
extern crate grin_keychain as keychain;
extern crate grin_util as util;
extern crate grin_wallet as wallet;
extern crate chrono;
pub mod common;
use chrono::Duration;
use common::{new_block, tx1i2o, tx2i1o, txspend1i1o};
use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT};
use grin_core::core::Committed;
use grin_core::core::block::Error;
use grin_core::core::hash::Hashed;
use grin_core::core::id::{ShortId, ShortIdentifiable};
use grin_core::core::Committed;
use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures};
use grin_core::{global, ser};
use keychain::{BlindingFactor, ExtKeychain, Keychain};
use std::time::Instant;
use chrono::Duration;
use util::{secp, secp_static};
use wallet::libtx::build::{self, input, output, with_fee};
@@ -68,12 +68,7 @@ fn too_large_block() {
// block with no inputs/outputs/kernels
// no fees, no reward, no coinbase
fn very_empty_block() {
let b = Block {
header: BlockHeader::default(),
inputs: vec![],
outputs: vec![],
kernels: vec![],
};
let b = Block::with_header(BlockHeader::default());
assert_eq!(
b.verify_coinbase(),
@@ -113,8 +108,8 @@ fn block_with_cut_through() {
// output) and should still be valid
println!("3");
b.validate(&BlindingFactor::zero(), &zero_commit).unwrap();
assert_eq!(b.inputs.len(), 3);
assert_eq!(b.outputs.len(), 3);
assert_eq!(b.inputs().len(), 3);
assert_eq!(b.outputs().len(), 3);
println!("4");
}
@@ -126,18 +121,20 @@ fn empty_block_with_coinbase_is_valid() {
let key_id = keychain.derive_key_id(1).unwrap();
let b = new_block(vec![], &keychain, &prev, &key_id);
assert_eq!(b.inputs.len(), 0);
assert_eq!(b.outputs.len(), 1);
assert_eq!(b.kernels.len(), 1);
assert_eq!(b.inputs().len(), 0);
assert_eq!(b.outputs().len(), 1);
assert_eq!(b.kernels().len(), 1);
let coinbase_outputs = b.outputs
let coinbase_outputs = b
.outputs()
.iter()
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT))
.map(|o| o.clone())
.collect::<Vec<_>>();
assert_eq!(coinbase_outputs.len(), 1);
let coinbase_kernels = b.kernels
let coinbase_kernels = b
.kernels()
.iter()
.filter(|out| out.features.contains(KernelFeatures::COINBASE_KERNEL))
.map(|o| o.clone())
@@ -161,11 +158,11 @@ fn remove_coinbase_output_flag() {
let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(
b.outputs[0]
b.outputs()[0]
.features
.contains(OutputFeatures::COINBASE_OUTPUT)
);
b.outputs[0]
b.outputs_mut()[0]
.features
.remove(OutputFeatures::COINBASE_OUTPUT);
@@ -191,11 +188,11 @@ fn remove_coinbase_kernel_flag() {
let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(
b.kernels[0]
b.kernels()[0]
.features
.contains(KernelFeatures::COINBASE_KERNEL)
);
b.kernels[0]
b.kernels_mut()[0]
.features
.remove(KernelFeatures::COINBASE_KERNEL);
@@ -224,12 +221,13 @@ fn serialize_deserialize_block() {
// After header serialization, timestamp will lose 'nanos' info, that's the designed behavior.
// To suppress 'nanos' difference caused assertion fail, we force b.header also lose 'nanos'.
let origin_ts = b.header.timestamp;
b.header.timestamp = origin_ts - Duration::nanoseconds(origin_ts.timestamp_subsec_nanos() as i64);
b.header.timestamp =
origin_ts - Duration::nanoseconds(origin_ts.timestamp_subsec_nanos() as i64);
assert_eq!(b.header, b2.header);
assert_eq!(b.inputs, b2.inputs);
assert_eq!(b.outputs, b2.outputs);
assert_eq!(b.kernels, b2.kernels);
assert_eq!(b.inputs(), b2.inputs());
assert_eq!(b.outputs(), b2.outputs());
assert_eq!(b.kernels(), b2.kernels());
}
#[test]
@@ -341,11 +339,11 @@ fn compact_block_hash_with_nonce() {
// correctly in both of the compact_blocks
assert_eq!(
cb1.kern_ids[0],
tx.kernels[0].short_id(&cb1.hash(), cb1.nonce)
tx.kernels()[0].short_id(&cb1.hash(), cb1.nonce)
);
assert_eq!(
cb2.kern_ids[0],
tx.kernels[0].short_id(&cb2.hash(), cb2.nonce)
tx.kernels()[0].short_id(&cb2.hash(), cb2.nonce)
);
}
@@ -364,7 +362,7 @@ fn convert_block_to_compact_block() {
assert_eq!(
cb.kern_ids[0],
b.kernels
b.kernels()
.iter()
.find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL))
.unwrap()
@@ -381,8 +379,8 @@ fn hydrate_empty_compact_block() {
let cb = b.as_compact_block();
let hb = Block::hydrate_from(cb, vec![]);
assert_eq!(hb.header, b.header);
assert_eq!(hb.outputs, b.outputs);
assert_eq!(hb.kernels, b.kernels);
assert_eq!(hb.outputs(), b.outputs());
assert_eq!(hb.kernels(), b.kernels());
}
#[test]
+34 -24
View File
@@ -28,8 +28,9 @@ use grin_core::core::{aggregate, deaggregate, KernelFeatures, Output, Transactio
use grin_core::ser;
use keychain::{BlindingFactor, ExtKeychain, Keychain};
use util::{secp_static, static_secp_instance};
use wallet::libtx::build::{self, initial_tx, input, output, with_excess, with_fee,
with_lock_height};
use wallet::libtx::build::{
self, initial_tx, input, output, with_excess, with_fee, with_lock_height,
};
#[test]
fn simple_tx_ser() {
@@ -47,8 +48,8 @@ fn simple_tx_ser_deser() {
ser::serialize(&mut vec, &tx).expect("serialization failed");
let dtx: Transaction = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(dtx.fee(), 2);
assert_eq!(dtx.inputs.len(), 2);
assert_eq!(dtx.outputs.len(), 1);
assert_eq!(dtx.inputs().len(), 2);
assert_eq!(dtx.outputs().len(), 1);
assert_eq!(tx.hash(), dtx.hash());
}
@@ -108,8 +109,8 @@ fn build_tx_kernel() {
tx.validate(false).unwrap();
// check the kernel is also itself valid
assert_eq!(tx.kernels.len(), 1);
let kern = &tx.kernels[0];
assert_eq!(tx.kernels().len(), 1);
let kern = &tx.kernels()[0];
kern.verify().unwrap();
assert_eq!(kern.features, KernelFeatures::DEFAULT_KERNEL);
@@ -145,7 +146,10 @@ fn multi_kernel_transaction_deaggregation() {
assert!(tx3.validate(false).is_ok());
assert!(tx4.validate(false).is_ok());
let tx1234 = aggregate(vec![tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()], None).unwrap();
let tx1234 = aggregate(
vec![tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()],
None,
).unwrap();
let tx12 = aggregate(vec![tx1.clone(), tx2.clone()], None).unwrap();
let tx34 = aggregate(vec![tx3.clone(), tx4.clone()], None).unwrap();
@@ -220,13 +224,16 @@ fn multi_kernel_transaction_deaggregation_4() {
assert!(tx4.validate(false).is_ok());
assert!(tx5.validate(false).is_ok());
let tx12345 = aggregate(vec![
tx1.clone(),
tx2.clone(),
tx3.clone(),
tx4.clone(),
tx5.clone(),
], None).unwrap();
let tx12345 = aggregate(
vec![
tx1.clone(),
tx2.clone(),
tx3.clone(),
tx4.clone(),
tx5.clone(),
],
None,
).unwrap();
assert!(tx12345.validate(false).is_ok());
let deaggregated_tx5 = deaggregate(
@@ -251,13 +258,16 @@ fn multi_kernel_transaction_deaggregation_5() {
assert!(tx4.validate(false).is_ok());
assert!(tx5.validate(false).is_ok());
let tx12345 = aggregate(vec![
tx1.clone(),
tx2.clone(),
tx3.clone(),
tx4.clone(),
tx5.clone(),
], None).unwrap();
let tx12345 = aggregate(
vec![
tx1.clone(),
tx2.clone(),
tx3.clone(),
tx4.clone(),
tx5.clone(),
],
None,
).unwrap();
let tx12 = aggregate(vec![tx1.clone(), tx2.clone()], None).unwrap();
let tx34 = aggregate(vec![tx3.clone(), tx4.clone()], None).unwrap();
@@ -309,9 +319,9 @@ fn hash_output() {
],
&keychain,
).unwrap();
let h = tx.outputs[0].hash();
let h = tx.outputs()[0].hash();
assert!(h != ZERO_HASH);
let h2 = tx.outputs[1].hash();
let h2 = tx.outputs()[1].hash();
assert!(h != h2);
}
@@ -325,7 +335,7 @@ fn blind_tx() {
// with a bullet proof causes painful errors
// checks that the range proof on our blind output is sufficiently hiding
let Output { proof, .. } = btx.outputs[0];
let Output { proof, .. } = btx.outputs()[0];
let secp = static_secp_instance();
let secp = secp.lock().unwrap();