Skip to content

Commit

Permalink
Merge branch 'development' into confidential-monitor-commitments
Browse files Browse the repository at this point in the history
* development:
  feat(claim_burn)!: adds encrypted value to UnclaimedConfidentialOutput substate (tari-project#427)
  • Loading branch information
sdbondi committed Mar 13, 2023
2 parents 9efcb8f + a19b2d7 commit 298f2ca
Show file tree
Hide file tree
Showing 33 changed files with 349 additions and 445 deletions.
1 change: 1 addition & 0 deletions applications/tari_dan_app_grpc/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ message Instruction {
bytes claim_burn_commitment_address = 10;
bytes claim_burn_range_proof = 11;
CommitmentSignature claim_burn_proof_of_knowledge = 12;
bytes claim_burn_public_key = 13;
}

message Arg {
Expand Down
14 changes: 11 additions & 3 deletions applications/tari_dan_app_grpc/src/conversions/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,19 @@ impl TryFrom<proto::transaction::Instruction> for tari_engine_types::instruction
},
4 => Instruction::ClaimBurn {
claim: Box::new(ConfidentialClaim {
commitment_address: request.claim_burn_commitment_address.try_into()?,
public_key: PublicKey::from_bytes(&request.claim_burn_public_key)
.map_err(|e| anyhow!("claim_burn_public_key: {}", e))?,
output_address: request
.claim_burn_commitment_address
.as_slice()
.try_into()
.map_err(|e| anyhow!("claim_burn_commitment_address: {}", e))?,
range_proof: request.claim_burn_range_proof,
proof_of_knowledge: request
.claim_burn_proof_of_knowledge
.ok_or_else(|| anyhow!("claim_burn_proof_of_knowledge not provided"))?
.try_into()?,
.try_into()
.map_err(|e| anyhow!("claim_burn_proof_of_knowledge: {}", e))?,
}),
},
_ => return Err(anyhow!("invalid instruction_type")),
Expand Down Expand Up @@ -173,9 +180,10 @@ impl From<tari_engine_types::instruction::Instruction> for proto::transaction::I
},
Instruction::ClaimBurn { claim } => {
result.instruction_type = 4;
result.claim_burn_commitment_address = claim.commitment_address.to_vec();
result.claim_burn_commitment_address = claim.output_address.to_vec();
result.claim_burn_range_proof = claim.range_proof.to_vec();
result.claim_burn_proof_of_knowledge = Some(claim.proof_of_knowledge.into());
result.claim_burn_public_key = claim.public_key.to_vec();
},
}
result
Expand Down
26 changes: 18 additions & 8 deletions applications/tari_dan_app_utilities/src/base_layer_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use tari_common_types::types::{Commitment, FixedHash, FixedHashSizeError};
use tari_core::transactions::transaction_components::{
CodeTemplateRegistration,
SideChainFeature,
TransactionOutput,
ValidatorNodeRegistration,
};
use tari_crypto::tari_utilities::ByteArray;
Expand All @@ -52,9 +53,12 @@ use tari_dan_storage_sqlite::{
global::SqliteGlobalDbAdapter,
sqlite_shard_store_factory::SqliteShardStore,
};
use tari_engine_types::substate::{Substate, SubstateAddress, SubstateValue};
use tari_engine_types::{
confidential::UnclaimedConfidentialOutput,
substate::{Substate, SubstateAddress, SubstateValue},
};
use tari_shutdown::ShutdownSignal;
use tari_template_lib::models::{LayerOneCommitmentAddress, TemplateAddress};
use tari_template_lib::models::{EncryptedValue, TemplateAddress, UnclaimedConfidentialOutputAddress};
use tokio::{task, task::JoinHandle, time};

use crate::{
Expand Down Expand Up @@ -287,7 +291,7 @@ impl BaseLayerScanner {
let output_hash = output.hash();
if output.is_burned() {
info!(target: LOG_TARGET, "Found burned output: {}", output_hash);
self.register_burnt_utxo(output.commitment)?;
self.register_burnt_utxo(&output)?;
} else {
let sidechain_feature = output.features.sidechain_feature.ok_or_else(|| {
BaseLayerScannerError::InvalidSideChainUtxoResponse(
Expand Down Expand Up @@ -338,18 +342,24 @@ impl BaseLayerScanner {
Ok(())
}

fn register_burnt_utxo(&mut self, commitment: Commitment) -> Result<(), BaseLayerScannerError> {
let address = SubstateAddress::LayerOneCommitment(
LayerOneCommitmentAddress::try_from_commitment(commitment.as_bytes()).map_err(|e|
fn register_burnt_utxo(&mut self, output: &TransactionOutput) -> Result<(), BaseLayerScannerError> {
let address = SubstateAddress::UnclaimedConfidentialOutput(
UnclaimedConfidentialOutputAddress::try_from_commitment(output.commitment.as_bytes()).map_err(|e|
// Technically impossible, but anyway
BaseLayerScannerError::InvalidSideChainUtxoResponse(format!("Invalid commitment: {}", e)))?,
);
let substate = Substate::new(0, SubstateValue::LayerOneCommitment(commitment.as_bytes().to_vec()));
let substate = Substate::new(
0,
SubstateValue::UnclaimedConfidentialOutput(UnclaimedConfidentialOutput {
commitment: output.commitment.clone(),
encrypted_value: EncryptedValue(output.encrypted_value.0),
}),
);
let shard_id = ShardId::from_address(&address, 0);
self.shard_store
.with_write_tx(|tx| tx.save_burnt_utxo(&substate, address, shard_id))
.map_err(|source| BaseLayerScannerError::CouldNotRegisterBurntUtxo {
commitment: Box::new(commitment),
commitment: Box::new(output.commitment.clone()),
source,
})?;
Ok(())
Expand Down
38 changes: 23 additions & 15 deletions applications/tari_dan_wallet_cli/src/command/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ use std::{io, io::Read};
use anyhow::anyhow;
use clap::{Args, Subcommand};
use serde_json as json;
use tari_template_lib::prelude::ComponentAddress;
use tari_wallet_daemon_client::{
types::{AccountsCreateRequest, AccountsGetBalancesRequest, AccountsInvokeRequest, ClaimBurnRequest},
types::{
AccountByNameResponse,
AccountsCreateRequest,
AccountsGetBalancesRequest,
AccountsInvokeRequest,
ClaimBurnRequest,
},
WalletDaemonClient,
};

use crate::{
command::transaction::{print_execution_results, CliArg},
command::transaction::{print_execution_results, summarize_finalize_result, CliArg},
table::Table,
table_row,
};
Expand Down Expand Up @@ -79,10 +84,11 @@ pub struct GetByNameArgs {

#[derive(Debug, Args, Clone)]
pub struct ClaimBurnArgs {
#[clap(long, short = 'a')]
account_address: ComponentAddress,
#[clap(long, short = 'n', alias = "name")]
account_name: String,
/// Optional proof JSON from the L1 console wallet. If not provided, you will be prompted to enter it.
#[clap(long, short = 'j', alias = "json")]
proof_json: Option<String>,
proof_json: Option<serde_json::Value>,
#[clap(long, short = 'f')]
fee: Option<u64>,
}
Expand Down Expand Up @@ -180,12 +186,14 @@ async fn handle_get_balances(args: GetBalancesArgs, client: &mut WalletDaemonCli

pub async fn handle_claim_burn(args: ClaimBurnArgs, client: &mut WalletDaemonClient) -> Result<(), anyhow::Error> {
let ClaimBurnArgs {
account_address,
account_name,
proof_json,
fee,
} = args;

let proof_json = if let Some(proof_json) = proof_json {
let AccountByNameResponse { account_address } = client.get_by_name(account_name).await?;

let claim_proof = if let Some(proof_json) = proof_json {
proof_json
} else {
println!(
Expand All @@ -195,23 +203,23 @@ pub async fn handle_claim_burn(args: ClaimBurnArgs, client: &mut WalletDaemonCli

let mut proof_json = String::new();
io::stdin().read_to_string(&mut proof_json)?;
println!("{}", proof_json);
proof_json.trim().to_string()
json::from_str::<json::Value>(proof_json.trim()).map_err(|e| anyhow!("Failed to parse proof JSON: {}", e))?
};

let claim = json::from_str::<json::Value>(&proof_json).map_err(|e| anyhow!("Failed to parse proof JSON: {}", e))?;
println!("JSON OK");
println!("✅ Claim burn submitted");

let req = ClaimBurnRequest {
account: account_address,
claim,
account: account_address.as_component_address().unwrap(),
claim_proof,
fee: fee.unwrap_or(1),
};

client
let resp = client
.claim_burn(req)
.await
.map_err(|e| anyhow!("Failed to claim burn with error = {}", e.to_string()))?;

summarize_finalize_result(&resp.result);
Ok(())
}

Expand Down
4 changes: 2 additions & 2 deletions applications/tari_dan_wallet_cli/src/command/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ fn summarize(result: &TransactionWaitResultResponse, time_taken: Duration) {
}
}

fn summarize_finalize_result(finalize: &FinalizeResult) {
pub fn summarize_finalize_result(finalize: &FinalizeResult) {
println!("========= Substates =========");
match finalize.result {
TransactionResult::Accept(ref diff) => {
Expand All @@ -490,7 +490,7 @@ fn summarize_finalize_result(finalize: &FinalizeResult) {
SubstateValue::NonFungible(_) => {
println!(" ▶ NFT: {}", address);
},
SubstateValue::LayerOneCommitment(_) => {
SubstateValue::UnclaimedConfidentialOutput(_) => {
println!(" ▶ Layer 1 commitment: {}", address);
},
SubstateValue::NonFungibleIndex(index) => {
Expand Down
73 changes: 47 additions & 26 deletions applications/tari_dan_wallet_daemon/src/handlers/accounts.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
// Copyright 2023 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause
use std::{convert::TryFrom, str::FromStr};
use std::convert::TryFrom;

use anyhow::anyhow;
use base64;
use log::*;
use tari_common_types::types::FixedHash;
use tari_crypto::{
commitment::HomomorphicCommitment as Commitment,
ristretto::{RistrettoComSig, RistrettoPublicKey, RistrettoSecretKey},
};
use tari_common_types::types::{FixedHash, PrivateKey, PublicKey};
use tari_crypto::{commitment::HomomorphicCommitment as Commitment, ristretto::RistrettoComSig};
use tari_dan_common_types::{optional::Optional, ShardId};
use tari_dan_wallet_sdk::{apis::key_manager, models::VersionedSubstateAddress};
use tari_engine_types::{
Expand All @@ -22,10 +19,10 @@ use tari_template_builtin::ACCOUNT_TEMPLATE_ADDRESS;
use tari_template_lib::{
args,
crypto::RistrettoPublicKeyBytes,
models::{LayerOneCommitmentAddress, NonFungibleAddress},
models::{NonFungibleAddress, UnclaimedConfidentialOutputAddress},
};
use tari_transaction::Transaction;
use tari_utilities::{hex::to_hex, ByteArray};
use tari_utilities::ByteArray;
use tari_wallet_daemon_client::types::{
AccountByNameRequest,
AccountByNameResponse,
Expand Down Expand Up @@ -229,29 +226,38 @@ pub async fn handle_claim_burn(
context: &HandlerContext,
req: ClaimBurnRequest,
) -> Result<ClaimBurnResponse, anyhow::Error> {
let ClaimBurnRequest { account, claim, fee } = req;
let ClaimBurnRequest {
account,
claim_proof,
fee,
} = req;
let reciprocal_claim_public_key = PublicKey::from_bytes(&base64::decode(
claim_proof["reciprocal_claim_public_key"]
.as_str()
.ok_or_else(|| anyhow!("Missing commitment"))?,
)?)?;
let commitment = base64::decode(
claim["commitment"]
claim_proof["commitment"]
.as_str()
.ok_or_else(|| anyhow!("Missing commitment"))?,
)?;
let range_proof = base64::decode(
claim["range_proof"]
claim_proof["range_proof"]
.as_str()
.ok_or_else(|| anyhow!("Missing range_proof"))?,
)?;
let public_nonce = RistrettoPublicKey::from_bytes(&base64::decode(
claim["ownership_proof"]["public_nonce"]
let public_nonce = PublicKey::from_bytes(&base64::decode(
claim_proof["ownership_proof"]["public_nonce"]
.as_str()
.ok_or_else(|| anyhow!("Missing public nonce from ownership_proof"))?,
)?)?;
let u = RistrettoSecretKey::from_bytes(&base64::decode(
claim["ownership_proof"]["u"]
let u = PrivateKey::from_bytes(&base64::decode(
claim_proof["ownership_proof"]["u"]
.as_str()
.ok_or_else(|| anyhow!("Missing u from ownership_proof"))?,
)?)?;
let v = RistrettoSecretKey::from_bytes(&base64::decode(
claim["ownership_proof"]["v"]
let v = PrivateKey::from_bytes(&base64::decode(
claim_proof["ownership_proof"]["v"]
.as_str()
.ok_or_else(|| anyhow!("Missing v from ownership_proof"))?,
)?)?;
Expand All @@ -261,14 +267,30 @@ pub async fn handle_claim_burn(
.key_manager_api()
.get_key_or_active(key_manager::TRANSACTION_BRANCH, None)?;

let mut inputs = sdk.substate_api().load_dependent_substates(&[account.into()])?;
let mut inputs = vec![];

// Add the account component
let account_substate = sdk.substate_api().get_substate(&account.into())?;
inputs.push(account_substate.address);

// Add all versioned account child addresses as inputs
let child_addresses = sdk.substate_api().load_dependent_substates(&[account.into()])?;
inputs.extend(child_addresses);

// TODO: we assume that all inputs will be consumed and produce a new output however this is only the case when the
// object is mutated
let outputs = inputs
.iter()
.map(|versioned_addr| ShardId::from_address(&versioned_addr.address, versioned_addr.version + 1))
.collect::<Vec<_>>();

// add the commitment substate address as input to the claim burn transaction
let commitment_substate_address = VersionedSubstateAddress {
address: SubstateAddress::from_str(&format!("commitment_{}", to_hex(commitment.as_ref())))?,
address: SubstateAddress::UnclaimedConfidentialOutput(UnclaimedConfidentialOutputAddress::try_from(
commitment.as_slice(),
)?),
version: 0,
};

inputs.push(commitment_substate_address.clone());

info!(
Expand All @@ -277,9 +299,6 @@ pub async fn handle_claim_burn(
inputs.len(),
account
);
for input in &inputs {
info!(target: LOG_TARGET, "input: {}", input);
}

let inputs = inputs
.into_iter()
Expand All @@ -289,7 +308,8 @@ pub async fn handle_claim_burn(
let instructions = vec![
Instruction::ClaimBurn {
claim: Box::new(ConfidentialClaim {
commitment_address: LayerOneCommitmentAddress::try_from(commitment)?,
public_key: reciprocal_claim_public_key,
output_address: UnclaimedConfidentialOutputAddress::try_from(commitment.as_slice())?,
range_proof,
proof_of_knowledge: RistrettoComSig::new(Commitment::from_public_key(&public_nonce), u, v),
}),
Expand All @@ -307,9 +327,10 @@ pub async fn handle_claim_burn(
.with_instructions(instructions)
.with_fee(fee)
.with_inputs(inputs)
.with_outputs(outputs)
// transaction should have one output, corresponding to the same shard
// as the account substate address
// TODO: on a second claim burn, we shoulnd't have any new outputs being created.
// TODO: on a second claim burn, we shouldn't have any new outputs being created.
.with_new_outputs(1)
.sign(&signing_key.k);

Expand All @@ -324,7 +345,7 @@ pub async fn handle_claim_burn(

Ok(ClaimBurnResponse {
hash: tx_hash,
result: finalized.result,
result: finalized,
})
}

Expand Down
1 change: 1 addition & 0 deletions applications/tari_validator_node/tests/cucumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub struct TariWorld {
addresses: IndexMap<String, String>,
num_databases_saved: usize,
account_public_keys: IndexMap<String, (RistrettoSecretKey, PublicKey)>,
claim_public_keys: IndexMap<String, PublicKey>,
}

impl TariWorld {
Expand Down
Loading

0 comments on commit 298f2ca

Please sign in to comment.