[Floonet] add feature for height locked kernels (#2168)

* add feature for height locked kernels

* add function to compute kernel features appropriate for lock height, and use it

* only sign kernel-features relevant fields; refactor Features

* simplify invalid kernel logic

* remove unused height arg to reward::output and run some rustfmt

* replace nested if/else by match
This commit is contained in:
John Tromp 2018-12-18 19:26:34 +01:00 committed by Yeastplume
parent aa9da6838b
commit f43df5f601
26 changed files with 175 additions and 124 deletions

View file

@ -44,8 +44,8 @@ pub fn get_output(
// For now we can just try both (but this probably needs to be part of the api
// params)
let outputs = [
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, &commit),
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, &commit),
OutputIdentifier::new(OutputFeatures::PLAIN, &commit),
OutputIdentifier::new(OutputFeatures::COINBASE, &commit),
];
for x in outputs.iter() {

View file

@ -251,10 +251,7 @@ impl OutputPrintable {
block_header: Option<&core::BlockHeader>,
include_proof: bool,
) -> OutputPrintable {
let output_type = if output
.features
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
{
let output_type = if output.is_coinbase() {
OutputType::Coinbase
} else {
OutputType::Transaction
@ -278,11 +275,7 @@ impl OutputPrintable {
// We require the rewind() to be stable even after the PMMR is pruned and
// compacted so we can still recreate the necessary proof.
let mut merkle_proof = None;
if output
.features
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
&& !spent && block_header.is_some()
{
if output.is_coinbase() && !spent && block_header.is_some() {
merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok()
};

View file

@ -16,7 +16,7 @@
use crate::core::core::hash::Hash;
use crate::core::core::pmmr::{self, ReadonlyPMMR};
use crate::core::core::{Block, BlockHeader, Input, Output, OutputFeatures, Transaction};
use crate::core::core::{Block, BlockHeader, Input, Output, Transaction};
use crate::core::global;
use crate::core::ser::PMMRIndexHashable;
use crate::error::{Error, ErrorKind};
@ -105,7 +105,7 @@ impl<'a> UTXOView<'a> {
// outputs we are attempting to spend.
let pos = inputs
.iter()
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
.filter(|x| x.is_coinbase())
.filter_map(|x| self.batch.get_output_pos(&x.commitment()).ok())
.max()
.unwrap_or(0);

View file

@ -83,7 +83,7 @@ fn data_files() {
let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
.unwrap();
@ -159,7 +159,7 @@ fn _prepare_block_nosum(
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap();
let reward = libtx::reward::output(kc, &key_id, fees).unwrap();
let mut b = match core::core::Block::new(
prev,
txs.into_iter().cloned().collect(),

View file

@ -70,7 +70,7 @@ fn mine_genesis_reward_chain() {
let mut genesis = genesis::genesis_dev();
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
let reward = reward::output(&keychain, &key_id, 0, 0).unwrap();
let reward = reward::output(&keychain, &key_id, 0).unwrap();
genesis = genesis.with_reward(reward.0, reward.1);
{
@ -103,7 +103,7 @@ where
let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(keychain, &pk, 0, prev.height).unwrap();
let reward = libtx::reward::output(keychain, &pk, 0).unwrap();
let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
.unwrap();
@ -283,7 +283,7 @@ fn spend_in_fork_and_compact() {
// so we can spend the coinbase later
let b = prepare_block(&kc, &fork_head, &chain, 2);
let out_id = OutputIdentifier::from_output(&b.outputs()[0]);
assert!(out_id.features.contains(OutputFeatures::COINBASE_OUTPUT));
assert!(out_id.features.is_coinbase());
fork_head = b.header.clone();
chain
.process_block(b.clone(), chain::Options::SKIP_POW)
@ -411,7 +411,7 @@ fn output_header_mappings() {
let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
reward_outputs.push(reward.0.clone());
let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
@ -511,7 +511,7 @@ where
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap();
let reward = libtx::reward::output(kc, &key_id, fees).unwrap();
let mut b = match core::core::Block::new(
prev,
txs.into_iter().cloned().collect(),

View file

@ -62,7 +62,7 @@ fn test_various_store_indices() {
setup_chain(&genesis, chain_store.clone()).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, 0, 1).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let block = Block::new(&genesis.header, vec![], Difficulty::min(), reward).unwrap();
let block_hash = block.hash();

View file

@ -14,7 +14,6 @@
use self::chain::types::NoopAdapter;
use self::chain::ErrorKind;
use self::core::core::transaction;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::global::{self, ChainTypes};
use self::core::libtx::{self, build};
@ -68,7 +67,7 @@ fn test_coinbase_maturity() {
let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let reward = libtx::reward::output(&keychain, &key_id1, 0, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id1, 0).unwrap();
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
block.header.timestamp = prev.timestamp + Duration::seconds(60);
block.header.pow.secondary_scaling = next_header_info.secondary_scaling;
@ -85,9 +84,7 @@ fn test_coinbase_maturity() {
assert_eq!(block.outputs().len(), 1);
let coinbase_output = block.outputs()[0];
assert!(coinbase_output
.features
.contains(transaction::OutputFeatures::COINBASE_OUTPUT));
assert!(coinbase_output.is_coinbase());
chain
.process_block(block.clone(), chain::Options::MINE)
@ -114,7 +111,7 @@ fn test_coinbase_maturity() {
let txs = vec![coinbase_txn.clone()];
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id3, fees, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id3, fees).unwrap();
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
block.header.timestamp = prev.timestamp + Duration::seconds(60);
@ -148,7 +145,7 @@ fn test_coinbase_maturity() {
let keychain = ExtKeychain::from_random_seed().unwrap();
let pk = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
block.header.timestamp = prev.timestamp + Duration::seconds(60);
@ -176,7 +173,7 @@ fn test_coinbase_maturity() {
let txs = vec![coinbase_txn];
let fees = txs.iter().map(|tx| tx.fee()).sum();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let reward = libtx::reward::output(&keychain, &key_id4, fees, prev.height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id4, fees).unwrap();
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
block.header.timestamp = prev.timestamp + Duration::seconds(60);

View file

@ -28,7 +28,7 @@ use crate::core::compact_block::{CompactBlock, CompactBlockBody};
use crate::core::hash::{Hash, Hashed, ZERO_HASH};
use crate::core::verifier_cache::VerifierCache;
use crate::core::{
transaction, Commitment, Input, KernelFeatures, Output, OutputFeatures, Transaction,
transaction, Commitment, Input, Output, Transaction,
TransactionBody, TxKernel,
};
use crate::global;
@ -663,14 +663,14 @@ impl Block {
.body
.outputs
.iter()
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT))
.filter(|out| out.is_coinbase())
.collect::<Vec<&Output>>();
let cb_kerns = self
.body
.kernels
.iter()
.filter(|kernel| kernel.features.contains(KernelFeatures::COINBASE_KERNEL))
.filter(|kernel| kernel.is_coinbase())
.collect::<Vec<&TxKernel>>();
{

View file

@ -19,7 +19,7 @@ use rand::{thread_rng, Rng};
use crate::core::block::{Block, BlockHeader, Error};
use crate::core::hash::Hashed;
use crate::core::id::ShortIdentifiable;
use crate::core::{KernelFeatures, Output, OutputFeatures, ShortId, TxKernel};
use crate::core::{Output, ShortId, TxKernel};
use crate::ser::{self, read_multi, Readable, Reader, VerifySortedAndUnique, Writeable, Writer};
/// Container for full (full) outputs and kernels and kern_ids for a compact block.
@ -168,7 +168,7 @@ impl From<Block> for CompactBlock {
let out_full = block
.outputs()
.iter()
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
.filter(|x| x.is_coinbase())
.cloned()
.collect::<Vec<_>>();
@ -176,7 +176,7 @@ impl From<Block> for CompactBlock {
let mut kern_ids = vec![];
for k in block.kernels() {
if k.features.contains(KernelFeatures::COINBASE_KERNEL) {
if k.is_coinbase() {
kern_full.push(k.clone());
} else {
kern_ids.push(k.short_id(&header.hash(), nonce));

View file

@ -40,10 +40,12 @@ bitflags! {
/// Options for a kernel's structure or use
#[derive(Serialize, Deserialize)]
pub struct KernelFeatures: u8 {
/// No flags
const DEFAULT_KERNEL = 0b00000000;
/// Kernel matching a coinbase output
const COINBASE_KERNEL = 0b00000001;
/// plain kernel has fee, but no lock_height
const PLAIN = 0;
/// coinbase kernel has neither fee nor lock_height (both zero)
const COINBASE = 1;
/// absolute height locked kernel; has fee and lock_height
const HEIGHT_LOCKED = 2;
}
}
@ -202,7 +204,39 @@ impl PMMRable for TxKernel {
}
}
impl KernelFeatures {
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.contains(KernelFeatures::COINBASE)
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
!self.is_coinbase() && !self.is_height_locked()
}
/// Is this a height locked kernel?
pub fn is_height_locked(&self) -> bool {
self.contains(KernelFeatures::HEIGHT_LOCKED)
}
}
impl TxKernel {
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
/// Is this a height locked kernel?
pub fn is_height_locked(&self) -> bool {
self.features.is_height_locked()
}
/// Return the excess commitment for this tx_kernel.
pub fn excess(&self) -> Commitment {
self.excess
@ -219,6 +253,10 @@ impl TxKernel {
/// as a public key and checking the signature verifies with the fee as
/// message.
pub fn verify(&self) -> Result<(), Error> {
if self.is_coinbase() && self.fee != 0 || !self.is_height_locked() && self.lock_height != 0
{
return Err(Error::InvalidKernelFeatures);
}
let secp = static_secp_instance();
let secp = secp.lock();
let sig = &self.excess_sig;
@ -242,7 +280,7 @@ impl TxKernel {
/// Build an empty tx kernel with zero values.
pub fn empty() -> TxKernel {
TxKernel {
features: KernelFeatures::DEFAULT_KERNEL,
features: KernelFeatures::PLAIN,
fee: 0,
lock_height: 0,
excess: Commitment::from_vec(vec![0; 33]),
@ -258,6 +296,7 @@ impl TxKernel {
/// Builds a new tx kernel with the provided lock_height.
pub fn with_lock_height(self, lock_height: u64) -> TxKernel {
TxKernel {
features: kernel_features(lock_height),
lock_height,
..self
}
@ -583,25 +622,17 @@ impl TransactionBody {
Ok(())
}
// Verify we have no outputs tagged as COINBASE_OUTPUT.
// Verify we have no outputs tagged as COINBASE.
fn verify_output_features(&self) -> Result<(), Error> {
if self
.outputs
.iter()
.any(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
{
if self.outputs.iter().any(|x| x.is_coinbase()) {
return Err(Error::InvalidOutputFeatures);
}
Ok(())
}
// Verify we have no kernels tagged as COINBASE_KERNEL.
// Verify we have no kernels tagged as COINBASE.
fn verify_kernel_features(&self) -> Result<(), Error> {
if self
.kernels
.iter()
.any(|x| x.features.contains(KernelFeatures::COINBASE_KERNEL))
{
if self.kernels.iter().any(|x| x.is_coinbase()) {
return Err(Error::InvalidKernelFeatures);
}
Ok(())
@ -1078,6 +1109,16 @@ impl Input {
pub fn commitment(&self) -> Commitment {
self.commit
}
/// Is this a coinbase input?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain input?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
}
bitflags! {
@ -1085,9 +1126,9 @@ bitflags! {
#[derive(Serialize, Deserialize)]
pub struct OutputFeatures: u8 {
/// No flags
const DEFAULT_OUTPUT = 0b00000000;
const PLAIN = 0;
/// Output is a coinbase output, must not be spent until maturity
const COINBASE_OUTPUT = 0b00000001;
const COINBASE = 1;
}
}
@ -1157,12 +1198,34 @@ impl PMMRable for Output {
}
}
impl OutputFeatures {
/// Is this a coinbase output?
pub fn is_coinbase(&self) -> bool {
self.contains(OutputFeatures::COINBASE)
}
/// Is this a plain output?
pub fn is_plain(&self) -> bool {
!self.contains(OutputFeatures::COINBASE)
}
}
impl Output {
/// Commitment for the output
pub fn commitment(&self) -> Commitment {
self.commit
}
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
/// Range proof for the output
pub fn proof(&self) -> RangeProof {
self.proof
@ -1288,25 +1351,43 @@ impl From<Output> for OutputIdentifier {
/// to produce a 32 byte message to sign.
///
/// testnet4: msg = (fee || lock_height)
/// mainnet: msg = hash(fee || lock_height || features)
/// mainnet: msg = hash(features) for coinbase kernels
/// hash(features || fee) for plain kernels
/// hash(features || fee || lock_height) for height locked kernels
///
pub fn kernel_sig_msg(
fee: u64,
lock_height: u64,
features: KernelFeatures,
) -> Result<secp::Message, Error> {
if features.is_coinbase() && fee != 0 || !features.is_height_locked() && lock_height != 0 {
return Err(Error::InvalidKernelFeatures);
}
let msg = if global::is_testnet() {
let mut bytes = [0; 32];
BigEndian::write_u64(&mut bytes[16..24], fee);
BigEndian::write_u64(&mut bytes[24..], lock_height);
secp::Message::from_slice(&bytes)?
} else {
let hash = (fee, lock_height, features).hash();
let hash = match features {
KernelFeatures::COINBASE => (features).hash(),
KernelFeatures::PLAIN => (features, fee).hash(),
_ => (features, fee, lock_height).hash(),
};
secp::Message::from_slice(&hash.as_bytes())?
};
Ok(msg)
}
/// kernel features as determined by lock height
pub fn kernel_features(lock_height: u64) -> KernelFeatures {
if lock_height > 0 {
KernelFeatures::HEIGHT_LOCKED
} else {
KernelFeatures::PLAIN
}
}
#[cfg(test)]
mod test {
use super::*;
@ -1325,7 +1406,7 @@ mod test {
let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap();
let kernel = TxKernel {
features: KernelFeatures::DEFAULT_KERNEL,
features: KernelFeatures::PLAIN,
lock_height: 0,
excess: commit,
excess_sig: sig.clone(),
@ -1335,7 +1416,7 @@ mod test {
let mut vec = vec![];
ser::serialize(&mut vec, &kernel).expect("serialized failed");
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(kernel2.features, KernelFeatures::DEFAULT_KERNEL);
assert_eq!(kernel2.features, KernelFeatures::PLAIN);
assert_eq!(kernel2.lock_height, 0);
assert_eq!(kernel2.excess, commit);
assert_eq!(kernel2.excess_sig, sig.clone());
@ -1343,7 +1424,7 @@ mod test {
// now check a kernel with lock_height serialize/deserialize correctly
let kernel = TxKernel {
features: KernelFeatures::DEFAULT_KERNEL,
features: KernelFeatures::HEIGHT_LOCKED,
lock_height: 100,
excess: commit,
excess_sig: sig.clone(),
@ -1353,7 +1434,7 @@ mod test {
let mut vec = vec![];
ser::serialize(&mut vec, &kernel).expect("serialized failed");
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(kernel2.features, KernelFeatures::DEFAULT_KERNEL);
assert_eq!(kernel2.features, KernelFeatures::HEIGHT_LOCKED);
assert_eq!(kernel2.lock_height, 100);
assert_eq!(kernel2.excess, commit);
assert_eq!(kernel2.excess_sig, sig.clone());
@ -1380,7 +1461,7 @@ mod test {
let commit = keychain.commit(5, &key_id).unwrap();
let input = Input {
features: OutputFeatures::DEFAULT_OUTPUT,
features: OutputFeatures::PLAIN,
commit: commit,
};
@ -1396,7 +1477,7 @@ mod test {
// now generate the short_id for a *very* similar output (single feature flag
// different) and check it generates a different short_id
let input = Input {
features: OutputFeatures::COINBASE_OUTPUT,
features: OutputFeatures::COINBASE,
commit: commit,
};

View file

@ -241,14 +241,14 @@ pub fn verify_partial_sig(
/// let commit = keychain.commit(value, &key_id).unwrap();
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
/// let output = Output {
/// features: OutputFeatures::COINBASE_OUTPUT,
/// features: OutputFeatures::COINBASE,
/// commit: commit,
/// proof: rproof,
/// };
/// let height = 20;
/// let over_commit = secp.commit_value(reward(fees)).unwrap();
/// let out_commit = output.commitment();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::DEFAULT_KERNEL).unwrap();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::HEIGHT_LOCKED).unwrap();
/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap();
/// let pubkey = excess.to_pubkey(&secp).unwrap();
/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, value, &key_id, Some(&pubkey)).unwrap();
@ -315,14 +315,14 @@ where
/// let commit = keychain.commit(value, &key_id).unwrap();
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
/// let output = Output {
/// features: OutputFeatures::COINBASE_OUTPUT,
/// features: OutputFeatures::COINBASE,
/// commit: commit,
/// proof: rproof,
/// };
/// let height = 20;
/// let over_commit = secp.commit_value(reward(fees)).unwrap();
/// let out_commit = output.commitment();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::DEFAULT_KERNEL).unwrap();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::HEIGHT_LOCKED).unwrap();
/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap();
/// let pubkey = excess.to_pubkey(&secp).unwrap();
/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, value, &key_id, Some(&pubkey)).unwrap();

View file

@ -69,7 +69,7 @@ where
"Building input (spending regular output): {}, {}",
value, key_id
);
build_input(value, OutputFeatures::DEFAULT_OUTPUT, key_id)
build_input(value, OutputFeatures::PLAIN, key_id)
}
/// Adds a coinbase input spending a coinbase output.
@ -78,7 +78,7 @@ where
K: Keychain,
{
debug!("Building input (spending coinbase): {}, {}", value, key_id);
build_input(value, OutputFeatures::COINBASE_OUTPUT, key_id)
build_input(value, OutputFeatures::COINBASE, key_id)
}
/// Adds an output with the provided value and key identifier from the
@ -97,7 +97,7 @@ where
(
tx.with_output(Output {
features: OutputFeatures::DEFAULT_OUTPUT,
features: OutputFeatures::PLAIN,
commit: commit,
proof: rproof,
}),

View file

@ -27,7 +27,6 @@ pub fn output<K>(
keychain: &K,
key_id: &Identifier,
fees: u64,
height: u64,
) -> Result<(Output, TxKernel), Error>
where
K: Keychain,
@ -40,7 +39,7 @@ where
let rproof = proof::create(keychain, value, key_id, commit, None)?;
let output = Output {
features: OutputFeatures::COINBASE_OUTPUT,
features: OutputFeatures::COINBASE,
commit: commit,
proof: rproof,
};
@ -53,22 +52,18 @@ where
let pubkey = excess.to_pubkey(&secp)?;
// NOTE: Remember we sign the fee *and* the lock_height.
// For a coinbase output the fee is 0 and the lock_height is
// the lock_height of the coinbase output itself,
// not the lock_height of the tx (there is no tx for a coinbase output).
// This output will not be spendable earlier than lock_height (and we sign this
// here).
let msg = kernel_sig_msg(0, height, KernelFeatures::COINBASE_KERNEL)?;
// For a coinbase output the fee is 0 and the lock_height is 0
let msg = kernel_sig_msg(0, 0, KernelFeatures::COINBASE)?;
let sig = aggsig::sign_from_key_id(&secp, keychain, &msg, value, &key_id, Some(&pubkey))?;
let proof = TxKernel {
features: KernelFeatures::COINBASE_KERNEL,
features: KernelFeatures::COINBASE,
excess: excess,
excess_sig: sig,
fee: 0,
// lock_height here is the height of the block (tx should be valid immediately)
// *not* the lock_height of the coinbase output (only spendable 1,000 blocks later)
lock_height: height,
// lock_height here is 0
// *not* the maturity of the coinbase output (only spendable 1,440 blocks later)
lock_height: 0,
};
Ok((output, proof))
}

View file

@ -16,10 +16,10 @@
//! around during an interactive wallet exchange
use crate::blake2::blake2b::blake2b;
use crate::core::committed::Committed;
use crate::core::transaction::{kernel_sig_msg, KernelFeatures, Transaction};
use crate::core::verifier_cache::LruVerifierCache;
use crate::core::amount_to_hr_string;
use crate::core::committed::Committed;
use crate::core::transaction::{kernel_features, kernel_sig_msg, Transaction};
use crate::core::verifier_cache::LruVerifierCache;
use crate::keychain::{BlindSum, BlindingFactor, Keychain};
use crate::libtx::error::{Error, ErrorKind};
use crate::libtx::{aggsig, build, tx_fee};
@ -160,8 +160,7 @@ impl Slate {
// Currently includes the fee and the lock_height.
fn msg_to_sign(&self) -> Result<secp::Message, Error> {
// Currently we only support interactively creating a tx with a "default" kernel.
let features = KernelFeatures::DEFAULT_KERNEL;
let features = kernel_features(self.lock_height);
let msg = kernel_sig_msg(self.fee, self.lock_height, features)?;
Ok(msg)
}

View file

@ -131,7 +131,7 @@ fn empty_block_with_coinbase_is_valid() {
let coinbase_outputs = b
.outputs()
.iter()
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT))
.filter(|out| out.is_coinbase())
.map(|o| o.clone())
.collect::<Vec<_>>();
assert_eq!(coinbase_outputs.len(), 1);
@ -139,7 +139,7 @@ fn empty_block_with_coinbase_is_valid() {
let coinbase_kernels = b
.kernels()
.iter()
.filter(|out| out.features.contains(KernelFeatures::COINBASE_KERNEL))
.filter(|out| out.is_coinbase())
.map(|o| o.clone())
.collect::<Vec<_>>();
assert_eq!(coinbase_kernels.len(), 1);
@ -152,7 +152,7 @@ fn empty_block_with_coinbase_is_valid() {
}
#[test]
// test that flipping the COINBASE_OUTPUT flag on the output features
// test that flipping the COINBASE 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() {
@ -161,12 +161,8 @@ fn remove_coinbase_output_flag() {
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(b.outputs()[0]
.features
.contains(OutputFeatures::COINBASE_OUTPUT));
b.outputs_mut()[0]
.features
.remove(OutputFeatures::COINBASE_OUTPUT);
assert!(b.outputs()[0].is_coinbase());
b.outputs_mut()[0].features = OutputFeatures::PLAIN;
assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch));
assert!(b
@ -179,7 +175,7 @@ fn remove_coinbase_output_flag() {
}
#[test]
// test that flipping the COINBASE_KERNEL flag on the kernel features
// test that flipping the COINBASE flag on the kernel features
// invalidates the block and specifically it causes verify_coinbase to fail
fn remove_coinbase_kernel_flag() {
let keychain = ExtKeychain::from_random_seed().unwrap();
@ -187,12 +183,8 @@ fn remove_coinbase_kernel_flag() {
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(b.kernels()[0]
.features
.contains(KernelFeatures::COINBASE_KERNEL));
b.kernels_mut()[0]
.features
.remove(KernelFeatures::COINBASE_KERNEL);
assert!(b.kernels()[0].is_coinbase());
b.kernels_mut()[0].features = KernelFeatures::PLAIN;
// Flipping the coinbase flag results in kernels not summing correctly.
assert_eq!(
@ -380,7 +372,7 @@ fn convert_block_to_compact_block() {
cb.kern_ids()[0],
b.kernels()
.iter()
.find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL))
.find(|x| !x.is_coinbase())
.unwrap()
.short_id(&cb.hash(), cb.nonce)
);

View file

@ -92,7 +92,7 @@ where
K: Keychain,
{
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward_output = reward::output(keychain, &key_id, fees, previous_header.height).unwrap();
let reward_output = reward::output(keychain, &key_id, fees).unwrap();
Block::new(
&previous_header,
txs.into_iter().cloned().collect(),

View file

@ -122,7 +122,7 @@ fn build_tx_kernel() {
let kern = &tx.kernels()[0];
kern.verify().unwrap();
assert_eq!(kern.features, KernelFeatures::DEFAULT_KERNEL);
assert_eq!(kern.features, KernelFeatures::PLAIN);
assert_eq!(kern.fee, tx.fee());
}

View file

@ -31,7 +31,7 @@ fn test_output_ser_deser() {
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
let out = Output {
features: OutputFeatures::DEFAULT_OUTPUT,
features: OutputFeatures::PLAIN,
commit: commit,
proof: proof,
};
@ -40,7 +40,7 @@ fn test_output_ser_deser() {
ser::serialize(&mut vec, &out).expect("serialized failed");
let dout: Output = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(dout.features, OutputFeatures::DEFAULT_OUTPUT);
assert_eq!(dout.features, OutputFeatures::PLAIN);
assert_eq!(dout.commit, out.commit);
assert_eq!(dout.proof, out.proof);
}

View file

@ -38,7 +38,7 @@ fn test_verifier_cache_rangeproofs() {
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
let out = Output {
features: OutputFeatures::DEFAULT_OUTPUT,
features: OutputFeatures::PLAIN,
commit: commit,
proof: proof,
};

View file

@ -44,7 +44,7 @@ fn test_transaction_pool_block_building() {
let height = prev_header.height + 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let fee = txs.iter().map(|x| x.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id, fee, height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, fee).unwrap();
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).

View file

@ -44,7 +44,7 @@ fn test_transaction_pool_block_reconciliation() {
let header = {
let height = 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let genesis = BlockHeader::default();
let mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap();
@ -63,7 +63,7 @@ fn test_transaction_pool_block_reconciliation() {
let block = {
let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
let fees = initial_tx.fee();
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, fees).unwrap();
let mut block = Block::new(&header, vec![initial_tx], Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
@ -156,7 +156,7 @@ fn test_transaction_pool_block_reconciliation() {
let block = {
let key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
let fees = block_txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, fees).unwrap();
let mut block = Block::new(&header, block_txs, Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).

View file

@ -43,7 +43,7 @@ fn test_the_transaction_pool() {
let header = {
let height = 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let block = Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
chain.update_db_for_block(&block);

View file

@ -173,7 +173,7 @@ fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, B
let keychain = ExtKeychain::from_random_seed().unwrap();
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let (out, kernel) =
crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees, block_fees.height)
crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees)
.unwrap();
Ok((out, kernel, block_fees))
}

View file

@ -458,13 +458,7 @@ where
debug!("receive_coinbase: {:?}", block_fees);
let (out, kern) = reward::output(
wallet.keychain(),
&key_id,
block_fees.fees,
block_fees.height,
)
.unwrap();
let (out, kern) = reward::output(wallet.keychain(), &key_id, block_fees.fees).unwrap();
/* .context(ErrorKind::Keychain)?; */
Ok((out, kern, block_fees))
}

View file

@ -45,8 +45,8 @@ pub use self::{testclient::LocalWalletClient, testclient::WalletProxy};
/// Get an output from the chain locally and present it back as an API output
fn get_output_local(chain: &chain::Chain, commit: &pedersen::Commitment) -> Option<api::Output> {
let outputs = [
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, commit),
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, commit),
OutputIdentifier::new(OutputFeatures::PLAIN, commit),
OutputIdentifier::new(OutputFeatures::COINBASE, commit),
];
for x in outputs.iter() {

View file

@ -26,7 +26,7 @@ use grin_wallet as wallet;
use rand::thread_rng;
fn kernel_sig_msg() -> secp::Message {
transaction::kernel_sig_msg(0, 0, transaction::KernelFeatures::DEFAULT_KERNEL).unwrap()
transaction::kernel_sig_msg(0, 0, transaction::KernelFeatures::PLAIN).unwrap()
}
#[test]