Skip to content

Commit

Permalink
feat!: add claim_public_key to sidechain features (#5619)
Browse files Browse the repository at this point in the history
Description
---
Add claim public key to validator node registration

Motivation and Context
---
This claim key is informational and will be used in L2 to restrict fee
claims to a particular signing key

How Has This Been Tested?
---
Existing tests

What process can a PR reviewer use to test or verify this change?
---
Run register validator node wallet command
<!-- Checklist -->
<!-- 1. Is the title of your PR in the form that would make nice release
notes? The title, excluding the conventional commit
tag, will be included exactly as is in the CHANGELOG, so please think
about it carefully. -->


Breaking Changes
---

- [ ] None
- [x] Requires data directory on base node to be deleted
- [x] Requires hard fork
- [ ] Other - Please specify

<!-- Does this include a breaking change? If so, include this line as a
footer -->
<!-- BREAKING CHANGE: Description what the user should do, e.g. delete a
database, resync the chain -->
  • Loading branch information
sdbondi authored Sep 8, 2023
1 parent 45c20a3 commit 4bdd364
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 42 deletions.
1 change: 1 addition & 0 deletions applications/minotari_app_grpc/proto/sidechain_types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ message SideChainFeature {
message ValidatorNodeRegistration {
bytes public_key = 1;
Signature signature = 2;
bytes claim_public_key = 3;
}

message TemplateRegistration {
Expand Down
5 changes: 3 additions & 2 deletions applications/minotari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,9 @@ message TransactionEventResponse {
message RegisterValidatorNodeRequest {
bytes validator_node_public_key = 1;
Signature validator_node_signature = 2;
uint64 fee_per_gram = 3;
string message = 4;
bytes validator_node_claim_public_key = 3;
uint64 fee_per_gram = 4;
string message = 5;
}

message RegisterValidatorNodeResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,20 @@ impl TryFrom<grpc::ValidatorNodeRegistration> for ValidatorNodeRegistration {
type Error = String;

fn try_from(value: grpc::ValidatorNodeRegistration) -> Result<Self, Self::Error> {
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")??,
)))
let public_key = PublicKey::from_bytes(&value.public_key).map_err(|e| format!("Invalid public key: {}", e))?;
let claim_public_key =
PublicKey::from_bytes(&value.claim_public_key).map_err(|e| format!("Invalid claim public key: {}", e))?;

Ok(ValidatorNodeRegistration::new(
ValidatorNodeSignature::new(
public_key,
value
.signature
.map(Signature::try_from)
.ok_or("signature not provided")??,
),
claim_public_key,
))
}
}

Expand All @@ -102,6 +109,7 @@ impl From<ValidatorNodeRegistration> for grpc::ValidatorNodeRegistration {
Self {
public_key: value.public_key().to_vec(),
signature: Some(value.signature().into()),
claim_public_key: value.claim_public_key().to_vec(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pub async fn register_validator_node(
mut wallet_transaction_service: TransactionServiceHandle,
validator_node_public_key: PublicKey,
validator_node_signature: Signature,
validator_node_claim_public_key: PublicKey,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroMinotari,
message: String,
Expand All @@ -211,6 +212,7 @@ pub async fn register_validator_node(
amount,
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
selection_criteria,
fee_per_gram,
message,
Expand Down Expand Up @@ -1001,6 +1003,7 @@ pub async fn command_runner(
args.validator_node_public_nonce.into(),
RistrettoSecretKey::from_vec(&args.validator_node_signature)?,
),
args.validator_node_claim_public_key.into(),
UtxoSelectionCriteria::default(),
config.fee_per_gram * uT,
args.message,
Expand Down
1 change: 1 addition & 0 deletions applications/minotari_console_wallet/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ pub struct RegisterValidatorNodeArgs {
pub validator_node_public_key: UniPublicKey,
pub validator_node_public_nonce: UniPublicKey,
pub validator_node_signature: Vec<u8>,
pub validator_node_claim_public_key: UniPublicKey,
#[clap(short, long, default_value = "Registering VN")]
pub message: String,
}
Original file line number Diff line number Diff line change
Expand Up @@ -1006,12 +1006,14 @@ impl wallet_server::Wallet for WalletGrpcServer {
let request = request.into_inner();
let mut transaction_service = self.get_transaction_service();
let validator_node_public_key = CommsPublicKey::from_bytes(&request.validator_node_public_key)
.map_err(|_| Status::internal("Destination address is malformed".to_string()))?;
.map_err(|_| Status::invalid_argument("Validator node address is malformed"))?;
let validator_node_signature = request
.validator_node_signature
.ok_or_else(|| Status::invalid_argument("Validator node signature is missing!"))?
.try_into()
.map_err(|_| Status::invalid_argument("Validator node signature is malformed!"))?;
let validator_node_claim_public_key = PublicKey::from_bytes(&request.validator_node_claim_public_key)
.map_err(|_| Status::invalid_argument("Claim public key is malformed"))?;

let constants = self.get_consensus_constants().map_err(|e| {
error!(target: LOG_TARGET, "Failed to get consensus constants: {}", e);
Expand All @@ -1023,6 +1025,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
constants.validator_node_registration_min_deposit_amount(),
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
UtxoSelectionCriteria::default(),
request.fee_per_gram.into(),
request.message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,12 @@ mod validator_node_merkle_root {
let (blocks, outputs) = add_many_chained_blocks(1, &db, &key_manager).await;

let (sk, public_key) = PublicKey::random_keypair(&mut OsRng);
let signature = ValidatorNodeSignature::sign(&sk, &[]);
let features =
OutputFeatures::for_validator_node_registration(public_key.clone(), signature.signature().clone());
let signature = ValidatorNodeSignature::sign(&sk, &public_key, &[]);
let features = OutputFeatures::for_validator_node_registration(
public_key.clone(),
signature.signature().clone(),
public_key.clone(),
);
let (tx, _outputs) = schema_to_transaction(
&[txn_schema!(
from: vec![outputs[0].clone()],
Expand Down
1 change: 1 addition & 0 deletions base_layer/core/src/proto/sidechain_feature.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ message SideChainFeature {
message ValidatorNodeRegistration {
bytes public_key = 1;
Signature signature = 2;
bytes claim_public_key = 3;
}

message TemplateRegistration {
Expand Down
22 changes: 15 additions & 7 deletions base_layer/core/src/proto/sidechain_feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,20 @@ impl TryFrom<proto::types::ValidatorNodeRegistration> for ValidatorNodeRegistrat
type Error = String;

fn try_from(value: proto::types::ValidatorNodeRegistration) -> Result<Self, Self::Error> {
Ok(Self::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")??,
)))
let public_key = PublicKey::from_bytes(&value.public_key).map_err(|e| format!("public_key: {}", e))?;
let claim_public_key =
PublicKey::from_bytes(&value.claim_public_key).map_err(|e| format!("claim_public_key: {}", e))?;

Ok(Self::new(
ValidatorNodeSignature::new(
public_key,
value
.signature
.map(Signature::try_from)
.ok_or("signature not provided")??,
),
claim_public_key,
))
}
}

Expand All @@ -104,6 +111,7 @@ impl From<ValidatorNodeRegistration> for proto::types::ValidatorNodeRegistration
Self {
public_key: value.public_key().to_vec(),
signature: Some(value.signature().into()),
claim_public_key: value.claim_public_key().to_vec(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,14 @@ impl OutputFeatures {
}

pub fn for_validator_node_registration(
validator_node_public_key: PublicKey,
validator_node_signature: Signature,
public_key: PublicKey,
signature: Signature,
claim_public_key: PublicKey,
) -> OutputFeatures {
OutputFeatures {
output_type: OutputType::ValidatorNodeRegistration,
sidechain_feature: Some(SideChainFeature::ValidatorNodeRegistration(
ValidatorNodeRegistration::new(ValidatorNodeSignature::new(
validator_node_public_key,
validator_node_signature,
)),
ValidatorNodeRegistration::new(ValidatorNodeSignature::new(public_key, signature), claim_public_key),
)),
..Default::default()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ use crate::{
#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize, BorshSerialize, BorshDeserialize)]
pub struct ValidatorNodeRegistration {
signature: ValidatorNodeSignature,
claim_public_key: PublicKey,
}

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

pub fn is_valid_signature_for(&self, msg: &[u8]) -> bool {
self.signature.is_valid_signature_for(msg)
self.signature.is_valid_signature_for(&self.claim_public_key, msg)
}

pub fn derive_shard_key(
Expand All @@ -71,6 +75,10 @@ impl ValidatorNodeRegistration {
self.signature.public_key()
}

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

pub fn signature(&self) -> &Signature {
self.signature.signature()
}
Expand All @@ -94,14 +102,19 @@ fn generate_shard_key(public_key: &PublicKey, entropy: &[u8; 32]) -> [u8; 32] {
mod test {
use rand::rngs::OsRng;
use tari_common_types::types::PrivateKey;
use tari_crypto::keys::SecretKey;
use tari_crypto::keys::{PublicKey, SecretKey};

use super::*;
use crate::test_helpers::new_public_key;

fn create_instance() -> ValidatorNodeRegistration {
let sk = PrivateKey::random(&mut OsRng);
ValidatorNodeRegistration::new(ValidatorNodeSignature::sign(&sk, b"valid"))
let claim_public_key = PublicKey::from_secret_key(&sk);

ValidatorNodeRegistration::new(
ValidatorNodeSignature::sign(&sk, &claim_public_key, b"valid"),
claim_public_key,
)
}

mod is_valid_signature_for {
Expand All @@ -122,10 +135,10 @@ mod test {
#[test]
fn it_returns_false_for_invalid_signature() {
let mut reg = create_instance();
reg = ValidatorNodeRegistration::new(ValidatorNodeSignature::new(
reg.public_key().clone(),
Signature::default(),
));
reg = ValidatorNodeRegistration::new(
ValidatorNodeSignature::new(reg.public_key().clone(), Signature::default()),
Default::default(),
);
assert!(!reg.is_valid_signature_for(b"valid"));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,36 @@ impl ValidatorNodeSignature {
Self { public_key, signature }
}

pub fn sign(private_key: &PrivateKey, msg: &[u8]) -> Self {
pub fn sign(private_key: &PrivateKey, claim_public_key: &PublicKey, 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);
let challenge = Self::construct_challenge(&public_key, &public_nonce, claim_public_key, msg);
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 {
fn construct_challenge(
public_key: &PublicKey,
public_nonce: &PublicKey,
claim_public_key: &PublicKey,
msg: &[u8],
) -> FixedHash {
let hasher = DomainSeparatedHasher::<Blake2b<U32>, ValidatorNodeHashDomain>::new_with_label("registration")
.chain(public_key.as_bytes())
.chain(public_nonce.as_bytes())
.chain(claim_public_key.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);
pub fn is_valid_signature_for(&self, claim_public_key: &PublicKey, msg: &[u8]) -> bool {
let challenge = Self::construct_challenge(
&self.public_key,
self.signature.get_public_nonce(),
claim_public_key,
msg,
);
self.signature.verify_challenge(&self.public_key, &*challenge)
}

Expand Down
3 changes: 3 additions & 0 deletions base_layer/wallet/src/transaction_service/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ pub enum TransactionServiceRequest {
amount: MicroMinotari,
validator_node_public_key: CommsPublicKey,
validator_node_signature: Signature,
validator_node_claim_public_key: CommsPublicKey,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroMinotari,
message: String,
Expand Down Expand Up @@ -497,6 +498,7 @@ impl TransactionServiceHandle {
amount: MicroMinotari,
validator_node_public_key: PublicKey,
validator_node_signature: Signature,
validator_node_claim_public_key: PublicKey,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroMinotari,
message: String,
Expand All @@ -507,6 +509,7 @@ impl TransactionServiceHandle {
amount,
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
selection_criteria,
fee_per_gram,
message,
Expand Down
10 changes: 8 additions & 2 deletions base_layer/wallet/src/transaction_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ where
amount,
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
selection_criteria,
fee_per_gram,
message,
Expand All @@ -681,6 +682,7 @@ where
amount,
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
selection_criteria,
fee_per_gram,
message,
Expand Down Expand Up @@ -1733,6 +1735,7 @@ where
amount: MicroMinotari,
validator_node_public_key: CommsPublicKey,
validator_node_signature: Signature,
validator_node_claim_public_key: PublicKey,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroMinotari,
message: String,
Expand All @@ -1744,8 +1747,11 @@ where
>,
reply_channel: oneshot::Sender<Result<TransactionServiceResponse, TransactionServiceError>>,
) -> Result<(), TransactionServiceError> {
let output_features =
OutputFeatures::for_validator_node_registration(validator_node_public_key, validator_node_signature);
let output_features = OutputFeatures::for_validator_node_registration(
validator_node_public_key,
validator_node_signature,
validator_node_claim_public_key,
);
self.send_transaction(
self.resources.wallet_identity.address.clone(),
amount,
Expand Down

0 comments on commit 4bdd364

Please sign in to comment.