2023-01-16 21:17:54 +00:00
|
|
|
use std::{
|
|
|
|
collections::{HashSet, HashMap},
|
|
|
|
str::FromStr,
|
|
|
|
};
|
|
|
|
|
2023-01-24 20:22:07 +00:00
|
|
|
use rand_core::{OsRng, RngCore};
|
|
|
|
|
|
|
|
use serde::Deserialize;
|
|
|
|
use serde_json::json;
|
2023-01-16 21:17:54 +00:00
|
|
|
|
|
|
|
use monero_rpc::{
|
2023-01-24 20:22:07 +00:00
|
|
|
monero::{
|
|
|
|
Amount, Address,
|
|
|
|
cryptonote::{hash::Hash, subaddress::Index},
|
|
|
|
util::address::PaymentId,
|
|
|
|
},
|
|
|
|
TransferOptions, WalletClient,
|
2023-01-16 21:17:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use monero_serai::{
|
2023-01-30 09:27:39 +00:00
|
|
|
transaction::Transaction,
|
2023-05-02 06:39:08 +00:00
|
|
|
rpc::{HttpRpc, Rpc},
|
2023-01-30 09:25:46 +00:00
|
|
|
wallet::{
|
|
|
|
address::{Network, AddressSpec, SubaddressIndex, MoneroAddress},
|
2023-03-11 15:31:58 +00:00
|
|
|
extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra},
|
2023-01-30 09:25:46 +00:00
|
|
|
Scanner,
|
|
|
|
},
|
2023-01-16 21:17:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
mod runner;
|
|
|
|
|
2023-01-24 20:22:07 +00:00
|
|
|
async fn make_integrated_address(payment_id: [u8; 8]) -> String {
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct IntegratedAddressResponse {
|
|
|
|
integrated_address: String,
|
|
|
|
}
|
|
|
|
|
2023-05-02 06:39:08 +00:00
|
|
|
let rpc = HttpRpc::new("http://127.0.0.1:6061".to_string()).unwrap();
|
2023-01-24 20:22:07 +00:00
|
|
|
let res = rpc
|
|
|
|
.json_rpc_call::<IntegratedAddressResponse>(
|
|
|
|
"make_integrated_address",
|
|
|
|
Some(json!({ "payment_id": hex::encode(payment_id) })),
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
res.integrated_address
|
|
|
|
}
|
|
|
|
|
2023-05-02 06:39:08 +00:00
|
|
|
async fn initialize_rpcs() -> (WalletClient, Rpc<HttpRpc>, monero_rpc::monero::Address) {
|
2023-01-16 21:17:54 +00:00
|
|
|
let wallet_rpc =
|
|
|
|
monero_rpc::RpcClientBuilder::new().build("http://127.0.0.1:6061").unwrap().wallet();
|
|
|
|
let daemon_rpc = runner::rpc().await;
|
|
|
|
|
|
|
|
let address_resp = wallet_rpc.get_address(0, None).await;
|
|
|
|
let wallet_rpc_addr = if address_resp.is_ok() {
|
|
|
|
address_resp.unwrap().address
|
|
|
|
} else {
|
2023-03-11 15:31:58 +00:00
|
|
|
wallet_rpc.create_wallet("wallet".to_string(), None, "English".to_string()).await.unwrap();
|
2023-01-16 21:17:54 +00:00
|
|
|
let addr = wallet_rpc.get_address(0, None).await.unwrap().address;
|
|
|
|
daemon_rpc.generate_blocks(&addr.to_string(), 70).await.unwrap();
|
|
|
|
addr
|
|
|
|
};
|
2023-01-24 20:22:07 +00:00
|
|
|
(wallet_rpc, daemon_rpc, wallet_rpc_addr)
|
|
|
|
}
|
|
|
|
|
2023-03-11 15:31:58 +00:00
|
|
|
async fn from_wallet_rpc_to_self(spec: AddressSpec) {
|
2023-01-24 20:22:07 +00:00
|
|
|
// initialize rpc
|
|
|
|
let (wallet_rpc, daemon_rpc, wallet_rpc_addr) = initialize_rpcs().await;
|
2023-01-16 21:17:54 +00:00
|
|
|
|
|
|
|
// make an addr
|
|
|
|
let (_, view_pair, _) = runner::random_address();
|
2023-07-08 15:29:05 +00:00
|
|
|
let addr = Address::from_str(&view_pair.address(Network::Mainnet, spec).to_string()).unwrap();
|
2023-01-16 21:17:54 +00:00
|
|
|
|
|
|
|
// refresh & make a tx
|
|
|
|
wallet_rpc.refresh(None).await.unwrap();
|
|
|
|
let tx = wallet_rpc
|
|
|
|
.transfer(
|
|
|
|
HashMap::from([(addr, Amount::ONE_XMR)]),
|
|
|
|
monero_rpc::TransferPriority::Default,
|
|
|
|
TransferOptions::default(),
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let tx_hash: [u8; 32] = tx.tx_hash.0.try_into().unwrap();
|
|
|
|
|
|
|
|
// unlock it
|
|
|
|
runner::mine_until_unlocked(&daemon_rpc, &wallet_rpc_addr.to_string(), tx_hash).await;
|
|
|
|
|
|
|
|
// create the scanner
|
|
|
|
let mut scanner = Scanner::from_view(view_pair, Some(HashSet::new()));
|
|
|
|
if let AddressSpec::Subaddress(index) = spec {
|
|
|
|
scanner.register_subaddress(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// retrieve it and confirm
|
|
|
|
let tx = daemon_rpc.get_transaction(tx_hash).await.unwrap();
|
|
|
|
let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0);
|
|
|
|
|
|
|
|
match spec {
|
|
|
|
AddressSpec::Subaddress(index) => assert_eq!(output.metadata.subaddress, Some(index)),
|
|
|
|
AddressSpec::Integrated(payment_id) => {
|
|
|
|
assert_eq!(output.metadata.payment_id, payment_id);
|
|
|
|
assert_eq!(output.metadata.subaddress, None);
|
|
|
|
}
|
2023-07-08 15:29:05 +00:00
|
|
|
AddressSpec::Standard | AddressSpec::Featured { .. } => {
|
|
|
|
assert_eq!(output.metadata.subaddress, None)
|
|
|
|
}
|
2023-01-16 21:17:54 +00:00
|
|
|
}
|
|
|
|
assert_eq!(output.commitment().amount, 1000000000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
async_sequential!(
|
2023-03-11 15:31:58 +00:00
|
|
|
async fn receipt_of_wallet_rpc_tx_standard() {
|
|
|
|
from_wallet_rpc_to_self(AddressSpec::Standard).await;
|
2023-01-16 21:17:54 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 15:31:58 +00:00
|
|
|
async fn receipt_of_wallet_rpc_tx_subaddress() {
|
|
|
|
from_wallet_rpc_to_self(AddressSpec::Subaddress(SubaddressIndex::new(0, 1).unwrap())).await;
|
2023-01-16 21:17:54 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 15:31:58 +00:00
|
|
|
async fn receipt_of_wallet_rpc_tx_integrated() {
|
2023-01-16 21:17:54 +00:00
|
|
|
let mut payment_id = [0u8; 8];
|
|
|
|
OsRng.fill_bytes(&mut payment_id);
|
2023-03-11 15:31:58 +00:00
|
|
|
from_wallet_rpc_to_self(AddressSpec::Integrated(payment_id)).await;
|
2023-01-16 21:17:54 +00:00
|
|
|
}
|
|
|
|
);
|
2023-01-24 20:22:07 +00:00
|
|
|
|
|
|
|
test!(
|
2023-03-11 15:31:58 +00:00
|
|
|
send_to_wallet_rpc_standard,
|
2023-01-24 20:22:07 +00:00
|
|
|
(
|
|
|
|
|_, mut builder: Builder, _| async move {
|
|
|
|
// initialize rpc
|
|
|
|
let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await;
|
|
|
|
|
|
|
|
// add destination
|
|
|
|
builder.add_payment(
|
|
|
|
MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr.to_string()).unwrap(),
|
|
|
|
1000000,
|
|
|
|
);
|
|
|
|
(builder.build().unwrap(), (wallet_rpc,))
|
|
|
|
},
|
|
|
|
|_, tx: Transaction, _, data: (WalletClient,)| async move {
|
|
|
|
// confirm receipt
|
|
|
|
data.0.refresh(None).await.unwrap();
|
|
|
|
let transfer =
|
|
|
|
data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap();
|
|
|
|
assert_eq!(transfer.amount.as_pico(), 1000000);
|
|
|
|
assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 });
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
test!(
|
2023-03-11 15:31:58 +00:00
|
|
|
send_to_wallet_rpc_subaddress,
|
2023-01-24 20:22:07 +00:00
|
|
|
(
|
|
|
|
|_, mut builder: Builder, _| async move {
|
|
|
|
// initialize rpc
|
|
|
|
let (wallet_rpc, _, _) = initialize_rpcs().await;
|
|
|
|
|
|
|
|
// make the addr
|
|
|
|
let (subaddress, index) = wallet_rpc.create_address(0, None).await.unwrap();
|
|
|
|
|
|
|
|
builder.add_payment(
|
|
|
|
MoneroAddress::from_str(Network::Mainnet, &subaddress.to_string()).unwrap(),
|
|
|
|
1000000,
|
|
|
|
);
|
|
|
|
(builder.build().unwrap(), (wallet_rpc, index))
|
|
|
|
},
|
|
|
|
|_, tx: Transaction, _, data: (WalletClient, u32)| async move {
|
|
|
|
// confirm receipt
|
|
|
|
data.0.refresh(None).await.unwrap();
|
|
|
|
let transfer =
|
|
|
|
data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap();
|
|
|
|
assert_eq!(transfer.amount.as_pico(), 1000000);
|
|
|
|
assert_eq!(transfer.subaddr_index, Index { major: 0, minor: data.1 });
|
2023-03-11 15:31:58 +00:00
|
|
|
|
|
|
|
// Make sure only one R was included in TX extra
|
|
|
|
assert!(Extra::read::<&[u8]>(&mut tx.prefix.extra.as_ref())
|
|
|
|
.unwrap()
|
|
|
|
.keys()
|
|
|
|
.unwrap()
|
|
|
|
.1
|
|
|
|
.is_none());
|
2023-01-24 20:22:07 +00:00
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
test!(
|
2023-03-11 15:31:58 +00:00
|
|
|
send_to_wallet_rpc_integrated,
|
2023-01-24 20:22:07 +00:00
|
|
|
(
|
|
|
|
|_, mut builder: Builder, _| async move {
|
|
|
|
// initialize rpc
|
|
|
|
let (wallet_rpc, _, _) = initialize_rpcs().await;
|
|
|
|
|
|
|
|
// make the addr
|
|
|
|
let mut payment_id = [0u8; 8];
|
|
|
|
OsRng.fill_bytes(&mut payment_id);
|
|
|
|
let addr = make_integrated_address(payment_id).await;
|
|
|
|
|
|
|
|
builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000);
|
|
|
|
(builder.build().unwrap(), (wallet_rpc, payment_id))
|
|
|
|
},
|
|
|
|
|_, tx: Transaction, _, data: (WalletClient, [u8; 8])| async move {
|
|
|
|
// confirm receipt
|
|
|
|
data.0.refresh(None).await.unwrap();
|
|
|
|
let transfer =
|
|
|
|
data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap();
|
|
|
|
assert_eq!(transfer.amount.as_pico(), 1000000);
|
|
|
|
assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 });
|
|
|
|
assert_eq!(transfer.payment_id.0, PaymentId::from_slice(&data.1));
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
2023-01-30 09:25:46 +00:00
|
|
|
|
|
|
|
test!(
|
2023-03-11 15:31:58 +00:00
|
|
|
send_to_wallet_rpc_with_arb_data,
|
2023-01-30 09:25:46 +00:00
|
|
|
(
|
|
|
|
|_, mut builder: Builder, _| async move {
|
|
|
|
// initialize rpc
|
|
|
|
let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await;
|
|
|
|
|
|
|
|
// add destination
|
|
|
|
builder.add_payment(
|
|
|
|
MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr.to_string()).unwrap(),
|
|
|
|
1000000,
|
|
|
|
);
|
|
|
|
|
2023-03-11 10:47:25 +00:00
|
|
|
// Make 2 data that is the full 255 bytes
|
2023-01-30 09:25:46 +00:00
|
|
|
for _ in 0 .. 2 {
|
2023-03-11 10:47:25 +00:00
|
|
|
// Subtract 1 since we prefix data with 127
|
|
|
|
let data = vec![b'a'; MAX_TX_EXTRA_NONCE_SIZE - 1];
|
2023-07-08 15:29:05 +00:00
|
|
|
builder.add_data(data).unwrap();
|
2023-01-30 09:25:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
(builder.build().unwrap(), (wallet_rpc,))
|
|
|
|
},
|
|
|
|
|_, tx: Transaction, _, data: (WalletClient,)| async move {
|
|
|
|
// confirm receipt
|
|
|
|
data.0.refresh(None).await.unwrap();
|
|
|
|
let transfer =
|
|
|
|
data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap();
|
|
|
|
assert_eq!(transfer.amount.as_pico(), 1000000);
|
|
|
|
assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 });
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|