Skip to content

Commit

Permalink
Merge branch 'feature-dan' into merge-feature-dan
Browse files Browse the repository at this point in the history
* feature-dan:
  fix(core)!: sort validate set by shard key (tari-project#4952)
  update validator signature
  feat!: implement validator node registration as per RFC-0313 (tari-project#4928)
  • Loading branch information
sdbondi committed Nov 28, 2022
2 parents baa196f + 349d429 commit 72fbf18
Show file tree
Hide file tree
Showing 44 changed files with 1,202 additions and 309 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ message ConsensusConstants {
/// Maximum byte size of TariScript
uint64 max_script_byte_size = 18;
/// How long does it take to timeout validator node registration
uint64 validator_node_timeout = 19;
uint64 validator_node_validity_period = 19;
/// The height at which these constants become effective
uint64 effective_from_height = 20;
/// Current version of the blockchain
Expand All @@ -143,4 +143,6 @@ message ConsensusConstants {
Range kernel_version_range = 28;
/// An allowlist of output types
repeated OutputType permitted_output_types = 29;
/// The length of an epoch
uint64 epoch_length = 30;
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ impl From<ConsensusConstants> for grpc::ConsensusConstants {
block_weight_inputs: weight_params.input_weight,
block_weight_outputs: weight_params.output_weight,
block_weight_kernels: weight_params.kernel_weight,
validator_node_timeout: cc.validator_node_timeout(),
max_script_byte_size: cc.get_max_script_byte_size() as u64,
faucet_value: cc.faucet_value().as_u64(),
effective_from_height: cc.effective_from_height(),
Expand All @@ -125,6 +124,8 @@ impl From<ConsensusConstants> for grpc::ConsensusConstants {
max_randomx_seed_height: cc.max_randomx_seed_height(),
output_version_range: Some(output_version_range),
permitted_output_types,
validator_node_validity_period: cc.validator_node_validity_period().as_u64(),
epoch_length: cc.epoch_length(),
}
}
}
17 changes: 10 additions & 7 deletions applications/tari_app_grpc/src/conversions/sidechain_feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@

use std::convert::{TryFrom, TryInto};

use tari_common_types::types::{PublicKey, Signature};
use tari_common_types::{
types::{PublicKey, Signature},
validator_node_signature::ValidatorNodeSignature,
};
use tari_core::{
consensus::MaxSizeString,
transactions::transaction_components::{
Expand Down Expand Up @@ -79,21 +82,21 @@ impl TryFrom<grpc::ValidatorNodeRegistration> for ValidatorNodeRegistration {
type Error = String;

fn try_from(value: grpc::ValidatorNodeRegistration) -> Result<Self, Self::Error> {
Ok(Self {
public_key: PublicKey::from_bytes(&value.public_key).map_err(|e| e.to_string())?,
signature: value
Ok(ValidatorNodeRegistration::new(ValidatorNodeSignature::new(
PublicKey::from_bytes(&value.public_key).map_err(|e| e.to_string())?,
value
.signature
.map(Signature::try_from)
.ok_or("signature not provided")??,
})
)))
}
}

impl From<ValidatorNodeRegistration> for grpc::ValidatorNodeRegistration {
fn from(value: ValidatorNodeRegistration) -> Self {
Self {
public_key: value.public_key.to_vec(),
signature: Some(value.signature.into()),
public_key: value.public_key().to_vec(),
signature: Some(value.signature().into()),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions applications/tari_console_wallet/src/automation/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ pub async fn claim_htlc_refund(
}

pub async fn register_validator_node(
amount: MicroTari,
mut wallet_transaction_service: TransactionServiceHandle,
validator_node_public_key: PublicKey,
validator_node_signature: Signature,
Expand All @@ -202,6 +203,7 @@ pub async fn register_validator_node(
) -> Result<TxId, CommandError> {
wallet_transaction_service
.register_validator_node(
amount,
validator_node_public_key,
validator_node_signature,
selection_criteria,
Expand Down Expand Up @@ -971,6 +973,7 @@ pub async fn command_runner(
},
RegisterValidatorNode(args) => {
let tx_id = register_validator_node(
args.amount,
transaction_service.clone(),
args.validator_node_public_key.into(),
Signature::new(
Expand Down
1 change: 1 addition & 0 deletions applications/tari_console_wallet/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ pub struct HashPasswordArgs {

#[derive(Debug, Args, Clone)]
pub struct RegisterValidatorNodeArgs {
pub amount: MicroTari,
pub validator_node_public_key: UniPublicKey,
pub validator_node_public_nonce: UniPublicKey,
pub validator_node_signature: Vec<u8>,
Expand Down
41 changes: 36 additions & 5 deletions applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,23 @@ use tari_common_types::{
types::{BlockHash, PublicKey, Signature},
};
use tari_comms::{multiaddr::Multiaddr, types::CommsPublicKey, CommsNode};
use tari_core::transactions::{
tari_amount::{MicroTari, T},
transaction_components::{CodeTemplateRegistration, OutputFeatures, OutputType, SideChainFeature, UnblindedOutput},
use tari_core::{
consensus::{ConsensusConstants, ConsensusManager},
transactions::{
tari_amount::{MicroTari, T},
transaction_components::{
CodeTemplateRegistration,
OutputFeatures,
OutputType,
SideChainFeature,
UnblindedOutput,
},
},
};
use tari_utilities::{hex::Hex, ByteArray};
use tari_wallet::{
connectivity_service::{OnlineStatus, WalletConnectivityInterface},
error::WalletStorageError,
output_manager_service::{handle::OutputManagerHandle, UtxoSelectionCriteria},
transaction_service::{
handle::TransactionServiceHandle,
Expand Down Expand Up @@ -127,11 +137,13 @@ async fn send_transaction_event(

pub struct WalletGrpcServer {
wallet: WalletSqlite,
rules: ConsensusManager,
}

impl WalletGrpcServer {
pub fn new(wallet: WalletSqlite) -> Self {
Self { wallet }
let rules = ConsensusManager::builder(wallet.network.as_network()).build();
Self { wallet, rules }
}

fn get_transaction_service(&self) -> TransactionServiceHandle {
Expand All @@ -145,6 +157,18 @@ impl WalletGrpcServer {
fn comms(&self) -> &CommsNode {
&self.wallet.comms
}

fn get_consensus_constants(&self) -> Result<&ConsensusConstants, WalletStorageError> {
// If we don't have the chain metadata, we hope that VNReg consensus constants did not change - worst case, we
// spend more than we need to or the the transaction is rejected.
let height = self
.wallet
.db
.get_chain_metadata()?
.map(|m| m.height_of_longest_chain())
.unwrap_or_default();
Ok(self.rules.consensus_constants(height))
}
}

#[tonic::async_trait]
Expand Down Expand Up @@ -955,10 +979,17 @@ impl wallet_server::Wallet for WalletGrpcServer {
.validator_node_signature
.ok_or_else(|| Status::invalid_argument("Validator node signature is missing!"))?
.try_into()
.unwrap();
.map_err(|_| Status::invalid_argument("Validator node signature is malformed!"))?;

let constants = self.get_consensus_constants().map_err(|e| {
error!(target: LOG_TARGET, "Failed to get consensus constants: {}", e);
Status::internal("failed to fetch consensus constants")
})?;

// TODO: we need to set the output maturity
let response = match transaction_service
.register_validator_node(
constants.validator_node_registration_min_deposit_amount(),
validator_node_public_key,
validator_node_signature,
UtxoSelectionCriteria::default(),
Expand Down
2 changes: 2 additions & 0 deletions base_layer/common_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ edition = "2018"
[dependencies]
tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.16.4" }
tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag="v0.4.10" }
# TODO: remove this dependency and move Network into tari_common_types
tari_common = { version = "^0.41", path = "../../common" }

base64 = "0.13.0"
borsh = "0.9.3"
digest = "0.9.0"
lazy_static = "1.4.0"
newtype-ops = "0.1"
rand = "0.7.3"
serde = { version = "1.0.106", features = ["derive"] }
thiserror = "1.0.29"
Expand Down
44 changes: 44 additions & 0 deletions base_layer/common_types/src/epoch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2022. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use newtype_ops::newtype_ops;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default)]
pub struct VnEpoch(pub u64);

impl VnEpoch {
pub fn as_u64(&self) -> u64 {
self.0
}

pub fn to_be_bytes(&self) -> [u8; 8] {
self.0.to_be_bytes()
}

pub fn saturating_sub(self, other: VnEpoch) -> VnEpoch {
VnEpoch(self.0.saturating_sub(other.0))
}
}

newtype_ops! { [VnEpoch] {add sub mul div} {:=} Self Self }
newtype_ops! { [VnEpoch] {add sub mul div} {:=} &Self &Self }
newtype_ops! { [VnEpoch] {add sub mul div} {:=} Self &Self }
2 changes: 2 additions & 0 deletions base_layer/common_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
pub mod chain_metadata;
pub mod dammsum;
pub mod emoji;
pub mod epoch;
pub mod grpc_authentication;
pub mod tari_address;
pub mod transaction;
mod tx_id;
pub mod types;
pub mod validator_node_signature;
pub mod waiting_requests;

#[macro_use]
Expand Down
74 changes: 74 additions & 0 deletions base_layer/common_types/src/validator_node_signature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2022. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use tari_crypto::{hash::blake2::Blake256, hash_domain, hashing::DomainSeparatedHasher, keys::PublicKey as PublicKeyT};
use tari_utilities::ByteArray;

use crate::types::{FixedHash, PrivateKey, PublicKey, Signature};

hash_domain!(ValidatorNodeHashDomain, "com.tari.dan_layer.validator_node", 0);

#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct ValidatorNodeSignature {
public_key: PublicKey,
signature: Signature,
}

impl ValidatorNodeSignature {
pub fn new(public_key: PublicKey, signature: Signature) -> Self {
Self { public_key, signature }
}

// TODO: pass in commitment instead of arbitrary message
pub fn sign(private_key: &PrivateKey, msg: &[u8]) -> Self {
let (secret_nonce, public_nonce) = PublicKey::random_keypair(&mut OsRng);
let public_key = PublicKey::from_secret_key(private_key);
let challenge = Self::construct_challenge(&public_key, &public_nonce, msg);
// TODO: Changing to use the new signing API requires a lot of changes
let signature = Signature::sign_raw(private_key, secret_nonce, &*challenge)
.expect("Sign cannot fail with 32-byte challenge and a RistrettoPublicKey");
Self { public_key, signature }
}

fn construct_challenge(public_key: &PublicKey, public_nonce: &PublicKey, msg: &[u8]) -> FixedHash {
let hasher = DomainSeparatedHasher::<Blake256, ValidatorNodeHashDomain>::new_with_label("registration")
.chain(public_key.as_bytes())
.chain(public_nonce.as_bytes())
.chain(msg);
digest::Digest::finalize(hasher).into()
}

pub fn is_valid_signature_for(&self, msg: &[u8]) -> bool {
let challenge = Self::construct_challenge(&self.public_key, self.signature.get_public_nonce(), msg);
self.signature.verify_challenge(&self.public_key, &*challenge)
}

pub fn public_key(&self) -> &PublicKey {
&self.public_key
}

pub fn signature(&self) -> &Signature {
&self.signature
}
}
Loading

0 comments on commit 72fbf18

Please sign in to comment.