Skip to content

Commit 12db85d

Browse files
authored
feat: import transactions via grpc (#7078)
Description --- In Tari Universe we want to import tx when view wallet instance is running. It's only possible via grpc due to exclusive file lock. * also print out tx_id when send-one-sided completed to export the tx easily Motivation and Context --- How Has This Been Tested? --- https://drive.google.com/file/d/1iV-cLxqvnTBX0QSs6lAzqg55Zn5aGOu2/view What process can a PR reviewer use to test or verify this change? --- <!-- 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 --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] 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 --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Added the ability to import transactions into the wallet via a new gRPC method. - Transaction IDs of sent one-sided transactions to stealth addresses are now displayed in the console. - Users receive notifications and balance updates when transactions are imported. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 4848150 commit 12db85d

File tree

6 files changed

+93
-44
lines changed

6 files changed

+93
-44
lines changed

applications/minotari_app_grpc/proto/wallet.proto

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ service Wallet {
159159
// ```
160160
rpc GetAddress (Empty) returns (GetAddressResponse);
161161

162-
// This RPC returns addresses generated for a specific payment ID. It provides both the interactive
163-
// and one-sided addresses for the given payment ID, along with their respective representations in
162+
// This RPC returns addresses generated for a specific payment ID. It provides both the interactive
163+
// and one-sided addresses for the given payment ID, along with their respective representations in
164164
// base58 and emoji formats.
165165
//
166166
// Example usage (JavaScript):
@@ -200,7 +200,7 @@ service Wallet {
200200
// - Raw binary
201201
// - Base58-encoded (human-readable)
202202
// - Emoji-encoded (for fun and friendliness)
203-
//
203+
//
204204
// Example usage (JavaScript with gRPC):
205205
//
206206
// ```js
@@ -262,18 +262,18 @@ service Wallet {
262262
// }
263263
// ```
264264
rpc Transfer (TransferRequest) returns (TransferResponse);
265-
265+
266266
// Returns the transaction details for the given transaction IDs.
267267
//
268268
// The GetTransactionInfo RPC retrieves detailed information about specific transactions based on their IDs.
269269
// The response includes details such as transaction status, direction, amount, fee, and more.
270270
//
271271
// ### Request Parameters:
272272
//
273-
// - `transaction_ids` (required):
274-
// - **Type**: `repeated uint64`
275-
// - **Description**: A list of transaction IDs to query.
276-
// - **Restrictions**:
273+
// - `transaction_ids` (required):
274+
// - **Type**: `repeated uint64`
275+
// - **Description**: A list of transaction IDs to query.
276+
// - **Restrictions**:
277277
// - Must contain at least one ID.
278278
// - All IDs must be valid unsigned 64-bit integers.
279279
// - Duplicates will be ignored; only the first occurrence is processed.
@@ -440,7 +440,7 @@ service Wallet {
440440
//
441441
// ### Request Parameters:
442442
//
443-
// - *(none)*
443+
// - *(none)*
444444
// - This method uses an empty request body (`google.protobuf.Empty`).
445445
// - No filters or arguments are required.
446446
//
@@ -470,29 +470,29 @@ service Wallet {
470470
//
471471
// ### Request Parameters:
472472
//
473-
// - `amount_per_split` (required):
474-
// - **Type**: `uint64`
475-
// - **Description**: The value of each individual output in the split.
473+
// - `amount_per_split` (required):
474+
// - **Type**: `uint64`
475+
// - **Description**: The value of each individual output in the split.
476476
// - **Restrictions**: Must be greater than zero.
477477
//
478-
// - `split_count` (required):
479-
// - **Type**: `uint64`
480-
// - **Description**: The number of outputs to create.
478+
// - `split_count` (required):
479+
// - **Type**: `uint64`
480+
// - **Description**: The number of outputs to create.
481481
// - **Restrictions**: Must be greater than zero and within practical system limits.
482482
//
483-
// - `fee_per_gram` (required):
484-
// - **Type**: `uint64`
485-
// - **Description**: The transaction fee rate (per gram of weight).
483+
// - `fee_per_gram` (required):
484+
// - **Type**: `uint64`
485+
// - **Description**: The transaction fee rate (per gram of weight).
486486
// - **Restrictions**: Should be set high enough to ensure confirmation.
487487
//
488-
// - `lock_height` (optional):
489-
// - **Type**: `uint64`
490-
// - **Description**: The earliest block height at which the transaction becomes valid.
488+
// - `lock_height` (optional):
489+
// - **Type**: `uint64`
490+
// - **Description**: The earliest block height at which the transaction becomes valid.
491491
// - **Restrictions**: Defaults to 0 if not specified.
492492
//
493-
// - `payment_id` (optional):
494-
// - **Type**: `bytes`
495-
// - **Description**: A user-defined identifier for tracking or referencing the transaction.
493+
// - `payment_id` (optional):
494+
// - **Type**: `bytes`
495+
// - **Description**: A user-defined identifier for tracking or referencing the transaction.
496496
// - **Restrictions**: Optional; can be left empty.
497497
//
498498
// ### Example JavaScript gRPC client usage:
@@ -528,17 +528,17 @@ service Wallet {
528528
//
529529
// ### Request Parameters:
530530
//
531-
// - `outputs` (required):
532-
// - **Type**: `repeated UnblindedOutput`
533-
// - **Description**: A list of unblinded outputs to import into the wallet.
534-
// - **Restrictions**:
531+
// - `outputs` (required):
532+
// - **Type**: `repeated UnblindedOutput`
533+
// - **Description**: A list of unblinded outputs to import into the wallet.
534+
// - **Restrictions**:
535535
// - Each output must be valid and convertible to an internal UTXO format.
536536
// - The list must contain at least one item.
537537
//
538-
// - `payment_id` (optional):
539-
// - **Type**: `bytes`
540-
// - **Description**: An optional user-defined identifier to associate with the imported outputs.
541-
// - **Restrictions**:
538+
// - `payment_id` (optional):
539+
// - **Type**: `bytes`
540+
// - **Description**: An optional user-defined identifier to associate with the imported outputs.
541+
// - **Restrictions**:
542542
// - Can be left empty if not needed.
543543
// - Must be a valid byte string if provided.
544544
//
@@ -572,7 +572,7 @@ service Wallet {
572572
//
573573
// ### Request Parameters:
574574
//
575-
// - *(none)*
575+
// - *(none)*
576576
// - This method uses an empty request body (`google.protobuf.Empty`).
577577
// - No filters or arguments are required.
578578
//
@@ -599,16 +599,16 @@ service Wallet {
599599
//
600600
// The `status` field indicates the current network connectivity of the wallet. Possible values are:
601601
//
602-
// - `ONLINE`:
603-
// - The wallet is fully connected to the network and functioning normally.
602+
// - `ONLINE`:
603+
// - The wallet is fully connected to the network and functioning normally.
604604
// - The node has enough active peer connections to operate efficiently.
605605
//
606-
// - `DEGRADED`:
607-
// - The wallet is connected to some peers but not enough to maintain full functionality.
606+
// - `DEGRADED`:
607+
// - The wallet is connected to some peers but not enough to maintain full functionality.
608608
// - This could indicate issues with network connectivity, such as intermittent disconnections or insufficient peers, leading to reduced performance or reliability.
609609
//
610-
// - `OFFLINE`:
611-
// - The wallet is not connected to any peers.
610+
// - `OFFLINE`:
611+
// - The wallet is not connected to any peers.
612612
// - This status means the wallet is unable to communicate with the network and cannot perform any network-related operations.
613613
//
614614
rpc GetNetworkStatus(Empty) returns (NetworkStatusResponse);
@@ -621,7 +621,7 @@ service Wallet {
621621
//
622622
// ### Request Parameters:
623623
//
624-
// - *(none)*
624+
// - *(none)*
625625
// - This method uses an empty request body (`google.protobuf.Empty`).
626626
// - No filters or arguments are required.
627627
//
@@ -681,7 +681,7 @@ service Wallet {
681681
// Cancels a specific transaction by its ID.
682682
//
683683
// The `CancelTransaction` call allows a transaction to be cancelled by its unique transaction ID (TxId).
684-
// If the cancellation is successful, the response will indicate success. Otherwise, the response will
684+
// If the cancellation is successful, the response will indicate success. Otherwise, the response will
685685
// contain a failure message with the reason for the failure.
686686
//
687687
// ### Request Parameters:
@@ -723,13 +723,13 @@ service Wallet {
723723

724724
// Sends a XTR SHA Atomic Swap transaction.
725725
//
726-
// The `SendShaAtomicSwapTransaction` call is used to initiate an Atomic Swap
727-
// transaction using SHA. It allows the sender to send a payment to the recipient
726+
// The `SendShaAtomicSwapTransaction` call is used to initiate an Atomic Swap
727+
// transaction using SHA. It allows the sender to send a payment to the recipient
728728
// in exchange for an atomic swap, with SHA used as the secret for the swap.
729729
// The method accepts the recipient's information and initiates the transaction.
730730
//
731731
// ### Request Parameters:
732-
// - **recipient** (required): A PaymentRecipient object containing the recipient's address,
732+
// - **recipient** (required): A PaymentRecipient object containing the recipient's address,
733733
// the amount to be swapped, the fee per gram, and the payment ID to identify the transaction.
734734
//
735735
// ### Response Fields:
@@ -997,6 +997,8 @@ service Wallet {
997997
rpc StreamTransactionEvents(TransactionEventRequest) returns (stream TransactionEventResponse);
998998

999999
rpc RegisterValidatorNode(RegisterValidatorNodeRequest) returns (RegisterValidatorNodeResponse);
1000+
1001+
rpc ImportTransactions(ImportTransactionsRequest) returns (ImportTransactionsResponse);
10001002
}
10011003

10021004

@@ -1355,3 +1357,11 @@ message RegisterValidatorNodeResponse {
13551357
bool is_success = 2;
13561358
string failure_message = 3;
13571359
}
1360+
1361+
message ImportTransactionsRequest {
1362+
string txs = 1;
1363+
}
1364+
1365+
message ImportTransactionsResponse {
1366+
repeated uint64 tx_ids = 1;
1367+
}

applications/minotari_console_wallet/src/automation/commands.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,7 @@ pub async fn command_runner(
20622062
target: LOG_TARGET,
20632063
"send-one-sided-to-stealth-address concluded with tx_id {}", tx_id
20642064
);
2065+
println!("Transaction ID: {}", tx_id);
20652066
tx_ids.push(tx_id);
20662067
},
20672068
Err(e) => eprintln!("SendOneSidedToStealthAddress error! {}", e),

applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ use minotari_app_grpc::tari_rpc::{
6565
GetUnspentAmountsResponse,
6666
GetVersionRequest,
6767
GetVersionResponse,
68+
ImportTransactionsRequest,
69+
ImportTransactionsResponse,
6870
ImportUtxosRequest,
6971
ImportUtxosResponse,
7072
RegisterValidatorNodeRequest,
@@ -1251,6 +1253,28 @@ impl wallet_server::Wallet for WalletGrpcServer {
12511253
};
12521254
Ok(Response::new(response))
12531255
}
1256+
1257+
async fn import_transactions(
1258+
&self,
1259+
request: Request<ImportTransactionsRequest>,
1260+
) -> Result<Response<ImportTransactionsResponse>, Status> {
1261+
let request = request.into_inner();
1262+
let txs: Vec<WalletTransaction> = serde_json::from_str(&request.txs)
1263+
.map_err(|_| Status::invalid_argument("Could not parse transactions. Use valid JSON format."))?;
1264+
info!(target: LOG_TARGET, "Importing {:?} transactions", txs.len());
1265+
1266+
let mut transaction_service = self.get_transaction_service();
1267+
let mut tx_ids = Vec::new();
1268+
for tx in txs {
1269+
match transaction_service.import_transaction(tx).await {
1270+
Ok(id) => {
1271+
tx_ids.push(id.into());
1272+
},
1273+
Err(e) => eprintln!("Could not import tx {}", e),
1274+
};
1275+
}
1276+
Ok(Response::new(ImportTransactionsResponse { tx_ids }))
1277+
}
12541278
}
12551279

12561280
async fn handle_completed_tx(

applications/minotari_console_wallet/src/ui/state/wallet_event_monitor.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ impl WalletEventMonitor {
168168
self.trigger_full_tx_state_refresh().await;
169169
self.trigger_balance_refresh();
170170
},
171+
TransactionEvent::TransactionImported(tx_id) => {
172+
self.trigger_tx_state_refresh(tx_id).await;
173+
self.trigger_balance_refresh();
174+
self.add_notification(
175+
format!("Transaction Imported - TxId: {}", tx_id)
176+
).await;
177+
},
171178
// Only the above variants trigger state refresh
172179
_ => (),
173180
}

base_layer/wallet/src/transaction_service/handle.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ pub enum TransactionEvent {
490490
num_confirmations: u64,
491491
is_valid: bool,
492492
},
493+
TransactionImported(TxId),
493494
TransactionValidationStateChanged(OperationId),
494495
TransactionValidationCompleted(OperationId),
495496
TransactionValidationFailed(OperationId, u64),
@@ -551,6 +552,9 @@ impl fmt::Display for TransactionEvent {
551552
{is_valid}",
552553
)
553554
},
555+
TransactionEvent::TransactionImported(tx) => {
556+
write!(f, "TransactionImported for {tx}")
557+
},
554558
TransactionEvent::Error(error) => {
555559
write!(f, "Error:{error}")
556560
},

base_layer/wallet/src/transaction_service/service.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,9 @@ where
946946
tx_id
947947
},
948948
};
949+
let _size = self
950+
.event_publisher
951+
.send(Arc::new(TransactionEvent::TransactionImported(tx_id)));
949952
Ok(TransactionServiceResponse::TransactionImported(tx_id))
950953
},
951954
TransactionServiceRequest::ImportUtxoWithStatus {

0 commit comments

Comments
 (0)