Skip to content

Commit

Permalink
feat: add more burn details to burn command (#5169)
Browse files Browse the repository at this point in the history
Description
---
Add burn fields to the GRPC method of burning

Motivation and Context
---
When claiming funds on the second layer, you will need a few proofs to claim them. This allows the wallet to provide them

How Has This Been Tested?
---
CI

<!-- 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 -->

Co-authored-by: Hansie Odendaal <39146854+hansieodendaal@users.noreply.github.com>
Co-authored-by: Stan Bondi <sdbondi@users.noreply.github.com>
  • Loading branch information
3 people committed Feb 20, 2023
1 parent 62428f2 commit e417e57
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 17 deletions.
4 changes: 4 additions & 0 deletions applications/tari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ message CreateBurnTransactionRequest{
uint64 amount = 1;
uint64 fee_per_gram = 2;
string message = 3;
bytes claim_public_key = 4;
}


Expand Down Expand Up @@ -137,6 +138,9 @@ message CreateBurnTransactionResponse{
uint64 transaction_id = 1;
bool is_success = 2;
string failure_message = 3;
bytes commitment = 4;
bytes ownership_proof = 5;
bytes rangeproof = 6;
}

message TransferResult {
Expand Down
9 changes: 8 additions & 1 deletion applications/tari_console_wallet/src/automation/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,16 @@ pub async fn burn_tari(
message: String,
) -> Result<TxId, CommandError> {
wallet_transaction_service
.burn_tari(amount, UtxoSelectionCriteria::default(), fee_per_gram * uT, message)
.burn_tari(
amount,
UtxoSelectionCriteria::default(),
fee_per_gram * uT,
message,
None,
)
.await
.map_err(CommandError::TransactionServiceError)
.map(|res| res.0)
}

/// publishes a tari-SHA atomic swap HTLC transaction
Expand Down
15 changes: 13 additions & 2 deletions applications/tari_console_wallet/src/grpc/wallet_grpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,23 +599,34 @@ impl wallet_server::Wallet for WalletGrpcServer {
UtxoSelectionCriteria::default(),
message.fee_per_gram.into(),
message.message,
if message.claim_public_key.is_empty() {
None
} else {
Some(
PublicKey::from_bytes(&message.claim_public_key)
.map_err(|e| Status::invalid_argument(e.to_string()))?,
)
},
)
.await
{
Ok(tx_id) => {
Ok((tx_id, commitment, ownership_proof, rangeproof)) => {
debug!(target: LOG_TARGET, "Transaction broadcast: {}", tx_id,);
CreateBurnTransactionResponse {
transaction_id: tx_id.as_u64(),
is_success: true,
failure_message: Default::default(),
commitment: commitment.to_vec(),
ownership_proof: ownership_proof.map(|o| o.to_vec()).unwrap_or_default(),
rangeproof: rangeproof.to_vec(),
}
},
Err(e) => {
warn!(target: LOG_TARGET, "Failed to burn Tarid: {}", e);
CreateBurnTransactionResponse {
transaction_id: Default::default(),
is_success: false,
failure_message: e.to_string(),
..Default::default()
}
},
};
Expand Down
4 changes: 4 additions & 0 deletions base_layer/wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod test_utils;
pub mod transaction_service;
pub mod types;

use tari_crypto::{hash::blake2::Blake256, hash_domain, hashing::DomainSeparatedHasher};
pub use types::WalletHasher; // For use externally to the code base
pub mod util;
pub mod wallet;
Expand Down Expand Up @@ -54,3 +55,6 @@ pub type WalletSqlite = Wallet<
ContactsServiceSqliteDatabase,
KeyManagerSqliteDatabase,
>;

hash_domain!(BurntOutputDomain, "burnt_output", 1);
type BurntOutputDomainHasher = DomainSeparatedHasher<Blake256, BurntOutputDomain>;
3 changes: 3 additions & 0 deletions base_layer/wallet/src/transaction_service/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use tari_core::transactions::{
transaction_components::{EncryptionError, TransactionError},
transaction_protocol::TransactionProtocolError,
};
use tari_crypto::signatures::CommitmentSignatureError;
use tari_p2p::services::liveness::error::LivenessError;
use tari_service_framework::reply_channel::TransportChannelError;
use tari_utilities::ByteArrayError;
Expand Down Expand Up @@ -178,6 +179,8 @@ pub enum TransactionServiceError {
EncryptionError(#[from] EncryptionError),
#[error("FixedHash size error: `{0}`")]
FixedHashSizeError(#[from] FixedHashSizeError),
#[error("Commitment signature error: {0}")]
CommitmentSignatureError(#[from] CommitmentSignatureError),
}

#[derive(Debug, Error)]
Expand Down
21 changes: 18 additions & 3 deletions base_layer/wallet/src/transaction_service/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use chrono::NaiveDateTime;
use tari_common_types::{
tari_address::TariAddress,
transaction::{ImportStatus, TxId},
types::{PublicKey, Signature},
types::{BulletRangeProof, Commitment, PublicKey, Signature},
};
use tari_comms::types::CommsPublicKey;
use tari_core::{
Expand All @@ -42,6 +42,7 @@ use tari_core::{
transaction_components::{OutputFeatures, Transaction, TransactionOutput},
},
};
use tari_crypto::ristretto::RistrettoComSig;
use tari_service_framework::reply_channel::SenderService;
use tokio::sync::broadcast;
use tower::Service;
Expand Down Expand Up @@ -86,6 +87,7 @@ pub enum TransactionServiceRequest {
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroTari,
message: String,
claim_public_key: Option<PublicKey>,
},
RegisterValidatorNode {
amount: MicroTari,
Expand Down Expand Up @@ -235,6 +237,12 @@ impl fmt::Display for TransactionServiceRequest {
#[derive(Debug)]
pub enum TransactionServiceResponse {
TransactionSent(TxId),
BurntTransactionSent {
tx_id: TxId,
commitment: Commitment,
ownership_proof: Option<RistrettoComSig>,
rangeproof: BulletRangeProof,
},
TransactionCancelled,
PendingInboundTransactions(HashMap<TxId, InboundTransaction>),
PendingOutboundTransactions(HashMap<TxId, OutboundTransaction>),
Expand Down Expand Up @@ -519,18 +527,25 @@ impl TransactionServiceHandle {
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroTari,
message: String,
) -> Result<TxId, TransactionServiceError> {
claim_public_key: Option<PublicKey>,
) -> Result<(TxId, Commitment, Option<RistrettoComSig>, BulletRangeProof), TransactionServiceError> {
match self
.handle
.call(TransactionServiceRequest::BurnTari {
amount,
selection_criteria,
fee_per_gram,
message,
claim_public_key,
})
.await??
{
TransactionServiceResponse::TransactionSent(tx_id) => Ok(tx_id),
TransactionServiceResponse::BurntTransactionSent {
tx_id,
commitment,
ownership_proof,
rangeproof,
} => Ok((tx_id, commitment, ownership_proof, rangeproof)),
_ => Err(TransactionServiceError::UnexpectedApiResponse),
}
}
Expand Down
72 changes: 62 additions & 10 deletions base_layer/wallet/src/transaction_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use sha2::Sha256;
use tari_common_types::{
tari_address::TariAddress,
transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId},
types::{PrivateKey, PublicKey, Signature},
types::{Commitment, FixedHash, PrivateKey, PublicKey, RangeProof, Signature},
};
use tari_comms::types::{CommsDHKE, CommsPublicKey};
use tari_comms_dht::outbound::OutboundMessageRequester;
Expand Down Expand Up @@ -69,12 +69,14 @@ use tari_core::{
use tari_crypto::{
commitment::HomomorphicCommitmentFactory,
keys::{PublicKey as PKtrait, SecretKey},
ristretto::RistrettoComSig,
tari_utilities::ByteArray,
};
use tari_p2p::domain_message::DomainMessage;
use tari_script::{inputs, one_sided_payment_script, script, stealth_payment_script, TariScript};
use tari_service_framework::{reply_channel, reply_channel::Receiver};
use tari_shutdown::ShutdownSignal;
use tari_utilities::hex::Hex;
use tokio::{
sync::{mpsc, mpsc::Sender, oneshot, Mutex},
task::JoinHandle,
Expand Down Expand Up @@ -129,6 +131,7 @@ use crate::{
watch::Watch,
},
utxo_scanner_service::RECOVERY_KEY,
BurntOutputDomainHasher,
OperationId,
};

Expand Down Expand Up @@ -648,16 +651,25 @@ where
selection_criteria,
fee_per_gram,
message,
claim_public_key,
} => self
.burn_tari(
amount,
selection_criteria,
fee_per_gram,
message,
claim_public_key,
transaction_broadcast_join_handles,
)
.await
.map(TransactionServiceResponse::TransactionSent),
.map(|(tx_id, commitment, ownership_proof, rangeproof)| {
TransactionServiceResponse::BurntTransactionSent {
tx_id,
commitment,
ownership_proof,
rangeproof,
}
}),
TransactionServiceRequest::RegisterValidatorNode {
amount,
validator_node_public_key,
Expand Down Expand Up @@ -1362,20 +1374,24 @@ where
.await
}

/// Creates a transaction to burn some Tari
/// # Arguments
/// 'amount': The amount of Tari to send to the recipient
/// 'fee_per_gram': The amount of fee per transaction gram to be included in transaction
/// Creates a transaction to burn some Tari. The optional _claim public key_ parameter is used in the challenge of
/// the
// corresponding optional _ownership proof_ return value. Burn commitments and ownership proofs will exclusively be
// used in the 2nd layer (DAN layer). When such an _ownership proof_ is presented later on as part of some
// transaction metadata, the _claim public key_ can be revealed to enable verification of the _ownership proof_
// and the transaction can be signed with the private key corresponding to the claim public key.
#[allow(clippy::too_many_lines)]
pub async fn burn_tari(
&mut self,
amount: MicroTari,
selection_criteria: UtxoSelectionCriteria,
fee_per_gram: MicroTari,
message: String,
claim_public_key: Option<PublicKey>,
transaction_broadcast_join_handles: &mut FuturesUnordered<
JoinHandle<Result<TxId, TransactionServiceProtocolError<TxId>>>,
>,
) -> Result<TxId, TransactionServiceError> {
) -> Result<(TxId, Commitment, Option<RistrettoComSig>, RangeProof), TransactionServiceError> {
let tx_id = TxId::new_random();
let output_features = OutputFeatures::create_burn_output();
// Prepare sender part of the transaction
Expand Down Expand Up @@ -1407,16 +1423,52 @@ where
.await
.map_err(|e| TransactionServiceProtocolError::new(tx_id, e.into()))?;
let sender_message = TransactionSenderMessage::new_single_round_message(stp.get_single_round_message()?);
// TODO: Save spending key in key manager
let spend_key = PrivateKey::random(&mut OsRng);
let rtp = ReceiverTransactionProtocol::new(
sender_message,
PrivateKey::random(&mut OsRng),
spend_key,
spend_key.clone(),
&self.resources.factories,
);

let recipient_reply = rtp.get_signed_data()?.clone();

let commitment = recipient_reply.output.commitment.clone();
let range_proof = recipient_reply.output.proof.clone();
let nonce_a = PrivateKey::random(&mut OsRng);
let nonce_x = PrivateKey::random(&mut OsRng);
let pub_nonce = self.resources.factories.commitment.commit(&nonce_x, &nonce_a);
let mut ownership_proof = None;

if let Some(claim_public_key) = claim_public_key {
let hasher = BurntOutputDomainHasher::new_with_label("commitment_signature")
.chain(pub_nonce.as_bytes())
.chain(commitment.as_bytes())
.chain(claim_public_key.as_bytes());

let challenge: FixedHash = digest::Digest::finalize(hasher).into();

warn!(target: LOG_TARGET, "Pub nonce: {}", pub_nonce.to_vec().to_hex());
warn!(
target: LOG_TARGET,
"claim_public_key: {}",
claim_public_key.to_vec().to_hex()
);
warn!(target: LOG_TARGET, "Challenge: {}", challenge.to_vec().to_hex());
ownership_proof = Some(RistrettoComSig::sign(
&PrivateKey::from(amount),
&spend_key,
&nonce_a,
&nonce_x,
challenge.as_bytes(),
&*self.resources.factories.commitment,
)?);
warn!(
target: LOG_TARGET,
"Ownership proof: {}",
ownership_proof.clone().unwrap().to_vec().to_hex()
);
}
// Start finalizing

stp.add_single_recipient_info(recipient_reply)
Expand Down Expand Up @@ -1466,7 +1518,7 @@ where
),
)?;

Ok(tx_id)
Ok((tx_id, commitment, ownership_proof, range_proof))
}

pub async fn register_validator_node(
Expand Down
2 changes: 1 addition & 1 deletion comms/dht/src/store_forward/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ where S: Service<DecryptedDhtMessage, Response = (), Error = PipelineError> + Se
);

let service = self.next_service.ready_oneshot().await?;
return service.oneshot(message).await;
service.oneshot(message).await
}

async fn get_storage_priority(&self, message: &DecryptedDhtMessage) -> SafResult<Option<StoredMessagePriority>> {
Expand Down
2 changes: 2 additions & 0 deletions integration_tests/tests/cucumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3815,11 +3815,13 @@ async fn node_reached_sync(world: &mut TariWorld, node: String) {
#[when(expr = "I create a burn transaction of {int} uT from {word} at fee {int}")]
async fn burn_transaction(world: &mut TariWorld, amount: u64, wallet: String, fee: u64) {
let mut client = world.get_wallet_client(&wallet).await.unwrap();
let identity = client.identify(GetIdentityRequest {}).await.unwrap().into_inner();

let req = grpc::CreateBurnTransactionRequest {
amount,
fee_per_gram: fee,
message: "Burning some tari".to_string(),
claim_public_key: identity.public_key,
};

let result = client.create_burn_transaction(req).await.unwrap();
Expand Down

0 comments on commit e417e57

Please sign in to comment.