Skip to content

Commit

Permalink
Add recovery_byte to OutputFeatures
Browse files Browse the repository at this point in the history
Added recovery_byte to OutputFeatures. This will not change the
genesis block and only become effective with version V1 of the
OutputFeatures, resulting in a hard fork.

Co-authored-by: Mike the Tike <[email protected]>
Co-authored-by: David Main <[email protected]>
  • Loading branch information
3 people committed Mar 3, 2022
1 parent fc516a4 commit dafe55f
Show file tree
Hide file tree
Showing 52 changed files with 5,250 additions and 4,371 deletions.
4 changes: 4 additions & 0 deletions applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ message OutputFeatures {
// Version
uint32 version = 9;
CommitteeDefinitionFeatures committee_definition = 10;

// The recovery byte - not consensus critical - can help reduce the bandwidth with wallet recovery or in other
// instances when a wallet needs to request the complete UTXO set from a base node.
uint32 recovery_byte = 11;
}

message AssetOutputFeatures {
Expand Down
2 changes: 2 additions & 0 deletions applications/tari_app_grpc/src/conversions/output_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ impl TryFrom<grpc::OutputFeatures> for OutputFeatures {
OutputFlags::from_bits(features.flags as u8)
.ok_or_else(|| "Invalid or unrecognised output flags".to_string())?,
features.maturity,
features.recovery_byte as u8,
features.metadata,
unique_id,
parent_public_key,
Expand Down Expand Up @@ -89,6 +90,7 @@ impl From<OutputFeatures> for grpc::OutputFeatures {
sidechain_checkpoint: features.sidechain_checkpoint.map(|m| m.into()),
version: features.version as u32,
committee_definition: features.committee_definition.map(|c| c.into()),
recovery_byte: features.recovery_byte as u32,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion applications/test_faucet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl Iterator for UTXOFeatures {
type Item = OutputFeatures;

fn next(&mut self) -> Option<Self::Item> {
let f = OutputFeatures::with_maturity(0);
let f = OutputFeatures::default();
Some(f)
}
}
Expand Down
8,000 changes: 4,000 additions & 4,000 deletions base_layer/core/src/blocks/faucets/dibbler_faucet.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions base_layer/core/src/blocks/genesis_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ fn get_dibbler_genesis_block_raw() -> Block {
version:OutputFeaturesVersion::V0,
flags:OutputFlags::COINBASE_OUTPUT,
maturity:60,
recovery_byte: OutputFeatures::RECOVERY_BYTE_DEFAULT,
metadata: Vec::new(),
unique_id: None,
parent_public_key: None,
Expand Down
13 changes: 9 additions & 4 deletions base_layer/core/src/chain_storage/tests/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,10 @@ mod add_block {

let prev_block = blocks.last().unwrap();
// Used to help identify the output we're interrogating in this test
let features = OutputFeatures::with_maturity(1);
let features = OutputFeatures {
maturity: 1,
..Default::default()
};
let (txns, tx_outputs) = schema_to_transaction(&[txn_schema!(
from: vec![outputs[0].clone()],
to: vec![500 * T],
Expand Down Expand Up @@ -731,7 +734,7 @@ mod fetch_utxo_by_unique_id {
// Height 1
let (blocks, outputs) = add_many_chained_blocks(1, &db);

let features = OutputFeatures {
let mut features = OutputFeatures {
flags: OutputFlags::MINT_NON_FUNGIBLE,
parent_public_key: Some(asset_pk.clone()),
unique_id: Some(unique_id.clone()),
Expand All @@ -742,8 +745,9 @@ mod fetch_utxo_by_unique_id {
to: vec![500 * T],
fee: 5.into(),
lock: 0,
features: features
features: features.clone()
)]);
features.set_recovery_byte(tx_outputs[0].features.recovery_byte);

let asset_utxo1 = tx_outputs.iter().find(|o| o.features == features).unwrap();

Expand All @@ -766,7 +770,7 @@ mod fetch_utxo_by_unique_id {
expected_commitment
);

let features = OutputFeatures {
let mut features = OutputFeatures {
flags: OutputFlags::empty(),
parent_public_key: Some(asset_pk.clone()),
unique_id: Some(unique_id.clone()),
Expand All @@ -779,6 +783,7 @@ mod fetch_utxo_by_unique_id {
lock: 0,
features: features
)]);
features.set_recovery_byte(tx_outputs[0].features.recovery_byte);

let asset_utxo2 = tx_outputs.iter().find(|o| o.features == features).unwrap();

Expand Down
3 changes: 2 additions & 1 deletion base_layer/core/src/consensus/consensus_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ impl ConsensusConstants {

pub fn coinbase_weight(&self) -> u64 {
// TODO: We do not know what script, features etc a coinbase has - this should be max coinbase size?
let output_features = OutputFeatures { ..Default::default() };
let metadata_size = self.transaction_weight.round_up_metadata_size(
script![Nop].consensus_encode_exact_size() + OutputFeatures::default().consensus_encode_exact_size(),
script![Nop].consensus_encode_exact_size() + output_features.consensus_encode_exact_size(),
);
self.transaction_weight.calculate(1, 0, 1, metadata_size)
}
Expand Down
8 changes: 7 additions & 1 deletion base_layer/core/src/covenants/covenant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,13 @@ mod test {
outputs[7].features.maturity = 42;
let mut input = create_input();
input.set_maturity(42).unwrap();
let covenant = covenant!(fields_preserved(@fields(@field::features)));
let covenant = covenant!(fields_preserved(@fields(
@field::features_flags,
@field::features_maturity,
@field::features_unique_id,
@field::features_parent_public_key,
@field::features_metadata))
);
let num_matching_outputs = covenant.execute(0, &input, &outputs).unwrap();
assert_eq!(num_matching_outputs, 3);
}
Expand Down
3 changes: 2 additions & 1 deletion base_layer/core/src/covenants/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ mod test {

#[test]
fn get_field_value_ref() {
let features = OutputFeatures {
let mut features = OutputFeatures {
maturity: 42,
..Default::default()
};
Expand All @@ -345,6 +345,7 @@ mod test {
})
.pop()
.unwrap();
features.set_recovery_byte(output.features.recovery_byte);
let r = OutputField::Features.get_field_value_ref::<OutputFeatures>(&output);
assert_eq!(*r.unwrap(), features);
}
Expand Down
4 changes: 4 additions & 0 deletions base_layer/core/src/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ message OutputFeatures {
// Version
uint32 version = 9;
CommitteeDefinitionFeatures committee_definition = 10;

// The recovery byte - not consensus critical - can help reduce the bandwidth with wallet recovery or in other
// instances when a wallet needs to request the complete UTXO set from a base node.
uint32 recovery_byte = 11;
}

message AssetOutputFeatures {
Expand Down
2 changes: 2 additions & 0 deletions base_layer/core/src/proto/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl TryFrom<proto::types::OutputFeatures> for OutputFeatures {
OutputFlags::from_bits(features.flags as u8)
.ok_or_else(|| "Invalid or unrecognised output flags".to_string())?,
features.maturity,
features.recovery_byte as u8,
features.metadata,
unique_id,
parent_public_key,
Expand Down Expand Up @@ -323,6 +324,7 @@ impl From<OutputFeatures> for proto::types::OutputFeatures {
sidechain_checkpoint: features.sidechain_checkpoint.map(|s| s.into()),
version: features.version as u32,
committee_definition: features.committee_definition.map(|c| c.into()),
recovery_byte: features.recovery_byte as u32,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions base_layer/core/src/test_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ pub fn mine_to_difficulty(mut block: Block, difficulty: Difficulty) -> Result<Bl
// When starting from the same nonce, in tests it becomes common to mine the same block more than once without the
// hash changing. This introduces the required entropy
block.header.nonce = rand::thread_rng().gen();
for _i in 0..10000 {
for _i in 0..20000 {
if sha3_difficulty(&block.header) == difficulty {
return Ok(block);
}
block.header.nonce += 1;
}
Err("Could not mine to difficulty in 10000 iterations".to_string())
Err("Could not mine to difficulty in 20000 iterations".to_string())
}

pub fn create_peer_manager<P: AsRef<Path>>(data_path: P) -> Arc<PeerManager> {
Expand Down
15 changes: 11 additions & 4 deletions base_layer/core/src/transactions/coinbase_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,13 @@ impl CoinbaseBuilder {
let spending_key = self.spend_key.ok_or(CoinbaseBuildError::MissingSpendKey)?;
let script_private_key = self.script_key.unwrap_or_else(|| spending_key.clone());
let script = self.script.unwrap_or_else(|| script!(Nop));
let output_features = OutputFeatures::create_coinbase(height + constants.coinbase_lock_height());

let commitment = self
.factories
.commitment
.commit_value(&spending_key, total_reward.as_u64());
let recovery_byte = OutputFeatures::create_unique_recovery_byte(&commitment, self.rewind_data.as_ref());
let output_features = OutputFeatures::create_coinbase(height + constants.coinbase_lock_height(), recovery_byte);
let excess = self.factories.commitment.commit_value(&spending_key, 0);
let kernel_features = KernelFeatures::create_coinbase();
let metadata = TransactionMetadata::default();
Expand Down Expand Up @@ -286,7 +292,7 @@ mod test {
let (builder, rules, _) = get_builder();
assert_eq!(
builder
.build(rules.consensus_constants(0), rules.emission_schedule())
.build(rules.consensus_constants(0), rules.emission_schedule(),)
.unwrap_err(),
CoinbaseBuildError::MissingBlockHeight
);
Expand All @@ -298,7 +304,7 @@ mod test {
let builder = builder.with_block_height(42);
assert_eq!(
builder
.build(rules.consensus_constants(42), rules.emission_schedule())
.build(rules.consensus_constants(42), rules.emission_schedule(),)
.unwrap_err(),
CoinbaseBuildError::MissingFees
);
Expand All @@ -313,7 +319,7 @@ mod test {
let builder = builder.with_block_height(42).with_fees(fees).with_nonce(p.nonce);
assert_eq!(
builder
.build(rules.consensus_constants(42), rules.emission_schedule())
.build(rules.consensus_constants(42), rules.emission_schedule(),)
.unwrap_err(),
CoinbaseBuildError::MissingSpendKey
);
Expand Down Expand Up @@ -358,6 +364,7 @@ mod test {
let rewind_data = RewindData {
rewind_key: rewind_key.clone(),
rewind_blinding_key: rewind_blinding_key.clone(),
recovery_byte_key: PrivateKey::random(&mut OsRng),
proof_message: proof_message.to_owned(),
};

Expand Down
Loading

0 comments on commit dafe55f

Please sign in to comment.