Cargo fmt all the things
This commit is contained in:
+68
-39
@@ -27,7 +27,8 @@ use core::target::Difficulty;
|
||||
pub const REWARD: u64 = 1_000_000_000;
|
||||
|
||||
/// Number of blocks before a coinbase matures and can be spent
|
||||
/// TODO - reduced this for testing - need to investigate if we can lower this in test env
|
||||
/// TODO - reduced this for testing - need to investigate if we can lower this
|
||||
/// in test env
|
||||
// pub const COINBASE_MATURITY: u64 = 1_000;
|
||||
pub const COINBASE_MATURITY: u64 = 3;
|
||||
|
||||
@@ -99,7 +100,8 @@ impl fmt::Display for TargetError {
|
||||
/// difference between the median timestamps at the beginning and the end
|
||||
/// of the window.
|
||||
pub fn next_difficulty<T>(cursor: T) -> Result<Difficulty, TargetError>
|
||||
where T: IntoIterator<Item = Result<(u64, Difficulty), TargetError>>
|
||||
where
|
||||
T: IntoIterator<Item = Result<(u64, Difficulty), TargetError>>,
|
||||
{
|
||||
|
||||
// Block times at the begining and end of the adjustment window, used to
|
||||
@@ -155,8 +157,9 @@ pub fn next_difficulty<T>(cursor: T) -> Result<Difficulty, TargetError>
|
||||
ts_damp
|
||||
};
|
||||
|
||||
Ok(diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW) /
|
||||
Difficulty::from_num(adj_ts))
|
||||
Ok(
|
||||
diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW) / Difficulty::from_num(adj_ts),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -171,24 +174,25 @@ mod test {
|
||||
// Builds an iterator for next difficulty calculation with the provided
|
||||
// constant time interval, difficulty and total length.
|
||||
fn repeat(interval: u64, diff: u64, len: u64) -> Vec<Result<(u64, Difficulty), TargetError>> {
|
||||
//watch overflow here, length shouldn't be ridiculous anyhow
|
||||
// watch overflow here, length shouldn't be ridiculous anyhow
|
||||
assert!(len < std::usize::MAX as u64);
|
||||
let diffs = vec![Difficulty::from_num(diff); len as usize];
|
||||
let times = (0..(len as usize)).map(|n| n * interval as usize).rev();
|
||||
let pairs = times.zip(diffs.iter());
|
||||
pairs.map(|(t, d)| Ok((t as u64, d.clone()))).collect::<Vec<_>>()
|
||||
pairs
|
||||
.map(|(t, d)| Ok((t as u64, d.clone())))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn repeat_offs(from: u64,
|
||||
interval: u64,
|
||||
diff: u64,
|
||||
len: u64)
|
||||
-> Vec<Result<(u64, Difficulty), TargetError>> {
|
||||
map_vec!(repeat(interval, diff, len), |e| {
|
||||
match e.clone() {
|
||||
Err(e) => Err(e),
|
||||
Ok((t, d)) => Ok((t + from, d)),
|
||||
}
|
||||
fn repeat_offs(
|
||||
from: u64,
|
||||
interval: u64,
|
||||
diff: u64,
|
||||
len: u64,
|
||||
) -> Vec<Result<(u64, Difficulty), TargetError>> {
|
||||
map_vec!(repeat(interval, diff, len), |e| match e.clone() {
|
||||
Err(e) => Err(e),
|
||||
Ok((t, d)) => Ok((t + from, d)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -196,19 +200,28 @@ mod test {
|
||||
#[test]
|
||||
fn next_target_adjustment() {
|
||||
// not enough data
|
||||
assert_eq!(next_difficulty(vec![]).unwrap(), Difficulty::from_num(MINIMUM_DIFFICULTY));
|
||||
assert_eq!(
|
||||
next_difficulty(vec![]).unwrap(),
|
||||
Difficulty::from_num(MINIMUM_DIFFICULTY)
|
||||
);
|
||||
|
||||
assert_eq!(next_difficulty(vec![Ok((60, Difficulty::one()))]).unwrap(),
|
||||
Difficulty::from_num(MINIMUM_DIFFICULTY));
|
||||
assert_eq!(
|
||||
next_difficulty(vec![Ok((60, Difficulty::one()))]).unwrap(),
|
||||
Difficulty::from_num(MINIMUM_DIFFICULTY)
|
||||
);
|
||||
|
||||
assert_eq!(next_difficulty(repeat(60, 10, DIFFICULTY_ADJUST_WINDOW)).unwrap(),
|
||||
Difficulty::from_num(MINIMUM_DIFFICULTY));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(60, 10, DIFFICULTY_ADJUST_WINDOW)).unwrap(),
|
||||
Difficulty::from_num(MINIMUM_DIFFICULTY)
|
||||
);
|
||||
|
||||
// just enough data, right interval, should stay constant
|
||||
|
||||
let just_enough = DIFFICULTY_ADJUST_WINDOW + MEDIAN_TIME_WINDOW;
|
||||
assert_eq!(next_difficulty(repeat(60, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1000));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(60, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1000)
|
||||
);
|
||||
|
||||
// checking averaging works, window length is odd so need to compensate a little
|
||||
let sec = DIFFICULTY_ADJUST_WINDOW / 2 + 1 + MEDIAN_TIME_WINDOW;
|
||||
@@ -218,28 +231,44 @@ mod test {
|
||||
assert_eq!(next_difficulty(s2).unwrap(), Difficulty::from_num(999));
|
||||
|
||||
// too slow, diff goes down
|
||||
assert_eq!(next_difficulty(repeat(90, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(889));
|
||||
assert_eq!(next_difficulty(repeat(120, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(800));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(90, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(889)
|
||||
);
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(120, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(800)
|
||||
);
|
||||
|
||||
// too fast, diff goes up
|
||||
assert_eq!(next_difficulty(repeat(55, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1021));
|
||||
assert_eq!(next_difficulty(repeat(45, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1067));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(55, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1021)
|
||||
);
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(45, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1067)
|
||||
);
|
||||
|
||||
// hitting lower time bound, should always get the same result below
|
||||
assert_eq!(next_difficulty(repeat(20, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1200));
|
||||
assert_eq!(next_difficulty(repeat(10, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1200));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(20, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1200)
|
||||
);
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(10, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(1200)
|
||||
);
|
||||
|
||||
// hitting higher time bound, should always get the same result above
|
||||
assert_eq!(next_difficulty(repeat(160, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(750));
|
||||
assert_eq!(next_difficulty(repeat(200, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(750));
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(160, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(750)
|
||||
);
|
||||
assert_eq!(
|
||||
next_difficulty(repeat(200, 1000, just_enough)).unwrap(),
|
||||
Difficulty::from_num(750)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+161
-142
@@ -85,14 +85,16 @@ impl Default for BlockHeader {
|
||||
/// Serialization of a block header
|
||||
impl Writeable for BlockHeader {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.height],
|
||||
[write_fixed_bytes, &self.previous],
|
||||
[write_i64, self.timestamp.to_timespec().sec],
|
||||
[write_fixed_bytes, &self.utxo_root],
|
||||
[write_fixed_bytes, &self.range_proof_root],
|
||||
[write_fixed_bytes, &self.kernel_root],
|
||||
[write_u8, self.features.bits()]);
|
||||
ser_multiwrite!(
|
||||
writer,
|
||||
[write_u64, self.height],
|
||||
[write_fixed_bytes, &self.previous],
|
||||
[write_i64, self.timestamp.to_timespec().sec],
|
||||
[write_fixed_bytes, &self.utxo_root],
|
||||
[write_fixed_bytes, &self.range_proof_root],
|
||||
[write_fixed_bytes, &self.kernel_root],
|
||||
[write_u8, self.features.bits()]
|
||||
);
|
||||
|
||||
try!(writer.write_u64(self.nonce));
|
||||
try!(self.difficulty.write(writer));
|
||||
@@ -129,7 +131,9 @@ impl Readable for BlockHeader {
|
||||
utxo_root: utxo_root,
|
||||
range_proof_root: rproof_root,
|
||||
kernel_root: kernel_root,
|
||||
features: BlockFeatures::from_bits(features).ok_or(ser::Error::CorruptedData)?,
|
||||
features: BlockFeatures::from_bits(features).ok_or(
|
||||
ser::Error::CorruptedData,
|
||||
)?,
|
||||
pow: pow,
|
||||
nonce: nonce,
|
||||
difficulty: difficulty,
|
||||
@@ -162,10 +166,12 @@ impl Writeable for Block {
|
||||
try!(self.header.write(writer));
|
||||
|
||||
if writer.serialization_mode() != ser::SerializationMode::Hash {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64],
|
||||
[write_u64, self.kernels.len() as u64]);
|
||||
ser_multiwrite!(
|
||||
writer,
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64],
|
||||
[write_u64, self.kernels.len() as u64]
|
||||
);
|
||||
|
||||
for inp in &self.inputs {
|
||||
try!(inp.write(writer));
|
||||
@@ -234,10 +240,11 @@ impl Block {
|
||||
/// Builds a new block from the header of the previous block, a vector of
|
||||
/// transactions and the private key that will receive the reward. Checks
|
||||
/// that all transactions are valid and calculates the Merkle tree.
|
||||
pub fn new(prev: &BlockHeader,
|
||||
txs: Vec<&Transaction>,
|
||||
reward_key: SecretKey)
|
||||
-> Result<Block, secp::Error> {
|
||||
pub fn new(
|
||||
prev: &BlockHeader,
|
||||
txs: Vec<&Transaction>,
|
||||
reward_key: SecretKey,
|
||||
) -> Result<Block, secp::Error> {
|
||||
|
||||
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
let (reward_out, reward_proof) = try!(Block::reward_output(reward_key, &secp));
|
||||
@@ -248,11 +255,12 @@ impl Block {
|
||||
/// Builds a new block ready to mine from the header of the previous block,
|
||||
/// a vector of transactions and the reward information. Checks
|
||||
/// that all transactions are valid and calculates the Merkle tree.
|
||||
pub fn with_reward(prev: &BlockHeader,
|
||||
txs: Vec<&Transaction>,
|
||||
reward_out: Output,
|
||||
reward_kern: TxKernel)
|
||||
-> Result<Block, secp::Error> {
|
||||
pub fn with_reward(
|
||||
prev: &BlockHeader,
|
||||
txs: Vec<&Transaction>,
|
||||
reward_out: Output,
|
||||
reward_kern: TxKernel,
|
||||
) -> Result<Block, secp::Error> {
|
||||
// note: the following reads easily but may not be the most efficient due to
|
||||
// repeated iterations, revisit if a problem
|
||||
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
@@ -264,18 +272,16 @@ impl Block {
|
||||
// build vectors with all inputs and all outputs, ordering them by hash
|
||||
// needs to be a fold so we don't end up with a vector of vectors and we
|
||||
// want to fully own the refs (not just a pointer like flat_map).
|
||||
let mut inputs = txs.iter()
|
||||
.fold(vec![], |mut acc, ref tx| {
|
||||
let mut inputs = tx.inputs.clone();
|
||||
acc.append(&mut inputs);
|
||||
acc
|
||||
});
|
||||
let mut outputs = txs.iter()
|
||||
.fold(vec![], |mut acc, ref tx| {
|
||||
let mut outputs = tx.outputs.clone();
|
||||
acc.append(&mut outputs);
|
||||
acc
|
||||
});
|
||||
let mut inputs = txs.iter().fold(vec![], |mut acc, ref tx| {
|
||||
let mut inputs = tx.inputs.clone();
|
||||
acc.append(&mut inputs);
|
||||
acc
|
||||
});
|
||||
let mut outputs = txs.iter().fold(vec![], |mut acc, ref tx| {
|
||||
let mut outputs = tx.outputs.clone();
|
||||
acc.append(&mut outputs);
|
||||
acc
|
||||
});
|
||||
outputs.push(reward_out);
|
||||
|
||||
inputs.sort_by_key(|inp| inp.hash());
|
||||
@@ -283,19 +289,24 @@ impl Block {
|
||||
|
||||
// calculate the overall Merkle tree and fees
|
||||
|
||||
Ok(Block {
|
||||
Ok(
|
||||
Block {
|
||||
header: BlockHeader {
|
||||
height: prev.height + 1,
|
||||
timestamp: time::Tm { tm_nsec: 0, ..time::now_utc() },
|
||||
timestamp: time::Tm {
|
||||
tm_nsec: 0,
|
||||
..time::now_utc()
|
||||
},
|
||||
previous: prev.hash(),
|
||||
total_difficulty: prev.pow.clone().to_difficulty() + prev.total_difficulty.clone(),
|
||||
total_difficulty: prev.pow.clone().to_difficulty() +
|
||||
prev.total_difficulty.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
kernels: kernels,
|
||||
}
|
||||
.compact())
|
||||
}.compact(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -312,37 +323,37 @@ impl Block {
|
||||
/// Matches any output with a potential spending input, eliminating them
|
||||
/// from the block. Provides a simple way to compact the block. The
|
||||
/// elimination is stable with respect to inputs and outputs order.
|
||||
///
|
||||
/// NOTE: exclude coinbase from compaction process
|
||||
/// if a block contains a new coinbase output and
|
||||
/// is a transaction spending a previous coinbase
|
||||
/// we do not want to compact these away
|
||||
///
|
||||
///
|
||||
/// NOTE: exclude coinbase from compaction process
|
||||
/// if a block contains a new coinbase output and
|
||||
/// is a transaction spending a previous coinbase
|
||||
/// we do not want to compact these away
|
||||
///
|
||||
pub fn compact(&self) -> Block {
|
||||
let in_set = self.inputs
|
||||
.iter()
|
||||
.map(|inp| inp.commitment())
|
||||
.collect::<HashSet<_>>();
|
||||
let in_set = self.inputs
|
||||
.iter()
|
||||
.map(|inp| inp.commitment())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let out_set = self.outputs
|
||||
.iter()
|
||||
.filter(|out| !out.features.contains(COINBASE_OUTPUT))
|
||||
.map(|out| out.commitment())
|
||||
.collect::<HashSet<_>>();
|
||||
let out_set = self.outputs
|
||||
.iter()
|
||||
.filter(|out| !out.features.contains(COINBASE_OUTPUT))
|
||||
.map(|out| out.commitment())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let commitments_to_compact = in_set.intersection(&out_set).collect::<HashSet<_>>();
|
||||
let commitments_to_compact = in_set.intersection(&out_set).collect::<HashSet<_>>();
|
||||
|
||||
let new_inputs = self.inputs
|
||||
.iter()
|
||||
.filter(|inp| !commitments_to_compact.contains(&inp.commitment()))
|
||||
.map(|&inp| inp)
|
||||
.collect::<Vec<_>>();
|
||||
let new_inputs = self.inputs
|
||||
.iter()
|
||||
.filter(|inp| !commitments_to_compact.contains(&inp.commitment()))
|
||||
.map(|&inp| inp)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let new_outputs = self.outputs
|
||||
.iter()
|
||||
.filter(|out| !commitments_to_compact.contains(&out.commitment()))
|
||||
.map(|&out| out)
|
||||
.collect::<Vec<_>>();
|
||||
let new_outputs = self.outputs
|
||||
.iter()
|
||||
.filter(|out| !commitments_to_compact.contains(&out.commitment()))
|
||||
.map(|&out| out)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Block {
|
||||
header: BlockHeader {
|
||||
@@ -374,18 +385,17 @@ impl Block {
|
||||
all_outputs.sort_by_key(|out| out.hash());
|
||||
|
||||
Block {
|
||||
// compact will fix the merkle tree
|
||||
header: BlockHeader {
|
||||
pow: self.header.pow.clone(),
|
||||
difficulty: self.header.difficulty.clone(),
|
||||
total_difficulty: self.header.total_difficulty.clone(),
|
||||
..self.header
|
||||
},
|
||||
inputs: all_inputs,
|
||||
outputs: all_outputs,
|
||||
kernels: all_kernels,
|
||||
}
|
||||
.compact()
|
||||
// compact will fix the merkle tree
|
||||
header: BlockHeader {
|
||||
pow: self.header.pow.clone(),
|
||||
difficulty: self.header.difficulty.clone(),
|
||||
total_difficulty: self.header.total_difficulty.clone(),
|
||||
..self.header
|
||||
},
|
||||
inputs: all_inputs,
|
||||
outputs: all_outputs,
|
||||
kernels: all_kernels,
|
||||
}.compact()
|
||||
}
|
||||
|
||||
/// Validates all the elements in a block that can be checked without
|
||||
@@ -394,7 +404,7 @@ impl Block {
|
||||
pub fn validate(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
self.verify_coinbase(secp)?;
|
||||
self.verify_kernels(secp)?;
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate the sum of input/output commitments match the sum in kernels
|
||||
@@ -441,23 +451,25 @@ impl Block {
|
||||
// verifying the kernels on a block composed of just the coinbase outputs
|
||||
// and kernels checks all we need
|
||||
Block {
|
||||
header: BlockHeader::default(),
|
||||
inputs: vec![],
|
||||
outputs: cb_outs,
|
||||
kernels: cb_kerns,
|
||||
}
|
||||
.verify_kernels(secp)
|
||||
header: BlockHeader::default(),
|
||||
inputs: vec![],
|
||||
outputs: cb_outs,
|
||||
kernels: cb_kerns,
|
||||
}.verify_kernels(secp)
|
||||
}
|
||||
|
||||
/// Builds the blinded output and related signature proof for the block
|
||||
/// reward.
|
||||
pub fn reward_output(skey: secp::key::SecretKey,
|
||||
secp: &Secp256k1)
|
||||
-> Result<(Output, TxKernel), secp::Error> {
|
||||
let msg = try!(secp::Message::from_slice(&[0; secp::constants::MESSAGE_SIZE]));
|
||||
pub fn reward_output(
|
||||
skey: secp::key::SecretKey,
|
||||
secp: &Secp256k1,
|
||||
) -> Result<(Output, TxKernel), secp::Error> {
|
||||
let msg = try!(secp::Message::from_slice(
|
||||
&[0; secp::constants::MESSAGE_SIZE],
|
||||
));
|
||||
let sig = try!(secp.sign(&msg, &skey));
|
||||
let commit = secp.commit(REWARD, skey).unwrap();
|
||||
//let switch_commit = secp.switch_commit(skey).unwrap();
|
||||
// let switch_commit = secp.switch_commit(skey).unwrap();
|
||||
let nonce = secp.nonce();
|
||||
let rproof = secp.range_proof(0, REWARD, skey, commit, nonce);
|
||||
|
||||
@@ -560,78 +572,85 @@ mod test {
|
||||
assert_eq!(b3.outputs.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_block_with_coinbase_is_valid() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
#[test]
|
||||
fn empty_block_with_coinbase_is_valid() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
|
||||
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(COINBASE_OUTPUT))
|
||||
.map(|o| o.clone())
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_outputs.len(), 1);
|
||||
assert_eq!(coinbase_outputs.len(), 1);
|
||||
|
||||
let coinbase_kernels = b.kernels
|
||||
let coinbase_kernels = b.kernels
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(COINBASE_KERNEL))
|
||||
.map(|o| o.clone())
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_kernels.len(), 1);
|
||||
assert_eq!(coinbase_kernels.len(), 1);
|
||||
|
||||
// the block should be valid here (single coinbase output with corresponding txn kernel)
|
||||
assert_eq!(b.validate(&secp), Ok(()));
|
||||
}
|
||||
// the block should be valid here (single coinbase output with corresponding
|
||||
// txn kernel)
|
||||
assert_eq!(b.validate(&secp), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
// test that flipping the COINBASE_OUTPUT flag on the output features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
// additionally verifying the merkle_inputs_outputs also fails
|
||||
fn remove_coinbase_output_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
#[test]
|
||||
// test that flipping the COINBASE_OUTPUT flag on the output features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
// additionally verifying the merkle_inputs_outputs also fails
|
||||
fn remove_coinbase_output_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
|
||||
assert!(b.outputs[0].features.contains(COINBASE_OUTPUT));
|
||||
b.outputs[0].features.remove(COINBASE_OUTPUT);
|
||||
assert!(b.outputs[0].features.contains(COINBASE_OUTPUT));
|
||||
b.outputs[0].features.remove(COINBASE_OUTPUT);
|
||||
|
||||
assert_eq!(b.verify_coinbase(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
assert_eq!(
|
||||
b.verify_coinbase(&secp),
|
||||
Err(secp::Error::IncorrectCommitSum)
|
||||
);
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
// test that flipping the COINBASE_KERNEL flag on the kernel features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
fn remove_coinbase_kernel_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
#[test]
|
||||
// test that flipping the COINBASE_KERNEL flag on the kernel features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
fn remove_coinbase_kernel_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
|
||||
assert!(b.kernels[0].features.contains(COINBASE_KERNEL));
|
||||
b.kernels[0].features.remove(COINBASE_KERNEL);
|
||||
assert!(b.kernels[0].features.contains(COINBASE_KERNEL));
|
||||
b.kernels[0].features.remove(COINBASE_KERNEL);
|
||||
|
||||
assert_eq!(b.verify_coinbase(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
assert_eq!(
|
||||
b.verify_coinbase(&secp),
|
||||
Err(secp::Error::IncorrectCommitSum)
|
||||
);
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_deserialize_block() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
#[test]
|
||||
fn serialize_deserialize_block() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
|
||||
let mut vec = Vec::new();
|
||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||
let b2: Block = ser::deserialize(&mut &vec[..]).unwrap();
|
||||
let mut vec = Vec::new();
|
||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||
let b2: Block = ser::deserialize(&mut &vec[..]).unwrap();
|
||||
|
||||
assert_eq!(b.inputs, b2.inputs);
|
||||
assert_eq!(b.outputs, b2.outputs);
|
||||
assert_eq!(b.kernels, b2.kernels);
|
||||
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.header, b2.header);
|
||||
}
|
||||
}
|
||||
|
||||
+35
-20
@@ -112,12 +112,14 @@ pub fn output(value: u64, blinding: SecretKey) -> Box<Append> {
|
||||
let commit = build.secp.commit(value, blinding).unwrap();
|
||||
let nonce = build.secp.nonce();
|
||||
let rproof = build.secp.range_proof(0, value, blinding, commit, nonce);
|
||||
(tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
sum.add(blinding))
|
||||
(
|
||||
tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
sum.add(blinding),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -130,30 +132,38 @@ pub fn output_rand(value: u64) -> Box<Append> {
|
||||
let commit = build.secp.commit(value, blinding).unwrap();
|
||||
let nonce = build.secp.nonce();
|
||||
let rproof = build.secp.range_proof(0, value, blinding, commit, nonce);
|
||||
(tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
sum.add(blinding))
|
||||
(
|
||||
tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
sum.add(blinding),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the fee on the transaction being built.
|
||||
pub fn with_fee(fee: u64) -> Box<Append> {
|
||||
Box::new(move |_build, (tx, sum)| -> (Transaction, BlindSum) { (tx.with_fee(fee), sum) })
|
||||
Box::new(move |_build, (tx, sum)| -> (Transaction, BlindSum) {
|
||||
(tx.with_fee(fee), sum)
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets a known excess value on the transaction being built. Usually used in
|
||||
/// combination with the initial_tx function when a new transaction is built
|
||||
/// by adding to a pre-existing one.
|
||||
pub fn with_excess(excess: SecretKey) -> Box<Append> {
|
||||
Box::new(move |_build, (tx, sum)| -> (Transaction, BlindSum) { (tx, sum.add(excess)) })
|
||||
Box::new(move |_build, (tx, sum)| -> (Transaction, BlindSum) {
|
||||
(tx, sum.add(excess))
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets an initial transaction to add to when building a new transaction.
|
||||
pub fn initial_tx(tx: Transaction) -> Box<Append> {
|
||||
Box::new(move |_build, (_, sum)| -> (Transaction, BlindSum) { (tx.clone(), sum) })
|
||||
Box::new(move |_build, (_, sum)| -> (Transaction, BlindSum) {
|
||||
(tx.clone(), sum)
|
||||
})
|
||||
}
|
||||
|
||||
/// Builds a new transaction by combining all the combinators provided in a
|
||||
@@ -171,8 +181,10 @@ pub fn transaction(elems: Vec<Box<Append>>) -> Result<(Transaction, SecretKey),
|
||||
secp: Secp256k1::with_caps(secp::ContextFlag::Commit),
|
||||
rng: OsRng::new().unwrap(),
|
||||
};
|
||||
let (mut tx, sum) = elems.iter().fold((Transaction::empty(), BlindSum::new()),
|
||||
|acc, elem| elem(&mut ctx, acc));
|
||||
let (mut tx, sum) = elems.iter().fold(
|
||||
(Transaction::empty(), BlindSum::new()),
|
||||
|acc, elem| elem(&mut ctx, acc),
|
||||
);
|
||||
|
||||
let blind_sum = sum.sum(&ctx.secp)?;
|
||||
let msg = secp::Message::from_slice(&u64_to_32bytes(tx.fee))?;
|
||||
@@ -199,9 +211,12 @@ mod test {
|
||||
#[test]
|
||||
fn blind_simple_tx() {
|
||||
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
let (tx, _) =
|
||||
transaction(vec![input_rand(10), input_rand(11), output_rand(20), with_fee(1)])
|
||||
.unwrap();
|
||||
let (tx, _) = transaction(vec![
|
||||
input_rand(10),
|
||||
input_rand(11),
|
||||
output_rand(20),
|
||||
with_fee(1),
|
||||
]).unwrap();
|
||||
tx.verify_sig(&secp).unwrap();
|
||||
}
|
||||
#[test]
|
||||
|
||||
@@ -143,9 +143,9 @@ impl HashWriter {
|
||||
/// Consume the `HashWriter`, outputting a `Hash` corresponding to its
|
||||
/// current state
|
||||
pub fn into_hash(self) -> Hash {
|
||||
let mut res = [0; 32];
|
||||
let mut res = [0; 32];
|
||||
(&mut res).copy_from_slice(self.state.finalize().as_bytes());
|
||||
Hash(res)
|
||||
Hash(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-14
@@ -20,7 +20,7 @@ pub mod hash;
|
||||
pub mod pmmr;
|
||||
pub mod target;
|
||||
pub mod transaction;
|
||||
//pub mod txoset;
|
||||
// pub mod txoset;
|
||||
#[allow(dead_code)]
|
||||
|
||||
use std::fmt;
|
||||
@@ -82,7 +82,7 @@ pub trait Committed {
|
||||
/// Proof of work
|
||||
pub struct Proof {
|
||||
/// The nonces
|
||||
pub nonces:Vec<u32>,
|
||||
pub nonces: Vec<u32>,
|
||||
|
||||
/// The proof size
|
||||
pub proof_size: usize,
|
||||
@@ -125,9 +125,8 @@ impl Clone for Proof {
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
|
||||
/// Builds a proof with all bytes zeroed out
|
||||
pub fn new(in_nonces:Vec<u32>) -> Proof {
|
||||
pub fn new(in_nonces: Vec<u32>) -> Proof {
|
||||
Proof {
|
||||
proof_size: in_nonces.len(),
|
||||
nonces: in_nonces,
|
||||
@@ -135,10 +134,10 @@ impl Proof {
|
||||
}
|
||||
|
||||
/// Builds a proof with all bytes zeroed out
|
||||
pub fn zero(proof_size:usize) -> Proof {
|
||||
pub fn zero(proof_size: usize) -> Proof {
|
||||
Proof {
|
||||
proof_size: proof_size,
|
||||
nonces: vec![0;proof_size],
|
||||
nonces: vec![0; proof_size],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,9 +250,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn hash_output() {
|
||||
let (tx, _) =
|
||||
build::transaction(vec![input_rand(75), output_rand(42), output_rand(32), with_fee(1)])
|
||||
.unwrap();
|
||||
let (tx, _) = build::transaction(vec![
|
||||
input_rand(75),
|
||||
output_rand(42),
|
||||
output_rand(32),
|
||||
with_fee(1),
|
||||
]).unwrap();
|
||||
let h = tx.outputs[0].hash();
|
||||
assert!(h != ZERO_HASH);
|
||||
let h2 = tx.outputs[1].hash();
|
||||
@@ -309,9 +311,11 @@ mod test {
|
||||
// From now on, Bob only has the obscured transaction and the sum of
|
||||
// blinding factors. He adds his output, finalizes the transaction so it's
|
||||
// ready for broadcast.
|
||||
let (tx_final, _) =
|
||||
build::transaction(vec![initial_tx(tx_alice), with_excess(blind_sum), output_rand(5)])
|
||||
.unwrap();
|
||||
let (tx_final, _) = build::transaction(vec![
|
||||
initial_tx(tx_alice),
|
||||
with_excess(blind_sum),
|
||||
output_rand(5),
|
||||
]).unwrap();
|
||||
|
||||
tx_final.validate(&secp).unwrap();
|
||||
}
|
||||
@@ -357,8 +361,12 @@ mod test {
|
||||
|
||||
// utility producing a transaction with 2 inputs and a single outputs
|
||||
pub fn tx2i1o() -> Transaction {
|
||||
build::transaction(vec![input_rand(10), input_rand(11), output_rand(20), with_fee(1)])
|
||||
.map(|(tx, _)| tx)
|
||||
build::transaction(vec![
|
||||
input_rand(10),
|
||||
input_rand(11),
|
||||
output_rand(20),
|
||||
with_fee(1),
|
||||
]).map(|(tx, _)| tx)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
|
||||
+97
-40
@@ -15,7 +15,11 @@
|
||||
//! Persistent and prunable Merkle Mountain Range implementation. For a high
|
||||
//! level description of MMRs, see:
|
||||
//!
|
||||
//! https://github.com/opentimestamps/opentimestamps-server/blob/master/doc/merkle-mountain-range.md
|
||||
//! https://github.
|
||||
//! com/opentimestamps/opentimestamps-server/blob/master/doc/merkle-mountain-range.
|
||||
//!
|
||||
//!
|
||||
//! md
|
||||
//!
|
||||
//! This implementation is built in two major parts:
|
||||
//!
|
||||
@@ -91,7 +95,10 @@ impl<T> Summable for NoSum<T> {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
impl<T> Writeable for NoSum<T> where T: Writeable {
|
||||
impl<T> Writeable for NoSum<T>
|
||||
where
|
||||
T: Writeable,
|
||||
{
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
self.0.write(writer)
|
||||
}
|
||||
@@ -100,14 +107,20 @@ impl<T> Writeable for NoSum<T> where T: Writeable {
|
||||
/// A utility type to handle (Hash, Sum) pairs more conveniently. The addition
|
||||
/// of two HashSums is the (Hash(h1|h2), h1 + h2) HashSum.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HashSum<T> where T: Summable {
|
||||
pub struct HashSum<T>
|
||||
where
|
||||
T: Summable,
|
||||
{
|
||||
/// The hash
|
||||
pub hash: Hash,
|
||||
/// The sum
|
||||
pub sum: T::Sum,
|
||||
}
|
||||
|
||||
impl<T> HashSum<T> where T: Summable + Hashed {
|
||||
impl<T> HashSum<T>
|
||||
where
|
||||
T: Summable + Hashed,
|
||||
{
|
||||
/// Create a hash sum from a summable
|
||||
pub fn from_summable(idx: u64, elmt: &T) -> HashSum<T> {
|
||||
let hash = elmt.hash();
|
||||
@@ -120,7 +133,10 @@ impl<T> HashSum<T> where T: Summable + Hashed {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Readable for HashSum<T> where T: Summable {
|
||||
impl<T> Readable for HashSum<T>
|
||||
where
|
||||
T: Summable,
|
||||
{
|
||||
fn read(r: &mut Reader) -> Result<HashSum<T>, ser::Error> {
|
||||
Ok(HashSum {
|
||||
hash: Hash::read(r)?,
|
||||
@@ -129,14 +145,20 @@ impl<T> Readable for HashSum<T> where T: Summable {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Writeable for HashSum<T> where T: Summable {
|
||||
impl<T> Writeable for HashSum<T>
|
||||
where
|
||||
T: Summable,
|
||||
{
|
||||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ser::Error> {
|
||||
self.hash.write(w)?;
|
||||
self.sum.write(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Add for HashSum<T> where T: Summable {
|
||||
impl<T> ops::Add for HashSum<T>
|
||||
where
|
||||
T: Summable,
|
||||
{
|
||||
type Output = HashSum<T>;
|
||||
fn add(self, other: HashSum<T>) -> HashSum<T> {
|
||||
HashSum {
|
||||
@@ -150,8 +172,10 @@ impl<T> ops::Add for HashSum<T> where T: Summable {
|
||||
/// The PMMR itself does not need the Backend to be accurate on the existence
|
||||
/// of an element (i.e. remove could be a no-op) but layers above can
|
||||
/// depend on an accurate Backend to check existence.
|
||||
pub trait Backend<T> where T: Summable {
|
||||
|
||||
pub trait Backend<T>
|
||||
where
|
||||
T: Summable,
|
||||
{
|
||||
/// Append the provided HashSums to the backend storage. The position of the
|
||||
/// first element of the Vec in the MMR is provided to help the
|
||||
/// implementation.
|
||||
@@ -176,15 +200,22 @@ pub trait Backend<T> where T: Summable {
|
||||
/// Heavily relies on navigation operations within a binary tree. In particular,
|
||||
/// all the implementation needs to keep track of the MMR structure is how far
|
||||
/// we are in the sequence of nodes making up the MMR.
|
||||
pub struct PMMR<'a, T, B> where T: Summable, B: 'a + Backend<T> {
|
||||
pub struct PMMR<'a, T, B>
|
||||
where
|
||||
T: Summable,
|
||||
B: 'a + Backend<T>,
|
||||
{
|
||||
last_pos: u64,
|
||||
backend: &'a mut B,
|
||||
// only needed for parameterizing Backend
|
||||
summable: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backend<T> {
|
||||
|
||||
impl<'a, T, B> PMMR<'a, T, B>
|
||||
where
|
||||
T: Summable + Hashed + Clone,
|
||||
B: 'a + Backend<T>,
|
||||
{
|
||||
/// Build a new prunable Merkle Mountain Range using the provided backend.
|
||||
pub fn new(backend: &'a mut B) -> PMMR<T, B> {
|
||||
PMMR {
|
||||
@@ -194,7 +225,8 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a new prunable Merkle Mountain Range pre-initlialized until last_pos
|
||||
/// Build a new prunable Merkle Mountain Range pre-initlialized until
|
||||
/// last_pos
|
||||
/// with the provided backend.
|
||||
pub fn at(backend: &'a mut B, last_pos: u64) -> PMMR<T, B> {
|
||||
PMMR {
|
||||
@@ -215,7 +247,7 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
ret = match (ret, peak) {
|
||||
(None, x) => x,
|
||||
(Some(hsum), None) => Some(hsum),
|
||||
(Some(lhsum), Some(rhsum)) => Some(lhsum + rhsum)
|
||||
(Some(lhsum), Some(rhsum)) => Some(lhsum + rhsum),
|
||||
}
|
||||
}
|
||||
ret.expect("no root, invalid tree")
|
||||
@@ -234,10 +266,11 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
// height it means we have to build a higher peak by summing with a previous
|
||||
// sibling. we do it iteratively in case the new peak itself allows the
|
||||
// creation of another parent.
|
||||
while bintree_postorder_height(pos+1) > height {
|
||||
while bintree_postorder_height(pos + 1) > height {
|
||||
let left_sibling = bintree_jump_left_sibling(pos);
|
||||
let left_hashsum = self.backend.get(left_sibling)
|
||||
.expect("missing left sibling in tree, should not have been pruned");
|
||||
let left_hashsum = self.backend.get(left_sibling).expect(
|
||||
"missing left sibling in tree, should not have been pruned",
|
||||
);
|
||||
current_hashsum = left_hashsum + current_hashsum;
|
||||
|
||||
to_append.push(current_hashsum.clone());
|
||||
@@ -259,7 +292,7 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
// position is a leaf, which may had some parent that needs to exist
|
||||
// afterward for the MMR to be valid
|
||||
let mut pos = position;
|
||||
while bintree_postorder_height(pos+1) > 0 {
|
||||
while bintree_postorder_height(pos + 1) > 0 {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
@@ -268,13 +301,14 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prune an element from the tree given its position. Note that to be able to
|
||||
/// Prune an element from the tree given its position. Note that to be able
|
||||
/// to
|
||||
/// provide that position and prune, consumers of this API are expected to
|
||||
/// keep an index of elements to positions in the tree. Prunes parent
|
||||
/// nodes as well when they become childless.
|
||||
pub fn prune(&mut self, position: u64, index: u32) -> Result<bool, String> {
|
||||
if let None = self.backend.get(position) {
|
||||
return Ok(false)
|
||||
return Ok(false);
|
||||
}
|
||||
let prunable_height = bintree_postorder_height(position);
|
||||
if prunable_height > 0 {
|
||||
@@ -286,7 +320,7 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
// the tree.
|
||||
let mut to_prune = vec![];
|
||||
let mut current = position;
|
||||
while current+1 < self.last_pos {
|
||||
while current + 1 < self.last_pos {
|
||||
let (parent, sibling) = family(current);
|
||||
if parent > self.last_pos {
|
||||
// can't prune when our parent isn't here yet
|
||||
@@ -330,7 +364,7 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
print!("{:>8} ", n + 1);
|
||||
}
|
||||
println!("");
|
||||
for n in 1..(sz+1) {
|
||||
for n in 1..(sz + 1) {
|
||||
let ohs = self.get(n);
|
||||
match ohs {
|
||||
Some(hs) => print!("{} ", hs.hash),
|
||||
@@ -345,36 +379,45 @@ impl<'a, T, B> PMMR<'a, T, B> where T: Summable + Hashed + Clone, B: 'a + Backen
|
||||
/// compact the Vector itself but still frees the reference to the
|
||||
/// underlying HashSum.
|
||||
#[derive(Clone)]
|
||||
pub struct VecBackend<T> where T: Summable + Clone {
|
||||
pub struct VecBackend<T>
|
||||
where
|
||||
T: Summable + Clone,
|
||||
{
|
||||
pub elems: Vec<Option<HashSum<T>>>,
|
||||
}
|
||||
|
||||
impl<T> Backend<T> for VecBackend<T> where T: Summable + Clone {
|
||||
impl<T> Backend<T> for VecBackend<T>
|
||||
where
|
||||
T: Summable + Clone,
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn append(&mut self, position: u64, data: Vec<HashSum<T>>) -> Result<(), String> {
|
||||
self.elems.append(&mut map_vec!(data, |d| Some(d.clone())));
|
||||
Ok(())
|
||||
}
|
||||
fn get(&self, position: u64) -> Option<HashSum<T>> {
|
||||
self.elems[(position-1) as usize].clone()
|
||||
self.elems[(position - 1) as usize].clone()
|
||||
}
|
||||
fn remove(&mut self, positions: Vec<u64>, index: u32) -> Result<(), String> {
|
||||
for n in positions {
|
||||
self.elems[(n-1) as usize] = None
|
||||
self.elems[(n - 1) as usize] = None
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn rewind(&mut self, position: u64, index: u32) -> Result<(), String> {
|
||||
self.elems = self.elems[0..(position as usize)+1].to_vec();
|
||||
self.elems = self.elems[0..(position as usize) + 1].to_vec();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VecBackend<T> where T: Summable + Clone {
|
||||
impl<T> VecBackend<T>
|
||||
where
|
||||
T: Summable + Clone,
|
||||
{
|
||||
/// Instantiates a new VecBackend<T>
|
||||
pub fn new() -> VecBackend<T> {
|
||||
VecBackend{elems: vec![]}
|
||||
VecBackend { elems: vec![] }
|
||||
}
|
||||
|
||||
/// Current number of HashSum elements in the underlying Vec.
|
||||
@@ -418,7 +461,7 @@ pub struct PruneList {
|
||||
impl PruneList {
|
||||
/// Instantiate a new empty prune list
|
||||
pub fn new() -> PruneList {
|
||||
PruneList{pruned_nodes: vec![]}
|
||||
PruneList { pruned_nodes: vec![] }
|
||||
}
|
||||
|
||||
/// Computes by how many positions a node at pos should be shifted given the
|
||||
@@ -501,7 +544,7 @@ fn peaks(num: u64) -> Vec<u64> {
|
||||
|
||||
// detecting an invalid mountain range, when siblings exist but no parent
|
||||
// exists
|
||||
if bintree_postorder_height(num+1) > bintree_postorder_height(num) {
|
||||
if bintree_postorder_height(num + 1) > bintree_postorder_height(num) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
@@ -616,7 +659,7 @@ pub fn family(pos: u64) -> (u64, u64) {
|
||||
let parent: u64;
|
||||
|
||||
let pos_height = bintree_postorder_height(pos);
|
||||
let next_height = bintree_postorder_height(pos+1);
|
||||
let next_height = bintree_postorder_height(pos + 1);
|
||||
if next_height > pos_height {
|
||||
sibling = bintree_jump_left_sibling(pos);
|
||||
parent = pos + 1;
|
||||
@@ -710,15 +753,19 @@ mod test {
|
||||
#[test]
|
||||
#[allow(unused_variables)]
|
||||
fn first_50_mmr_heights() {
|
||||
let first_100_str =
|
||||
"0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 \
|
||||
let first_100_str = "0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 \
|
||||
0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 5 \
|
||||
0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 0 0 1 0 0";
|
||||
let first_100 = first_100_str.split(' ').map(|n| n.parse::<u64>().unwrap());
|
||||
let mut count = 1;
|
||||
for n in first_100 {
|
||||
assert_eq!(n, bintree_postorder_height(count), "expected {}, got {}",
|
||||
n, bintree_postorder_height(count));
|
||||
assert_eq!(
|
||||
n,
|
||||
bintree_postorder_height(count),
|
||||
"expected {}, got {}",
|
||||
n,
|
||||
bintree_postorder_height(count)
|
||||
);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
@@ -785,7 +832,13 @@ mod test {
|
||||
let hash = Hashed::hash(&elems[0]);
|
||||
let sum = elems[0].sum();
|
||||
let node_hash = (1 as u64, &sum, hash).hash();
|
||||
assert_eq!(pmmr.root(), HashSum{hash: node_hash, sum: sum});
|
||||
assert_eq!(
|
||||
pmmr.root(),
|
||||
HashSum {
|
||||
hash: node_hash,
|
||||
sum: sum,
|
||||
}
|
||||
);
|
||||
assert_eq!(pmmr.unpruned_size(), 1);
|
||||
|
||||
// two elements
|
||||
@@ -802,7 +855,8 @@ mod test {
|
||||
|
||||
// four elements
|
||||
pmmr.push(elems[3]).unwrap();
|
||||
let sum4 = sum2 + (HashSum::from_summable(4, &elems[2]) + HashSum::from_summable(5, &elems[3]));
|
||||
let sum4 = sum2 +
|
||||
(HashSum::from_summable(4, &elems[2]) + HashSum::from_summable(5, &elems[3]));
|
||||
assert_eq!(pmmr.root(), sum4);
|
||||
assert_eq!(pmmr.unpruned_size(), 7);
|
||||
|
||||
@@ -814,7 +868,8 @@ mod test {
|
||||
|
||||
// six elements
|
||||
pmmr.push(elems[5]).unwrap();
|
||||
let sum6 = sum4.clone() + (HashSum::from_summable(8, &elems[4]) + HashSum::from_summable(9, &elems[5]));
|
||||
let sum6 = sum4.clone() +
|
||||
(HashSum::from_summable(8, &elems[4]) + HashSum::from_summable(9, &elems[5]));
|
||||
assert_eq!(pmmr.root(), sum6.clone());
|
||||
assert_eq!(pmmr.unpruned_size(), 10);
|
||||
|
||||
@@ -826,7 +881,9 @@ mod test {
|
||||
|
||||
// eight elements
|
||||
pmmr.push(elems[7]).unwrap();
|
||||
let sum8 = sum4 + ((HashSum::from_summable(8, &elems[4]) + HashSum::from_summable(9, &elems[5])) + (HashSum::from_summable(11, &elems[6]) + HashSum::from_summable(12, &elems[7])));
|
||||
let sum8 = sum4 +
|
||||
((HashSum::from_summable(8, &elems[4]) + HashSum::from_summable(9, &elems[5])) +
|
||||
(HashSum::from_summable(11, &elems[6]) + HashSum::from_summable(12, &elems[7])));
|
||||
assert_eq!(pmmr.root(), sum8);
|
||||
assert_eq!(pmmr.unpruned_size(), 15);
|
||||
|
||||
|
||||
+14
-8
@@ -59,8 +59,8 @@ impl Difficulty {
|
||||
/// provided hash.
|
||||
pub fn from_hash(h: &Hash) -> Difficulty {
|
||||
let max_target = BigEndian::read_u64(&MAX_TARGET);
|
||||
//Use the first 64 bits of the given hash
|
||||
let mut in_vec=h.to_vec();
|
||||
// Use the first 64 bits of the given hash
|
||||
let mut in_vec = h.to_vec();
|
||||
in_vec.truncate(8);
|
||||
let num = BigEndian::read_u64(&in_vec);
|
||||
Difficulty { num: max_target / num }
|
||||
@@ -121,7 +121,8 @@ impl Readable for Difficulty {
|
||||
|
||||
impl Serialize for Difficulty {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_u64(self.num)
|
||||
}
|
||||
@@ -129,7 +130,8 @@ impl Serialize for Difficulty {
|
||||
|
||||
impl<'de> Deserialize<'de> for Difficulty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Difficulty, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_u64(DiffVisitor)
|
||||
}
|
||||
@@ -145,12 +147,16 @@ impl<'de> de::Visitor<'de> for DiffVisitor {
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let num_in = s.parse::<u64>();
|
||||
if let Err(_)=num_in {
|
||||
return Err(de::Error::invalid_value(de::Unexpected::Str(s), &"a value number"));
|
||||
};
|
||||
if let Err(_) = num_in {
|
||||
return Err(de::Error::invalid_value(
|
||||
de::Unexpected::Str(s),
|
||||
&"a value number",
|
||||
));
|
||||
};
|
||||
Ok(Difficulty { num: num_in.unwrap() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +54,13 @@ pub struct TxKernel {
|
||||
|
||||
impl Writeable for TxKernel {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u8, self.features.bits()],
|
||||
[write_fixed_bytes, &self.excess],
|
||||
[write_bytes, &self.excess_sig],
|
||||
[write_u64, self.fee]);
|
||||
ser_multiwrite!(
|
||||
writer,
|
||||
[write_u8, self.features.bits()],
|
||||
[write_fixed_bytes, &self.excess],
|
||||
[write_bytes, &self.excess_sig],
|
||||
[write_u64, self.fee]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -66,8 +68,9 @@ impl Writeable for TxKernel {
|
||||
impl Readable for TxKernel {
|
||||
fn read(reader: &mut Reader) -> Result<TxKernel, ser::Error> {
|
||||
Ok(TxKernel {
|
||||
features:
|
||||
KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
|
||||
features: KernelFeatures::from_bits(reader.read_u8()?).ok_or(
|
||||
ser::Error::CorruptedData,
|
||||
)?,
|
||||
excess: Commitment::read(reader)?,
|
||||
excess_sig: reader.read_vec()?,
|
||||
fee: reader.read_u64()?,
|
||||
@@ -104,11 +107,13 @@ pub struct Transaction {
|
||||
/// write the transaction as binary.
|
||||
impl Writeable for Transaction {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.fee],
|
||||
[write_bytes, &self.excess_sig],
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64]);
|
||||
ser_multiwrite!(
|
||||
writer,
|
||||
[write_u64, self.fee],
|
||||
[write_bytes, &self.excess_sig],
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64]
|
||||
);
|
||||
for inp in &self.inputs {
|
||||
try!(inp.write(writer));
|
||||
}
|
||||
@@ -185,7 +190,10 @@ impl Transaction {
|
||||
pub fn with_input(self, input: Input) -> Transaction {
|
||||
let mut new_ins = self.inputs;
|
||||
new_ins.push(input);
|
||||
Transaction { inputs: new_ins, ..self }
|
||||
Transaction {
|
||||
inputs: new_ins,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a new transaction with the provided output added. Existing
|
||||
@@ -193,7 +201,10 @@ impl Transaction {
|
||||
pub fn with_output(self, output: Output) -> Transaction {
|
||||
let mut new_outs = self.outputs;
|
||||
new_outs.push(output);
|
||||
Transaction { outputs: new_outs, ..self }
|
||||
Transaction {
|
||||
outputs: new_outs,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a new transaction with the provided fee.
|
||||
@@ -304,9 +315,11 @@ pub struct Output {
|
||||
/// an Output as binary.
|
||||
impl Writeable for Output {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u8, self.features.bits()],
|
||||
[write_fixed_bytes, &self.commit]);
|
||||
ser_multiwrite!(
|
||||
writer,
|
||||
[write_u8, self.features.bits()],
|
||||
[write_fixed_bytes, &self.commit]
|
||||
);
|
||||
// The hash of an output doesn't include the range proof
|
||||
if writer.serialization_mode() == ser::SerializationMode::Full {
|
||||
writer.write_bytes(&self.proof)?
|
||||
@@ -320,8 +333,9 @@ impl Writeable for Output {
|
||||
impl Readable for Output {
|
||||
fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
|
||||
Ok(Output {
|
||||
features:
|
||||
OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
|
||||
features: OutputFeatures::from_bits(reader.read_u8()?).ok_or(
|
||||
ser::Error::CorruptedData,
|
||||
)?,
|
||||
commit: Commitment::read(reader)?,
|
||||
proof: RangeProof::read(reader)?,
|
||||
})
|
||||
@@ -341,8 +355,6 @@ impl Output {
|
||||
|
||||
/// Validates the range proof using the commitment
|
||||
pub fn verify_proof(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
/// secp.verify_range_proof returns range if and only if both min_value and max_value less than 2^64
|
||||
/// since group order is much larger (~2^256) we can be sure overflow is not the case
|
||||
secp.verify_range_proof(self.commit, self.proof).map(|_| ())
|
||||
}
|
||||
}
|
||||
@@ -392,7 +404,10 @@ impl ops::Add for SumCommit {
|
||||
type Output = SumCommit;
|
||||
|
||||
fn add(self, other: SumCommit) -> SumCommit {
|
||||
let sum = match self.secp.commit_sum(vec![self.commit.clone(), other.commit.clone()], vec![]) {
|
||||
let sum = match self.secp.commit_sum(
|
||||
vec![self.commit.clone(), other.commit.clone()],
|
||||
vec![],
|
||||
) {
|
||||
Ok(s) => s,
|
||||
Err(_) => Commitment::from_vec(vec![1; 33]),
|
||||
};
|
||||
|
||||
+74
-31
@@ -21,7 +21,7 @@
|
||||
/// different sets of parameters for different purposes,
|
||||
/// e.g. CI, User testing, production values
|
||||
|
||||
use std::sync::{RwLock};
|
||||
use std::sync::RwLock;
|
||||
use consensus::PROOFSIZE;
|
||||
use consensus::DEFAULT_SIZESHIFT;
|
||||
|
||||
@@ -29,16 +29,16 @@ use consensus::DEFAULT_SIZESHIFT;
|
||||
/// by users
|
||||
|
||||
/// Automated testing sizeshift
|
||||
pub const AUTOMATED_TESTING_SIZESHIFT:u8 = 10;
|
||||
pub const AUTOMATED_TESTING_SIZESHIFT: u8 = 10;
|
||||
|
||||
/// Automated testing proof size
|
||||
pub const AUTOMATED_TESTING_PROOF_SIZE:usize = 4;
|
||||
pub const AUTOMATED_TESTING_PROOF_SIZE: usize = 4;
|
||||
|
||||
/// User testing sizeshift
|
||||
pub const USER_TESTING_SIZESHIFT:u8 = 16;
|
||||
pub const USER_TESTING_SIZESHIFT: u8 = 16;
|
||||
|
||||
/// User testing proof size
|
||||
pub const USER_TESTING_PROOF_SIZE:usize = 42;
|
||||
pub const USER_TESTING_PROOF_SIZE: usize = 42;
|
||||
|
||||
/// Mining parameter modes
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -55,18 +55,19 @@ pub enum MiningParameterMode {
|
||||
|
||||
lazy_static!{
|
||||
/// The mining parameter mode
|
||||
pub static ref MINING_PARAMETER_MODE: RwLock<MiningParameterMode> = RwLock::new(MiningParameterMode::Production);
|
||||
pub static ref MINING_PARAMETER_MODE: RwLock<MiningParameterMode> =
|
||||
RwLock::new(MiningParameterMode::Production);
|
||||
}
|
||||
|
||||
/// Set the mining mode
|
||||
pub fn set_mining_mode(mode:MiningParameterMode){
|
||||
let mut param_ref=MINING_PARAMETER_MODE.write().unwrap();
|
||||
*param_ref=mode;
|
||||
pub fn set_mining_mode(mode: MiningParameterMode) {
|
||||
let mut param_ref = MINING_PARAMETER_MODE.write().unwrap();
|
||||
*param_ref = mode;
|
||||
}
|
||||
|
||||
/// The sizeshift
|
||||
pub fn sizeshift() -> u8 {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
let param_ref = MINING_PARAMETER_MODE.read().unwrap();
|
||||
match *param_ref {
|
||||
MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_SIZESHIFT,
|
||||
MiningParameterMode::UserTesting => USER_TESTING_SIZESHIFT,
|
||||
@@ -76,7 +77,7 @@ pub fn sizeshift() -> u8 {
|
||||
|
||||
/// The proofsize
|
||||
pub fn proofsize() -> usize {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
let param_ref = MINING_PARAMETER_MODE.read().unwrap();
|
||||
match *param_ref {
|
||||
MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE,
|
||||
MiningParameterMode::UserTesting => USER_TESTING_PROOF_SIZE,
|
||||
@@ -86,8 +87,8 @@ pub fn proofsize() -> usize {
|
||||
|
||||
/// Are we in automated testing mode?
|
||||
pub fn is_automated_testing_mode() -> bool {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
if let MiningParameterMode::AutomatedTesting=*param_ref {
|
||||
let param_ref = MINING_PARAMETER_MODE.read().unwrap();
|
||||
if let MiningParameterMode::AutomatedTesting = *param_ref {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -96,8 +97,8 @@ pub fn is_automated_testing_mode() -> bool {
|
||||
|
||||
/// Are we in production mode?
|
||||
pub fn is_production_mode() -> bool {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
if let MiningParameterMode::Production=*param_ref {
|
||||
let param_ref = MINING_PARAMETER_MODE.read().unwrap();
|
||||
if let MiningParameterMode::Production = *param_ref {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -105,30 +106,72 @@ pub fn is_production_mode() -> bool {
|
||||
}
|
||||
|
||||
|
||||
/// Helper function to get a nonce known to create a valid POW on
|
||||
/// Helper function to get a nonce known to create a valid POW on
|
||||
/// the genesis block, to prevent it taking ages. Should be fine for now
|
||||
/// as the genesis block POW solution turns out to be the same for every new block chain
|
||||
/// as the genesis block POW solution turns out to be the same for every new
|
||||
/// block chain
|
||||
/// at the moment
|
||||
|
||||
pub fn get_genesis_nonce() -> u64 {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
let param_ref = MINING_PARAMETER_MODE.read().unwrap();
|
||||
match *param_ref {
|
||||
MiningParameterMode::AutomatedTesting => 0, //won't make a difference
|
||||
MiningParameterMode::UserTesting => 22141, //Magic nonce for current genesis block at cuckoo16
|
||||
MiningParameterMode::Production => 1429942738856787200, //Magic nonce for current genesis at cuckoo30
|
||||
// won't make a difference
|
||||
MiningParameterMode::AutomatedTesting => 0,
|
||||
// Magic nonce for current genesis block at cuckoo16
|
||||
MiningParameterMode::UserTesting => 22141,
|
||||
// Magic nonce for current genesis at cuckoo30
|
||||
MiningParameterMode::Production => 1429942738856787200,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the genesis POW for production, because it takes far too long to mine at production values
|
||||
/// Returns the genesis POW for production, because it takes far too long to
|
||||
/// mine at production values
|
||||
/// using the internal miner
|
||||
|
||||
pub fn get_genesis_pow() -> [u32;42]{
|
||||
//TODO: This is diff 26, probably just want a 10: mine one
|
||||
[7444824, 11926557, 28520390, 30594072, 50854023, 52797085, 57882033,
|
||||
59816511, 61404804, 84947619, 87779345, 115270337, 162618676,
|
||||
166860710, 178656003, 178971372, 200454733, 209197630, 221231015,
|
||||
228598741, 241012783, 245401183, 279080304, 295848517, 327300943,
|
||||
329741709, 366394532, 382493153, 389329248, 404353381, 406012911,
|
||||
418813499, 426573907, 452566575, 456930760, 463021458, 474340589,
|
||||
476248039, 478197093, 487576917, 495653489, 501862896]
|
||||
pub fn get_genesis_pow() -> [u32; 42] {
|
||||
// TODO: This is diff 26, probably just want a 10: mine one
|
||||
[
|
||||
7444824,
|
||||
11926557,
|
||||
28520390,
|
||||
30594072,
|
||||
50854023,
|
||||
52797085,
|
||||
57882033,
|
||||
59816511,
|
||||
61404804,
|
||||
84947619,
|
||||
87779345,
|
||||
115270337,
|
||||
162618676,
|
||||
166860710,
|
||||
178656003,
|
||||
178971372,
|
||||
200454733,
|
||||
209197630,
|
||||
221231015,
|
||||
228598741,
|
||||
241012783,
|
||||
245401183,
|
||||
279080304,
|
||||
295848517,
|
||||
327300943,
|
||||
329741709,
|
||||
366394532,
|
||||
382493153,
|
||||
389329248,
|
||||
404353381,
|
||||
406012911,
|
||||
418813499,
|
||||
426573907,
|
||||
452566575,
|
||||
456930760,
|
||||
463021458,
|
||||
474340589,
|
||||
476248039,
|
||||
478197093,
|
||||
487576917,
|
||||
495653489,
|
||||
501862896,
|
||||
]
|
||||
}
|
||||
|
||||
+35
-16
@@ -55,9 +55,10 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::IOErr(ref e) => write!(f, "{}", e),
|
||||
Error::UnexpectedData { expected: ref e, received: ref r } => {
|
||||
write!(f, "expected {:?}, got {:?}", e, r)
|
||||
}
|
||||
Error::UnexpectedData {
|
||||
expected: ref e,
|
||||
received: ref r,
|
||||
} => write!(f, "expected {:?}, got {:?}", e, r),
|
||||
Error::CorruptedData => f.write_str("corrupted data"),
|
||||
Error::TooLargeReadErr => f.write_str("too large read"),
|
||||
}
|
||||
@@ -75,7 +76,10 @@ impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::IOErr(ref e) => error::Error::description(e),
|
||||
Error::UnexpectedData { expected: _, received: _ } => "unexpected data",
|
||||
Error::UnexpectedData {
|
||||
expected: _,
|
||||
received: _,
|
||||
} => "unexpected data",
|
||||
Error::CorruptedData => "corrupted data",
|
||||
Error::TooLargeReadErr => "too large read",
|
||||
}
|
||||
@@ -180,7 +184,8 @@ pub trait Writeable {
|
||||
/// Reads directly to a Reader, a utility type thinly wrapping an
|
||||
/// underlying Read implementation.
|
||||
pub trait Readable
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Reads the data necessary to this Readable from the provided reader
|
||||
fn read(reader: &mut Reader) -> Result<Self, Error>;
|
||||
@@ -245,7 +250,9 @@ impl<'a> Reader for BinReader<'a> {
|
||||
return Err(Error::TooLargeReadErr);
|
||||
}
|
||||
let mut buf = vec![0; length];
|
||||
self.source.read_exact(&mut buf).map(move |_| buf).map_err(Error::IOErr)
|
||||
self.source.read_exact(&mut buf).map(move |_| buf).map_err(
|
||||
Error::IOErr,
|
||||
)
|
||||
}
|
||||
|
||||
fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
|
||||
@@ -338,14 +345,19 @@ impl_int!(u32, write_u32, read_u32);
|
||||
impl_int!(u64, write_u64, read_u64);
|
||||
impl_int!(i64, write_i64, read_i64);
|
||||
|
||||
impl<T> Readable for Vec<T> where T: Readable {
|
||||
impl<T> Readable for Vec<T>
|
||||
where
|
||||
T: Readable,
|
||||
{
|
||||
fn read(reader: &mut Reader) -> Result<Vec<T>, Error> {
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
let elem = T::read(reader);
|
||||
match elem {
|
||||
Ok(e) => buf.push(e),
|
||||
Err(Error::IOErr(ref ioerr)) if ioerr.kind() == io::ErrorKind::UnexpectedEof => break,
|
||||
Err(Error::IOErr(ref ioerr)) if ioerr.kind() == io::ErrorKind::UnexpectedEof => {
|
||||
break
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
@@ -353,7 +365,10 @@ impl<T> Readable for Vec<T> where T: Readable {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Writeable for Vec<T> where T: Writeable {
|
||||
impl<T> Writeable for Vec<T>
|
||||
where
|
||||
T: Writeable,
|
||||
{
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
for elmt in self {
|
||||
elmt.write(writer)?;
|
||||
@@ -400,18 +415,22 @@ impl<A: Writeable, B: Writeable, C: Writeable, D: Writeable> Writeable for (A, B
|
||||
|
||||
impl<A: Readable, B: Readable, C: Readable> Readable for (A, B, C) {
|
||||
fn read(reader: &mut Reader) -> Result<(A, B, C), Error> {
|
||||
Ok((try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader))))
|
||||
Ok((
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Readable, B: Readable, C: Readable, D: Readable> Readable for (A, B, C, D) {
|
||||
fn read(reader: &mut Reader) -> Result<(A, B, C, D), Error> {
|
||||
Ok((try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader))))
|
||||
Ok((
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
try!(Readable::read(reader)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user