mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
[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:
parent
aa9da6838b
commit
f43df5f601
26 changed files with 175 additions and 124 deletions
|
@ -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() {
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>>();
|
||||
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue