Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add atomic swap refund transaction handling #3573

Merged
merged 1 commit into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions applications/tari_app_grpc/proto/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ message UnblindedOutput {
bytes sender_offset_public_key = 8;
// UTXO signature with the script offset private key, k_O
ComSignature metadata_signature = 9;
// The minimum height the script allows this output to be spent
uint64 script_lock_height = 10;
}

// ----------------------------- Network Types ----------------------------- //
Expand Down
13 changes: 12 additions & 1 deletion applications/tari_app_grpc/proto/wallet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ service Wallet {
rpc ListConnectedPeers(Empty) returns (ListConnectedPeersResponse);
// Cancel pending transaction
rpc CancelTransaction (CancelTransactionRequest) returns (CancelTransactionResponse);
// Will triggger a complete revalidation of all wallet outputs.
// Will trigger a complete revalidation of all wallet outputs.
rpc RevalidateAllTransactions (RevalidateRequest) returns (RevalidateResponse);
// This will send a XTR SHA Atomic swap transaction
rpc SendShaAtomicSwapTransaction(SendShaAtomicSwapRequest) returns (SendShaAtomicSwapResponse);
// This will claim a XTR SHA Atomic swap transaction
rpc ClaimShaAtomicSwapTransaction(ClaimShaAtomicSwapRequest) returns (ClaimShaAtomicSwapResponse);
// This will claim a HTLC refund transaction
rpc ClaimHtlcRefundTransaction(ClaimHtlcRefundRequest) returns (ClaimHtlcRefundResponse);
}

message GetVersionRequest { }
Expand Down Expand Up @@ -125,6 +127,15 @@ message ClaimShaAtomicSwapResponse {
TransferResult results = 1;
}

message ClaimHtlcRefundRequest{
string output_hash = 1;
uint64 fee_per_gram = 2;
}

message ClaimHtlcRefundResponse {
TransferResult results = 1;
}

message GetTransactionInfoRequest {
repeated uint64 transaction_ids = 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl From<UnblindedOutput> for grpc::UnblindedOutput {
signature_u: Vec::from(output.metadata_signature.u().as_bytes()),
signature_v: Vec::from(output.metadata_signature.v().as_bytes()),
}),
script_lock_height: output.script_lock_height,
}
}
}
Expand Down Expand Up @@ -91,6 +92,7 @@ impl TryFrom<grpc::UnblindedOutput> for UnblindedOutput {
script_private_key,
sender_offset_public_key,
metadata_signature,
script_lock_height: output.script_lock_height,
})
}
}
1 change: 1 addition & 0 deletions applications/tari_base_node/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ async fn build_node_context(
Box::new(TxInternalConsistencyValidator::new(
factories.clone(),
config.base_node_bypass_range_proof_verification,
blockchain_db.clone(),
)),
Box::new(TxInputAndMaturityValidator::new(blockchain_db.clone())),
Box::new(TxConsensusValidator::new(blockchain_db.clone())),
Expand Down
14 changes: 14 additions & 0 deletions applications/tari_console_wallet/src/automation/command_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl Display for ParsedCommand {
ClearCustomBaseNode => "clear-custom-base-node",
InitShaAtomicSwap => "init-sha-atomic-swap",
FinaliseShaAtomicSwap => "finalise-sha-atomic-swap",
ClaimShaAtomicSwapRefund => "claim-sha-atomic-swap-refund",
};

let args = self
Expand Down Expand Up @@ -130,6 +131,7 @@ pub fn parse_command(command: &str) -> Result<ParsedCommand, ParseError> {
ClearCustomBaseNode => Vec::new(),
InitShaAtomicSwap => parse_init_sha_atomic_swap(args)?,
FinaliseShaAtomicSwap => parse_finalise_sha_atomic_swap(args)?,
ClaimShaAtomicSwapRefund => parse_claim_htlc_refund_refund(args)?,
};

Ok(ParsedCommand { command, args })
Expand Down Expand Up @@ -219,6 +221,18 @@ fn parse_finalise_sha_atomic_swap(mut args: SplitWhitespace) -> Result<Vec<Parse
Ok(parsed_args)
}

fn parse_claim_htlc_refund_refund(mut args: SplitWhitespace) -> Result<Vec<ParsedArgument>, ParseError> {
let mut parsed_args = Vec::new();
// hash
let hash = args
.next()
.ok_or_else(|| ParseError::Empty("Output hash".to_string()))?;
let hash = parse_hash(hash).ok_or(ParseError::Hash)?;
parsed_args.push(ParsedArgument::Hash(hash));

Ok(parsed_args)
}

fn parse_make_it_rain(mut args: SplitWhitespace) -> Result<Vec<ParsedArgument>, ParseError> {
let mut parsed_args = Vec::new();

Expand Down
27 changes: 27 additions & 0 deletions applications/tari_console_wallet/src/automation/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum WalletCommand {
ClearCustomBaseNode,
InitShaAtomicSwap,
FinaliseShaAtomicSwap,
ClaimShaAtomicSwapRefund,
}

#[derive(Debug, EnumString, PartialEq, Clone)]
Expand Down Expand Up @@ -205,6 +206,27 @@ pub async fn finalise_sha_atomic_swap(
Ok(tx_id)
}

/// claims a HTLC refund transaction
pub async fn claim_htlc_refund(
mut output_service: OutputManagerHandle,
mut transaction_service: TransactionServiceHandle,
args: Vec<ParsedArgument>,
) -> Result<TxId, CommandError> {
use ParsedArgument::*;
let output = match args[0].clone() {
Hash(output) => Ok(output),
_ => Err(CommandError::Argument),
}?;

let (tx_id, fee, amount, tx) = output_service
.create_htlc_refund_transaction(output, MicroTari(25))
.await?;
transaction_service
.submit_transaction(tx_id, tx, fee, amount, "Claimed HTLC refund".into())
.await?;
Ok(tx_id)
}

/// Send a one-sided transaction to a recipient
pub async fn send_one_sided(
mut wallet_transaction_service: TransactionServiceHandle,
Expand Down Expand Up @@ -759,6 +781,11 @@ pub async fn command_runner(
debug!(target: LOG_TARGET, "claiming tari HTLC tx_id {}", tx_id);
tx_ids.push(tx_id);
},
ClaimShaAtomicSwapRefund => {
let tx_id = claim_htlc_refund(output_service.clone(), transaction_service.clone(), parsed.args).await?;
debug!(target: LOG_TARGET, "claiming tari HTLC tx_id {}", tx_id);
tx_ids.push(tx_id);
},
}
}

Expand Down
56 changes: 54 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 @@ -7,6 +7,8 @@ use tari_app_grpc::{
tari_rpc::{
payment_recipient::PaymentType,
wallet_server,
ClaimHtlcRefundRequest,
ClaimHtlcRefundResponse,
ClaimShaAtomicSwapRequest,
ClaimShaAtomicSwapResponse,
CoinSplitRequest,
Expand Down Expand Up @@ -189,7 +191,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
"Transaction broadcast: {}, preimage_hex: {}, hash {}",
tx_id,
pre_image.to_hex(),
output.to_string()
output.hash().to_hex()
);
SendShaAtomicSwapResponse {
transaction_id: tx_id,
Expand Down Expand Up @@ -226,7 +228,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
.map_err(|_| Status::internal("pre_image is malformed".to_string()))?;
let output = BlockHash::from_hex(&message.output)
.map_err(|_| Status::internal("Output hash is malformed".to_string()))?;

debug!(target: LOG_TARGET, "Trying to claim HTLC with hash {}", output.to_hex());
let mut transaction_service = self.get_transaction_service();
let mut output_manager_service = self.get_output_manager_service();
let response = match output_manager_service
Expand Down Expand Up @@ -274,6 +276,56 @@ impl wallet_server::Wallet for WalletGrpcServer {
}))
}

async fn claim_htlc_refund_transaction(
&self,
request: Request<ClaimHtlcRefundRequest>,
) -> Result<Response<ClaimHtlcRefundResponse>, Status> {
let message = request.into_inner();
let output = BlockHash::from_hex(&message.output_hash)
.map_err(|_| Status::internal("Output hash is malformed".to_string()))?;

let mut transaction_service = self.get_transaction_service();
let mut output_manager_service = self.get_output_manager_service();
debug!(target: LOG_TARGET, "Trying to claim HTLC with hash {}", output.to_hex());
let response = match output_manager_service
.create_htlc_refund_transaction(output, message.fee_per_gram.into())
.await
{
Ok((tx_id, fee, amount, tx)) => {
match transaction_service
.submit_transaction(tx_id, tx, fee, amount, "Creating HTLC refund transaction".to_string())
.await
{
Ok(()) => TransferResult {
address: Default::default(),
transaction_id: tx_id,
is_success: true,
failure_message: Default::default(),
},
Err(e) => TransferResult {
address: Default::default(),
transaction_id: Default::default(),
is_success: false,
failure_message: e.to_string(),
},
}
},
Err(e) => {
warn!(target: LOG_TARGET, "Failed to claim HTLC refund transaction: {}", e);
TransferResult {
address: Default::default(),
transaction_id: Default::default(),
is_success: false,
failure_message: e.to_string(),
}
},
};

Ok(Response::new(ClaimHtlcRefundResponse {
results: Some(response),
}))
}

async fn transfer(&self, request: Request<TransferRequest>) -> Result<Response<TransferResponse>, Status> {
let message = request.into_inner();
let recipients = message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,12 @@ mod test {
.unwrap();

let factories = CryptoFactories::default();
let mut stx_protocol = stx_builder.build::<HashDigest>(&factories).unwrap();
stx_protocol.finalize(KernelFeatures::empty(), &factories).unwrap();
let mut stx_protocol = stx_builder
.build::<HashDigest>(&factories, None, Some(u64::MAX))
.unwrap();
stx_protocol
.finalize(KernelFeatures::empty(), &factories, None, Some(u64::MAX))
.unwrap();

let tx3 = stx_protocol.get_transaction().unwrap().clone();

Expand Down
15 changes: 13 additions & 2 deletions base_layer/core/src/transactions/aggregated_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ use log::*;
use serde::{Deserialize, Serialize};
use std::{
cmp::max,
convert::TryInto,
fmt::{Display, Error, Formatter},
};
use tari_common_types::types::{
BlindingFactor,
Commitment,
CommitmentFactory,
HashOutput,
PrivateKey,
PublicKey,
RangeProofService,
Expand All @@ -55,6 +57,7 @@ use tari_crypto::{
commitment::HomomorphicCommitmentFactory,
keys::PublicKey as PublicKeyTrait,
ristretto::pedersen::PedersenCommitment,
script::ScriptContext,
tari_utilities::hex::Hex,
};

Expand Down Expand Up @@ -342,13 +345,16 @@ impl AggregateBody {
/// This function does NOT check that inputs come from the UTXO set
/// The reward is the total amount of Tari rewarded for this block (block reward + total fees), this should be 0
/// for a transaction
#[allow(clippy::too_many_arguments)]
pub fn validate_internal_consistency(
&self,
tx_offset: &BlindingFactor,
script_offset: &BlindingFactor,
bypass_range_proof_verification: bool,
total_reward: MicroTari,
factories: &CryptoFactories,
prev_header: Option<HashOutput>,
height: Option<u64>,
) -> Result<(), TransactionError> {
self.verify_kernel_signatures()?;

Expand All @@ -361,7 +367,7 @@ impl AggregateBody {
self.verify_metadata_signatures()?;

let script_offset_g = PublicKey::from_secret_key(script_offset);
self.validate_script_offset(script_offset_g, &factories.commitment)
self.validate_script_offset(script_offset_g, &factories.commitment, prev_header, height)
}

pub fn dissolve(self) -> (Vec<TransactionInput>, Vec<TransactionOutput>, Vec<TransactionKernel>) {
Expand Down Expand Up @@ -425,12 +431,17 @@ impl AggregateBody {
&self,
script_offset: PublicKey,
factory: &CommitmentFactory,
prev_header: Option<HashOutput>,
height: Option<u64>,
) -> Result<(), TransactionError> {
trace!(target: LOG_TARGET, "Checking script offset");
// lets count up the input script public keys
let mut input_keys = PublicKey::default();
let prev_hash: [u8; 32] = prev_header.unwrap_or_default().as_slice().try_into().unwrap_or([0; 32]);
let height = height.unwrap_or_default();
philipr-za marked this conversation as resolved.
Show resolved Hide resolved
for input in &self.inputs {
input_keys = input_keys + input.run_and_verify_script(factory)?;
let context = ScriptContext::new(height, &prev_hash, &input.commitment);
input_keys = input_keys + input.run_and_verify_script(factory, Some(context))?;
}

// Now lets gather the output public keys and hashes.
Expand Down
7 changes: 5 additions & 2 deletions base_layer/core/src/transactions/coinbase_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ impl CoinbaseBuilder {
script_private_key,
sender_offset_public_key,
metadata_sig,
0,
);
let output = if let Some(rewind_data) = self.rewind_data.as_ref() {
unblinded_output
Expand Down Expand Up @@ -235,7 +236,7 @@ impl CoinbaseBuilder {
.with_reward(total_reward)
.with_kernel(kernel);
let tx = builder
.build(&self.factories)
.build(&self.factories, None, Some(height))
.map_err(|e| CoinbaseBuildError::BuildError(e.to_string()))?;
Ok((tx, unblinded_output))
}
Expand Down Expand Up @@ -525,7 +526,9 @@ mod test {
&PrivateKey::default(),
false,
block_reward,
&factories
&factories,
None,
Some(u64::MAX)
),
Ok(())
);
Expand Down
14 changes: 10 additions & 4 deletions base_layer/core/src/transactions/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ impl TestParams {
self.script_private_key.clone(),
self.sender_offset_public_key.clone(),
metadata_signature,
0,
)
}

Expand Down Expand Up @@ -444,8 +445,10 @@ pub fn create_transaction_with(
stx_builder.with_output(utxo, script_offset_pvt_key).unwrap();
});

let mut stx_protocol = stx_builder.build::<Blake256>(&factories).unwrap();
stx_protocol.finalize(KernelFeatures::empty(), &factories).unwrap();
let mut stx_protocol = stx_builder.build::<Blake256>(&factories, None, Some(u64::MAX)).unwrap();
stx_protocol
.finalize(KernelFeatures::empty(), &factories, None, Some(u64::MAX))
.unwrap();
stx_protocol.take_transaction().unwrap()
}

Expand Down Expand Up @@ -513,7 +516,7 @@ pub fn spend_utxos(schema: TransactionSchema) -> (Transaction, Vec<UnblindedOutp
.unwrap();
}

let mut stx_protocol = stx_builder.build::<Blake256>(&factories).unwrap();
let mut stx_protocol = stx_builder.build::<Blake256>(&factories, None, Some(u64::MAX)).unwrap();
let change = stx_protocol.get_change_amount().unwrap();
// The change output is assigned its own random script offset private key
let change_sender_offset_public_key = stx_protocol.get_change_sender_offset_public_key().unwrap().unwrap();
Expand All @@ -539,9 +542,12 @@ pub fn spend_utxos(schema: TransactionSchema) -> (Transaction, Vec<UnblindedOutp
test_params_change_and_txn.script_private_key.clone(),
change_sender_offset_public_key,
metadata_sig,
0,
);
outputs.push(change_output);
stx_protocol.finalize(KernelFeatures::empty(), &factories).unwrap();
stx_protocol
.finalize(KernelFeatures::empty(), &factories, None, Some(u64::MAX))
.unwrap();
let txn = stx_protocol.get_transaction().unwrap().clone();
(txn, outputs, test_params_change_and_txn)
}
Expand Down
Loading