mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-05-19 23:20:30 -04:00
feat(swap): Use art_client
to dial over Tor (#196)
- Upgrade `sqlx` to `0.8` - Use `arti_client@0.24` in combination with [`libp2p-community-tor`](https://crates.io/crates/libp2p-community-tor/0.4.1). https://github.com/umgefahren/libp2p-tor/pull/18 was required for this. - Display spinner in GUI while Tor circuits are being established - Remove unused dependencies (`once_cell`, `tauri-plugin-devtools`, `digest`, `hyper`, `itertools`, `erased_serde`) - Bundle roboto font from npm registry
This commit is contained in:
parent
3aef92e848
commit
6cd228fada
41 changed files with 2689 additions and 871 deletions
|
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
- CLI + GUI: Tor is now bundled with the application. All libp2p connections between peers are routed through Tor, if the `--enable-tor` flag is set. The `--tor-socks5-port` argument has been removed. This feature is powered by [arti](https://tpo.pages.torproject.net/core/arti/), an implementation of the Tor protocol in Rust by the Tor Project.
|
||||
|
||||
## [1.0.0-rc.5] - 2024-11-19
|
||||
|
||||
- GUI: Set new Discord invite link to non-expired one
|
||||
|
|
2703
Cargo.lock
generated
2703
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,36 +1,35 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/renderer/index.tsx"></script>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
-webkit-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/renderer/index.tsx"></script>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
-webkit-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -15,6 +15,7 @@
|
|||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.1.0",
|
||||
"@material-ui/core": "^4.12.4",
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||
|
@ -66,4 +67,4 @@
|
|||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ export interface CliLog {
|
|||
name: CliLogSpanType;
|
||||
[index: string]: unknown;
|
||||
}[];
|
||||
target?: string;
|
||||
}
|
||||
|
||||
function isCliLog(log: unknown): log is CliLog {
|
||||
|
|
|
@ -13,6 +13,7 @@ import { useSettings } from "store/hooks";
|
|||
import { themes } from "./theme";
|
||||
import { useEffect } from "react";
|
||||
import { setupBackgroundTasks } from "renderer/background";
|
||||
import "@fontsource/roboto";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
innerContent: {
|
||||
|
|
|
@ -57,6 +57,12 @@ export default function DaemonStatusAlert() {
|
|||
Opening the local database
|
||||
</LoadingSpinnerAlert>
|
||||
);
|
||||
case "EstablishingTorCircuits":
|
||||
return (
|
||||
<LoadingSpinnerAlert severity="warning">
|
||||
Connecting to the Tor network
|
||||
</LoadingSpinnerAlert>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "Available":
|
||||
|
|
|
@ -5,7 +5,7 @@ import { logsToRawString } from "utils/parseUtils";
|
|||
import ScrollablePaperTextBox from "./ScrollablePaperTextBox";
|
||||
|
||||
function RenderedCliLog({ log }: { log: CliLog }) {
|
||||
const { timestamp, level, fields } = log;
|
||||
const { timestamp, level, fields, target } = log;
|
||||
|
||||
const levelColorMap = {
|
||||
DEBUG: "#1976d2", // Blue
|
||||
|
@ -29,6 +29,9 @@ function RenderedCliLog({ log }: { log: CliLog }) {
|
|||
size="small"
|
||||
style={{ backgroundColor: levelColorMap[level], color: "white" }}
|
||||
/>
|
||||
{target && (
|
||||
<Chip label={target.split("::")[0]} size="small" variant="outlined" />
|
||||
)}
|
||||
<Chip label={timestamp} size="small" variant="outlined" />
|
||||
<Typography variant="subtitle2">{fields.message}</Typography>
|
||||
</Box>
|
||||
|
|
|
@ -399,6 +399,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843"
|
||||
integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
|
||||
|
||||
"@fontsource/roboto@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-5.1.0.tgz#00230737ec09c60ae877a5e33d067c0607fdd5ba"
|
||||
integrity sha512-cFRRC1s6RqPygeZ8Uw/acwVHqih8Czjt6Q0MwoUoDe9U3m4dH1HmNDRBZyqlMSFwgNAUKgFImncKdmDHyKpwdg==
|
||||
|
||||
"@humanwhocodes/module-importer@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
|
||||
|
|
|
@ -16,14 +16,12 @@ tauri-build = { version = "2.0", features = [ "config-json5" ] }
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
once_cell = "1"
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
serde_json = "1"
|
||||
swap = { path = "../swap", features = [ "tauri" ] }
|
||||
sysinfo = "=0.32.0"
|
||||
tauri = { version = "2.0", features = [ "config-json5" ] }
|
||||
tauri-plugin-clipboard-manager = "2.0"
|
||||
tauri-plugin-devtools = "2.0"
|
||||
tauri-plugin-process = "2.0"
|
||||
tauri-plugin-shell = "2.0"
|
||||
tauri-plugin-store = "2.1.0"
|
||||
|
|
|
@ -299,6 +299,7 @@ async fn initialize_context(
|
|||
})
|
||||
.with_json(false)
|
||||
.with_debug(true)
|
||||
.with_tor(true)
|
||||
.with_tauri(tauri_handle.clone())
|
||||
.build()
|
||||
.await;
|
||||
|
|
20
swap/.sqlx/query-081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6.json
generated
Normal file
20
swap/.sqlx/query-081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT peer_id\n FROM peers\n WHERE swap_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "peer_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6"
|
||||
}
|
12
swap/.sqlx/query-0ab84c094964968e96a3f2bf590d9ae92227d057386921e0e57165b887de3c75.json
generated
Normal file
12
swap/.sqlx/query-0ab84c094964968e96a3f2bf590d9ae92227d057386921e0e57165b887de3c75.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n insert into peer_addresses (\n peer_id,\n address\n ) values (?, ?);\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0ab84c094964968e96a3f2bf590d9ae92227d057386921e0e57165b887de3c75"
|
||||
}
|
20
swap/.sqlx/query-0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c.json
generated
Normal file
20
swap/.sqlx/query-0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT min(entered_at) as start_date\n FROM swap_states\n WHERE swap_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "start_date",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c"
|
||||
}
|
12
swap/.sqlx/query-2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225.json
generated
Normal file
12
swap/.sqlx/query-2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n insert into peers (\n swap_id,\n peer_id\n ) values (?, ?);\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225"
|
||||
}
|
12
swap/.sqlx/query-50a5764546f69c118fa0b64120da50f51073d36257d49768de99ff863e3511e0.json
generated
Normal file
12
swap/.sqlx/query-50a5764546f69c118fa0b64120da50f51073d36257d49768de99ff863e3511e0.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n insert into monero_addresses (\n swap_id,\n address\n ) values (?, ?);\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "50a5764546f69c118fa0b64120da50f51073d36257d49768de99ff863e3511e0"
|
||||
}
|
26
swap/.sqlx/query-5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8.json
generated
Normal file
26
swap/.sqlx/query-5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8.json
generated
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT swap_id, state\n FROM (\n SELECT max(id), swap_id, state\n FROM swap_states\n GROUP BY swap_id\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "swap_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8"
|
||||
}
|
20
swap/.sqlx/query-88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf.json
generated
Normal file
20
swap/.sqlx/query-88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT state\n FROM swap_states\n WHERE swap_id = ?\n ORDER BY id desc\n LIMIT 1;\n\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "state",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf"
|
||||
}
|
20
swap/.sqlx/query-98a8b7f4971e0eb4ab8f5aa688aa22e7fdc6b925de211f7784782f051c2dcd8c.json
generated
Normal file
20
swap/.sqlx/query-98a8b7f4971e0eb4ab8f5aa688aa22e7fdc6b925de211f7784782f051c2dcd8c.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT DISTINCT address FROM monero_addresses",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "address",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "98a8b7f4971e0eb4ab8f5aa688aa22e7fdc6b925de211f7784782f051c2dcd8c"
|
||||
}
|
12
swap/.sqlx/query-b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0.json
generated
Normal file
12
swap/.sqlx/query-b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n insert into swap_states (\n swap_id,\n entered_at,\n state\n ) values (?, ?, ?);\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0"
|
||||
}
|
20
swap/.sqlx/query-ce270dd4a4b9615695a79864240c5401e2122077365e5e5a19408c068c7f9454.json
generated
Normal file
20
swap/.sqlx/query-ce270dd4a4b9615695a79864240c5401e2122077365e5e5a19408c068c7f9454.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT address\n FROM monero_addresses\n WHERE swap_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "address",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ce270dd4a4b9615695a79864240c5401e2122077365e5e5a19408c068c7f9454"
|
||||
}
|
20
swap/.sqlx/query-d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2.json
generated
Normal file
20
swap/.sqlx/query-d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT DISTINCT address\n FROM peer_addresses\n WHERE peer_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "address",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2"
|
||||
}
|
20
swap/.sqlx/query-e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646.json
generated
Normal file
20
swap/.sqlx/query-e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT state\n FROM swap_states\n WHERE swap_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "state",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646"
|
||||
}
|
12
swap/.sqlx/query-e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6.json
generated
Normal file
12
swap/.sqlx/query-e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6.json
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO buffered_transfer_proofs (\n swap_id,\n proof\n ) VALUES (?, ?);\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6"
|
||||
}
|
20
swap/.sqlx/query-e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae.json
generated
Normal file
20
swap/.sqlx/query-e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae.json
generated
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT proof\n FROM buffered_transfer_proofs\n WHERE swap_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "proof",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae"
|
||||
}
|
|
@ -13,6 +13,7 @@ tauri = [ "dep:tauri" ]
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
arti-client = { version = "0.24.0", features = [ "static-sqlite", "tokio", "rustls" ], default-features = false }
|
||||
async-compression = { version = "0.3", features = [ "bzip2", "tokio" ] }
|
||||
async-trait = "0.1"
|
||||
asynchronous-codec = "0.7.0"
|
||||
|
@ -29,7 +30,6 @@ conquer-once = "0.4"
|
|||
curve25519-dalek = { package = "curve25519-dalek-ng", version = "4" }
|
||||
data-encoding = "2.6"
|
||||
dialoguer = "0.11"
|
||||
digest = "0.10.7"
|
||||
directories-next = "2"
|
||||
ecdsa_fun = { version = "0.10", default-features = false, features = [
|
||||
"libsecp_compat",
|
||||
|
@ -37,14 +37,12 @@ ecdsa_fun = { version = "0.10", default-features = false, features = [
|
|||
"adaptor",
|
||||
] }
|
||||
ed25519-dalek = "1"
|
||||
erased-serde = "0.4.5"
|
||||
futures = { version = "0.3", default-features = false }
|
||||
hex = "0.4"
|
||||
hyper = "0.14.20"
|
||||
itertools = "0.13"
|
||||
jsonrpsee = { version = "0.16.2", features = [ "server" ] }
|
||||
jsonrpsee-core = "0.16.2"
|
||||
libp2p = { version = "0.53.2", features = [ "tcp", "yamux", "dns", "noise", "request-response", "ping", "rendezvous", "identify", "macros", "cbor", "json", "tokio", "serde", "rsa" ] }
|
||||
libp2p-community-tor = { git = "https://github.com/UnstoppableSwap/libp2p-tor", branch = "main" }
|
||||
monero = { version = "0.12", features = [ "serde_support" ] }
|
||||
monero-rpc = { path = "../monero-rpc" }
|
||||
once_cell = "1.19"
|
||||
|
@ -73,10 +71,9 @@ sigma_fun = { version = "0.7", default-features = false, features = [
|
|||
"secp256k1",
|
||||
"alloc",
|
||||
] }
|
||||
sqlx = { version = "0.6.3", features = [
|
||||
sqlx = { version = "0.8", features = [
|
||||
"sqlite",
|
||||
"runtime-tokio-rustls",
|
||||
"offline",
|
||||
] }
|
||||
structopt = "0.3"
|
||||
strum = { version = "0.26", features = [ "derive" ] }
|
||||
|
@ -95,10 +92,10 @@ tokio = { version = "1", features = [
|
|||
"net",
|
||||
"parking_lot",
|
||||
] }
|
||||
tokio-socks = "0.5"
|
||||
tokio-tungstenite = { version = "0.15", features = [ "rustls-tls" ] }
|
||||
tokio-util = { version = "0.7", features = [ "io", "codec" ] }
|
||||
toml = "0.8"
|
||||
tor-rtcompat = "0.24.0"
|
||||
torut = { version = "0.2", default-features = false, features = [
|
||||
"v3",
|
||||
"control",
|
||||
|
@ -107,7 +104,6 @@ tower = { version = "0.4.13", features = [ "full" ] }
|
|||
tower-http = { version = "0.3.4", features = [ "full" ] }
|
||||
tracing = { version = "0.1", features = [ "attributes" ] }
|
||||
tracing-appender = "0.2"
|
||||
tracing-futures = { version = "0.2", features = [ "std-future", "futures-03" ] }
|
||||
tracing-subscriber = { version = "0.3", default-features = false, features = [
|
||||
"fmt",
|
||||
"ansi",
|
||||
|
@ -131,13 +127,10 @@ zip = "0.5"
|
|||
[dev-dependencies]
|
||||
bitcoin-harness = { git = "https://github.com/delta1/bitcoin-harness-rs.git", rev = "80cc8d05db2610d8531011be505b7bee2b5cdf9f" }
|
||||
get-port = "3"
|
||||
hyper = "1.3"
|
||||
jsonrpsee = { version = "0.16.2", features = [ "ws-client" ] }
|
||||
mockito = "1.4"
|
||||
monero-harness = { path = "../monero-harness" }
|
||||
port_check = "0.2"
|
||||
proptest = "1"
|
||||
sequential-test = "0.2.4"
|
||||
serde_cbor = "0.11"
|
||||
serial_test = "3.1"
|
||||
tempfile = "3"
|
||||
|
|
|
@ -4,6 +4,7 @@ pub mod cancel_and_refund;
|
|||
pub mod command;
|
||||
mod event_loop;
|
||||
mod list_sellers;
|
||||
mod tor;
|
||||
pub mod transport;
|
||||
pub mod watcher;
|
||||
|
||||
|
@ -45,7 +46,7 @@ mod tests {
|
|||
rendezvous_peer_id,
|
||||
rendezvous_address,
|
||||
namespace,
|
||||
0,
|
||||
None,
|
||||
identity::Keypair::generate_ed25519(),
|
||||
);
|
||||
let sellers = tokio::time::timeout(Duration::from_secs(15), list_sellers)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub mod request;
|
||||
pub mod tauri_bindings;
|
||||
|
||||
use crate::cli::command::{Bitcoin, Monero, Tor};
|
||||
use crate::cli::command::{Bitcoin, Monero};
|
||||
use crate::common::tracing_util::Format;
|
||||
use crate::database::{open_db, AccessMode};
|
||||
use crate::env::{Config as EnvConfig, GetConfig, Mainnet, Testnet};
|
||||
|
@ -12,6 +12,7 @@ use crate::seed::Seed;
|
|||
use crate::{bitcoin, common, monero};
|
||||
use anyhow::anyhow;
|
||||
use anyhow::{bail, Context as AnyContext, Error, Result};
|
||||
use arti_client::TorClient;
|
||||
use futures::future::try_join_all;
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
|
@ -22,18 +23,19 @@ use tauri_bindings::{
|
|||
};
|
||||
use tokio::sync::{broadcast, broadcast::Sender, Mutex as TokioMutex, RwLock};
|
||||
use tokio::task::JoinHandle;
|
||||
use tor_rtcompat::tokio::TokioRustlsRuntime;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing::Level;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::tor::init_tor_client;
|
||||
use super::watcher::Watcher;
|
||||
|
||||
static START: Once = Once::new();
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Config {
|
||||
tor_socks5_port: u16,
|
||||
namespace: XmrBtcNamespace,
|
||||
pub env_config: EnvConfig,
|
||||
seed: Option<Seed>,
|
||||
|
@ -188,6 +190,7 @@ pub struct Context {
|
|||
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
|
||||
monero_wallet: Option<Arc<monero::Wallet>>,
|
||||
monero_rpc_process: Option<Arc<SyncMutex<monero::WalletRpcProcess>>>,
|
||||
tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
|
||||
}
|
||||
|
||||
/// A conveniant builder struct for [`Context`].
|
||||
|
@ -196,11 +199,11 @@ pub struct Context {
|
|||
pub struct ContextBuilder {
|
||||
monero: Option<Monero>,
|
||||
bitcoin: Option<Bitcoin>,
|
||||
tor: Option<Tor>,
|
||||
data: Option<PathBuf>,
|
||||
is_testnet: bool,
|
||||
debug: bool,
|
||||
json: bool,
|
||||
tor: bool,
|
||||
tauri_handle: Option<TauriHandle>,
|
||||
}
|
||||
|
||||
|
@ -219,11 +222,11 @@ impl ContextBuilder {
|
|||
ContextBuilder {
|
||||
monero: None,
|
||||
bitcoin: None,
|
||||
tor: None,
|
||||
data: None,
|
||||
is_testnet: false,
|
||||
debug: false,
|
||||
json: false,
|
||||
tor: false,
|
||||
tauri_handle: None,
|
||||
}
|
||||
}
|
||||
|
@ -247,12 +250,6 @@ impl ContextBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Configures the Context to use Tor with the given configuration.
|
||||
pub fn with_tor(mut self, tor: impl Into<Option<Tor>>) -> Self {
|
||||
self.tor = tor.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Attach a handle to Tauri to the Context for emitting events etc.
|
||||
pub fn with_tauri(mut self, tauri: impl Into<Option<TauriHandle>>) -> Self {
|
||||
self.tauri_handle = tauri.into();
|
||||
|
@ -277,6 +274,12 @@ impl ContextBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Whether to initialize a Tor client (default false)
|
||||
pub fn with_tor(mut self, tor: bool) -> Self {
|
||||
self.tor = tor;
|
||||
self
|
||||
}
|
||||
|
||||
/// Takes the builder, initializes the context by initializing the wallets and other components and returns the Context.
|
||||
pub async fn build(self) -> Result<Context> {
|
||||
let data_dir = data::data_dir_from(self.data, self.is_testnet)?;
|
||||
|
@ -343,6 +346,7 @@ impl ContextBuilder {
|
|||
self.tauri_handle.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
(Some(Arc::new(wlt)), Some(Arc::new(SyncMutex::new(prc))))
|
||||
} else {
|
||||
(None, None)
|
||||
|
@ -356,8 +360,6 @@ impl ContextBuilder {
|
|||
TauriContextInitializationProgress::OpeningDatabase,
|
||||
));
|
||||
|
||||
let tor_socks5_port = self.tor.map_or(9050, |tor| tor.tor_socks5_port);
|
||||
|
||||
// If we are connected to the Bitcoin blockchain and if there is a handle to Tauri present,
|
||||
// we start a background task to watch for timelock changes.
|
||||
if let Some(wallet) = bitcoin_wallet.clone() {
|
||||
|
@ -372,13 +374,28 @@ impl ContextBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
self.tauri_handle
|
||||
.emit_context_init_progress_event(TauriContextStatusEvent::Initializing(
|
||||
TauriContextInitializationProgress::EstablishingTorCircuits,
|
||||
));
|
||||
|
||||
let tor = if self.tor {
|
||||
init_tor_client(&data_dir)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
tracing::error!(%err, "Failed to establish Tor client");
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let context = Context {
|
||||
db,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
monero_rpc_process,
|
||||
config: Config {
|
||||
tor_socks5_port,
|
||||
namespace: XmrBtcNamespace::from_is_testnet(self.is_testnet),
|
||||
env_config,
|
||||
seed: Some(seed),
|
||||
|
@ -390,6 +407,7 @@ impl ContextBuilder {
|
|||
swap_lock,
|
||||
tasks: Arc::new(PendingTaskList::default()),
|
||||
tauri_handle: self.tauri_handle,
|
||||
tor_client: tor,
|
||||
};
|
||||
|
||||
Ok(context)
|
||||
|
@ -423,6 +441,7 @@ impl Context {
|
|||
swap_lock: Arc::new(SwapLock::new()),
|
||||
tasks: Arc::new(PendingTaskList::default()),
|
||||
tauri_handle: None,
|
||||
tor_client: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,7 +558,6 @@ impl Config {
|
|||
let data_dir = data::data_dir_from(None, false).expect("Could not find data directory");
|
||||
|
||||
Self {
|
||||
tor_socks5_port: 9050,
|
||||
namespace: XmrBtcNamespace::from_is_testnet(false),
|
||||
env_config,
|
||||
seed: Some(seed),
|
||||
|
@ -576,7 +594,6 @@ pub mod api_test {
|
|||
|
||||
let env_config = env_config_from(is_testnet);
|
||||
Self {
|
||||
tor_socks5_port: 9050,
|
||||
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
||||
env_config,
|
||||
seed: Some(seed),
|
||||
|
|
|
@ -625,7 +625,7 @@ pub async fn buy_xmr(
|
|||
|
||||
let mut swarm = swarm::cli(
|
||||
seed.derive_libp2p_identity(),
|
||||
context.config.tor_socks5_port,
|
||||
context.tor_client.clone(),
|
||||
behaviour,
|
||||
)
|
||||
.await?;
|
||||
|
@ -813,7 +813,7 @@ pub async fn resume_swap(
|
|||
),
|
||||
(seed.clone(), context.config.namespace),
|
||||
);
|
||||
let mut swarm = swarm::cli(seed.clone(), context.config.tor_socks5_port, behaviour).await?;
|
||||
let mut swarm = swarm::cli(seed.clone(), context.tor_client.clone(), behaviour).await?;
|
||||
let our_peer_id = swarm.local_peer_id();
|
||||
|
||||
tracing::debug!(peer_id = %our_peer_id, "Network layer initialized");
|
||||
|
@ -1083,7 +1083,7 @@ pub async fn list_sellers(
|
|||
rendezvous_node_peer_id,
|
||||
rendezvous_point,
|
||||
context.config.namespace,
|
||||
context.config.tor_socks5_port,
|
||||
context.tor_client.clone(),
|
||||
identity,
|
||||
)
|
||||
.await?;
|
||||
|
@ -1224,17 +1224,9 @@ where
|
|||
}
|
||||
|
||||
loop {
|
||||
println!("max_giveable: {}", max_giveable);
|
||||
println!("bid_quote.min_quantity: {}", bid_quote.min_quantity);
|
||||
let min_outstanding = bid_quote.min_quantity - max_giveable;
|
||||
println!("min_outstanding: {}", min_outstanding);
|
||||
let min_bitcoin_lock_tx_fee = estimate_fee(min_outstanding).await?;
|
||||
println!("min_bitcoin_lock_tx_fee: {}", min_bitcoin_lock_tx_fee);
|
||||
let min_deposit_until_swap_will_start = min_outstanding + min_bitcoin_lock_tx_fee;
|
||||
println!(
|
||||
"min_deposit_until_swap_will_start: {}",
|
||||
min_deposit_until_swap_will_start
|
||||
);
|
||||
let max_deposit_until_maximum_amount_is_reached =
|
||||
maximum_amount - max_giveable + min_bitcoin_lock_tx_fee;
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@ pub enum TauriContextInitializationProgress {
|
|||
},
|
||||
OpeningMoneroWallet,
|
||||
OpeningDatabase,
|
||||
EstablishingTorCircuits,
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
|
|
|
@ -33,8 +33,6 @@ pub const DEFAULT_ELECTRUM_RPC_URL_TESTNET: &str = "tcp://electrum.blockstream.i
|
|||
const DEFAULT_BITCOIN_CONFIRMATION_TARGET: u16 = 1;
|
||||
pub const DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET: u16 = 1;
|
||||
|
||||
const DEFAULT_TOR_SOCKS5_PORT: &str = "9050";
|
||||
|
||||
/// Represents the result of parsing the command-line parameters.
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -85,9 +83,9 @@ where
|
|||
|
||||
let context = Arc::new(
|
||||
ContextBuilder::new(is_testnet)
|
||||
.with_tor(tor.enable_tor)
|
||||
.with_bitcoin(bitcoin)
|
||||
.with_monero(monero)
|
||||
.with_tor(tor)
|
||||
.with_data_dir(data)
|
||||
.with_debug(debug)
|
||||
.with_json(json)
|
||||
|
@ -184,9 +182,9 @@ where
|
|||
} => {
|
||||
let context = Arc::new(
|
||||
ContextBuilder::new(is_testnet)
|
||||
.with_tor(tor.enable_tor)
|
||||
.with_bitcoin(bitcoin)
|
||||
.with_monero(monero)
|
||||
.with_tor(tor)
|
||||
.with_data_dir(data)
|
||||
.with_debug(debug)
|
||||
.with_json(json)
|
||||
|
@ -231,9 +229,9 @@ where
|
|||
} => {
|
||||
let context = Arc::new(
|
||||
ContextBuilder::new(is_testnet)
|
||||
.with_tor(tor.enable_tor)
|
||||
.with_bitcoin(bitcoin)
|
||||
.with_monero(monero)
|
||||
.with_tor(tor)
|
||||
.with_data_dir(data)
|
||||
.with_debug(debug)
|
||||
.with_json(json)
|
||||
|
@ -248,12 +246,10 @@ where
|
|||
CliCommand::CancelAndRefund {
|
||||
swap_id: SwapId { swap_id },
|
||||
bitcoin,
|
||||
tor,
|
||||
} => {
|
||||
let context = Arc::new(
|
||||
ContextBuilder::new(is_testnet)
|
||||
.with_bitcoin(bitcoin)
|
||||
.with_tor(tor)
|
||||
.with_data_dir(data)
|
||||
.with_debug(debug)
|
||||
.with_json(json)
|
||||
|
@ -273,7 +269,7 @@ where
|
|||
} => {
|
||||
let context = Arc::new(
|
||||
ContextBuilder::new(is_testnet)
|
||||
.with_tor(tor)
|
||||
.with_tor(tor.enable_tor)
|
||||
.with_data_dir(data)
|
||||
.with_debug(debug)
|
||||
.with_json(json)
|
||||
|
@ -475,9 +471,6 @@ enum CliCommand {
|
|||
|
||||
#[structopt(flatten)]
|
||||
bitcoin: Bitcoin,
|
||||
|
||||
#[structopt(flatten)]
|
||||
tor: Tor,
|
||||
},
|
||||
/// Discover and list sellers (i.e. ASB providers)
|
||||
ListSellers {
|
||||
|
@ -562,11 +555,10 @@ impl Bitcoin {
|
|||
#[derive(structopt::StructOpt, Debug)]
|
||||
pub struct Tor {
|
||||
#[structopt(
|
||||
long = "tor-socks5-port",
|
||||
help = "Your local Tor socks5 proxy port",
|
||||
default_value = DEFAULT_TOR_SOCKS5_PORT
|
||||
long = "enable-tor",
|
||||
help = "Bootstrap a tor client and use it for all libp2p connections"
|
||||
)]
|
||||
pub tor_socks5_port: u16,
|
||||
pub enable_tor: bool,
|
||||
}
|
||||
|
||||
#[derive(structopt::StructOpt, Debug)]
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::network::quote::BidQuote;
|
|||
use crate::network::rendezvous::XmrBtcNamespace;
|
||||
use crate::network::{quote, swarm};
|
||||
use anyhow::{Context, Result};
|
||||
use arti_client::TorClient;
|
||||
use futures::StreamExt;
|
||||
use libp2p::multiaddr::Protocol;
|
||||
use libp2p::request_response;
|
||||
|
@ -12,7 +13,9 @@ use serde::Serialize;
|
|||
use serde_with::{serde_as, DisplayFromStr};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tor_rtcompat::tokio::TokioRustlsRuntime;
|
||||
use typeshare::typeshare;
|
||||
|
||||
/// Returns sorted list of sellers, with [Online](Status::Online) listed first.
|
||||
|
@ -25,7 +28,7 @@ pub async fn list_sellers(
|
|||
rendezvous_node_peer_id: PeerId,
|
||||
rendezvous_node_addr: Multiaddr,
|
||||
namespace: XmrBtcNamespace,
|
||||
tor_socks5_port: u16,
|
||||
maybe_tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
|
||||
identity: identity::Keypair,
|
||||
) -> Result<Vec<Seller>> {
|
||||
let behaviour = Behaviour {
|
||||
|
@ -33,7 +36,7 @@ pub async fn list_sellers(
|
|||
quote: quote::cli(),
|
||||
ping: ping::Behaviour::new(ping::Config::new().with_timeout(Duration::from_secs(60))),
|
||||
};
|
||||
let mut swarm = swarm::cli(identity, tor_socks5_port, behaviour).await?;
|
||||
let mut swarm = swarm::cli(identity, maybe_tor_client, behaviour).await?;
|
||||
|
||||
swarm.add_peer_address(rendezvous_node_peer_id, rendezvous_node_addr.clone());
|
||||
|
||||
|
|
30
swap/src/cli/tor.rs
Normal file
30
swap/src/cli/tor.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use arti_client::{config::TorClientConfigBuilder, Error, TorClient};
|
||||
use tor_rtcompat::tokio::TokioRustlsRuntime;
|
||||
|
||||
pub async fn init_tor_client(data_dir: &Path) -> Result<Arc<TorClient<TokioRustlsRuntime>>, Error> {
|
||||
// We store the Tor state in the data directory
|
||||
let data_dir = data_dir.join("tor");
|
||||
let state_dir = data_dir.join("state");
|
||||
let cache_dir = data_dir.join("cache");
|
||||
|
||||
// The client configuration describes how to connect to the Tor network,
|
||||
// and what directories to use for storing persistent state.
|
||||
let config = TorClientConfigBuilder::from_directories(state_dir, cache_dir)
|
||||
.build()
|
||||
.expect("We initialized the Tor client all required attributes");
|
||||
|
||||
// Start the Arti client, and let it bootstrap a connection to the Tor network.
|
||||
// (This takes a while to gather the necessary directory information.
|
||||
// It uses cached information when possible.)
|
||||
let runtime = TokioRustlsRuntime::current().expect("We are always running with tokio");
|
||||
|
||||
let tor_client = TorClient::with_runtime(runtime)
|
||||
.config(config)
|
||||
.create_bootstrapped()
|
||||
.await?;
|
||||
|
||||
Ok(Arc::new(tor_client))
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
use crate::network::tor_transport::TorDialOnlyTransport;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::network::transport::authenticate_and_multiplex;
|
||||
use anyhow::Result;
|
||||
use arti_client::TorClient;
|
||||
use libp2p::core::muxing::StreamMuxerBox;
|
||||
use libp2p::core::transport::{Boxed, OptionalTransport};
|
||||
use libp2p::dns;
|
||||
use libp2p::tcp;
|
||||
use libp2p::{identity, PeerId, Transport};
|
||||
use libp2p_community_tor::{AddressConversion, TorTransport};
|
||||
use tor_rtcompat::tokio::TokioRustlsRuntime;
|
||||
|
||||
/// Creates the libp2p transport for the swap CLI.
|
||||
///
|
||||
|
@ -17,13 +21,16 @@ use libp2p::{identity, PeerId, Transport};
|
|||
/// TCP transport.
|
||||
pub fn new(
|
||||
identity: &identity::Keypair,
|
||||
maybe_tor_socks5_port: Option<u16>,
|
||||
maybe_tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
|
||||
) -> Result<Boxed<(PeerId, StreamMuxerBox)>> {
|
||||
let tcp = tcp::tokio::Transport::new(tcp::Config::new().nodelay(true));
|
||||
let tcp_with_dns = dns::tokio::Transport::system(tcp)?;
|
||||
|
||||
let maybe_tor_transport = match maybe_tor_socks5_port {
|
||||
Some(port) => OptionalTransport::some(TorDialOnlyTransport::new(port)),
|
||||
let maybe_tor_transport: OptionalTransport<TorTransport> = match maybe_tor_client {
|
||||
Some(client) => OptionalTransport::some(libp2p_community_tor::TorTransport::from_client(
|
||||
client,
|
||||
AddressConversion::IpAndDns,
|
||||
)),
|
||||
None => OptionalTransport::none(),
|
||||
};
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ pub fn init(
|
|||
.with_writer(TauriWriter::new(tauri_handle))
|
||||
.with_ansi(false)
|
||||
.with_timer(UtcTime::rfc_3339())
|
||||
.with_target(false)
|
||||
.with_target(true)
|
||||
.json()
|
||||
.with_filter(env_filter(level_filter)?);
|
||||
|
||||
|
@ -101,6 +101,12 @@ fn env_filter(level_filter: LevelFilter) -> Result<EnvFilter> {
|
|||
Ok(EnvFilter::from_default_env()
|
||||
.add_directive(Directive::from_str(&format!("asb={}", &level_filter))?)
|
||||
.add_directive(Directive::from_str(&format!("swap={}", &level_filter))?)
|
||||
.add_directive(Directive::from_str(&format!("arti={}", &level_filter))?)
|
||||
.add_directive(Directive::from_str(&format!("libp2p={}", &level_filter))?)
|
||||
.add_directive(Directive::from_str(&format!(
|
||||
"libp2p_community_tor={}",
|
||||
&level_filter
|
||||
))?)
|
||||
.add_directive(Directive::from_str(&format!(
|
||||
"unstoppableswap-gui-rs={}",
|
||||
&level_filter
|
||||
|
|
|
@ -29,7 +29,7 @@ impl SqliteDatabase {
|
|||
|
||||
let path_str = format!("sqlite:{}", path.as_ref().display());
|
||||
|
||||
let mut options = SqliteConnectOptions::from_str(&path_str)?.read_only(read_only);
|
||||
let options = SqliteConnectOptions::from_str(&path_str)?.read_only(read_only);
|
||||
let options = options.disable_statement_logging();
|
||||
|
||||
let pool = SqlitePool::connect_with(options.to_owned()).await?;
|
||||
|
@ -59,8 +59,6 @@ impl SqliteDatabase {
|
|||
#[async_trait]
|
||||
impl Database for SqliteDatabase {
|
||||
async fn insert_peer_id(&self, swap_id: Uuid, peer_id: PeerId) -> Result<()> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let swap_id = swap_id.to_string();
|
||||
let peer_id = peer_id.to_string();
|
||||
|
||||
|
@ -74,15 +72,13 @@ impl Database for SqliteDatabase {
|
|||
swap_id,
|
||||
peer_id
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_peer_id(&self, swap_id: Uuid) -> Result<PeerId> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let swap_id = swap_id.to_string();
|
||||
|
||||
let row = sqlx::query!(
|
||||
|
@ -93,7 +89,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_one(&mut conn)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
|
||||
let peer_id = PeerId::from_str(&row.peer_id)?;
|
||||
|
@ -101,8 +97,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn insert_monero_address(&self, swap_id: Uuid, address: Address) -> Result<()> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let swap_id = swap_id.to_string();
|
||||
let address = address.to_string();
|
||||
|
||||
|
@ -116,15 +110,13 @@ impl Database for SqliteDatabase {
|
|||
swap_id,
|
||||
address
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_monero_address(&self, swap_id: Uuid) -> Result<Address> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let swap_id = swap_id.to_string();
|
||||
|
||||
let row = sqlx::query!(
|
||||
|
@ -135,7 +127,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_one(&mut conn)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
|
||||
let address = row.address.parse()?;
|
||||
|
@ -144,10 +136,8 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn get_monero_addresses(&self) -> Result<Vec<monero::Address>> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let rows = sqlx::query!("SELECT DISTINCT address FROM monero_addresses")
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
let addresses = rows
|
||||
|
@ -159,8 +149,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let peer_id = peer_id.to_string();
|
||||
let address = address.to_string();
|
||||
|
||||
|
@ -174,15 +162,13 @@ impl Database for SqliteDatabase {
|
|||
peer_id,
|
||||
address
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_addresses(&self, peer_id: PeerId) -> Result<Vec<Multiaddr>> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
|
||||
let peer_id = peer_id.to_string();
|
||||
|
||||
let rows = sqlx::query!(
|
||||
|
@ -193,7 +179,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
peer_id,
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
let addresses = rows
|
||||
|
@ -208,7 +194,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn get_swap_start_date(&self, swap_id: Uuid) -> Result<String> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let swap_id = swap_id.to_string();
|
||||
|
||||
let row = sqlx::query!(
|
||||
|
@ -219,7 +204,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_one(&mut conn)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
|
||||
row.start_date
|
||||
|
@ -227,7 +212,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let entered_at = OffsetDateTime::now_utc();
|
||||
|
||||
let swap = serde_json::to_string(&Swap::from(state))?;
|
||||
|
@ -246,7 +230,7 @@ impl Database for SqliteDatabase {
|
|||
entered_at,
|
||||
swap
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
// Emit event to Tauri, the frontend will then send another request to get the latest state
|
||||
|
@ -257,7 +241,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn get_state(&self, swap_id: Uuid) -> Result<State> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let swap_id = swap_id.to_string();
|
||||
let row = sqlx::query!(
|
||||
r#"
|
||||
|
@ -270,7 +253,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
let row = row
|
||||
|
@ -282,34 +265,38 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn all(&self) -> Result<Vec<(Uuid, State)>> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let rows = sqlx::query!(
|
||||
r#"
|
||||
SELECT swap_id, state
|
||||
FROM (
|
||||
SELECT max(id), swap_id, state
|
||||
FROM swap_states
|
||||
GROUP BY swap_id
|
||||
)
|
||||
SELECT swap_id, state
|
||||
FROM (
|
||||
SELECT max(id), swap_id, state
|
||||
FROM swap_states
|
||||
GROUP BY swap_id
|
||||
)
|
||||
"#
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
let result = rows
|
||||
.iter()
|
||||
.filter_map(|row| {
|
||||
let swap_id = match Uuid::from_str(&row.swap_id) {
|
||||
let (Some(swap_id), Some(state)) = (&row.swap_id, &row.state) else {
|
||||
tracing::error!("Row didn't contain state or swap_id when it should have");
|
||||
return None;
|
||||
};
|
||||
|
||||
let swap_id = match Uuid::from_str(swap_id) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
tracing::error!(swap_id = %row.swap_id, error = ?e, "Failed to parse UUID");
|
||||
tracing::error!(%swap_id, error = ?e, "Failed to parse UUID");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let state = match serde_json::from_str::<Swap>(&row.state) {
|
||||
let state = match serde_json::from_str::<Swap>(state) {
|
||||
Ok(a) => State::from(a),
|
||||
Err(e) => {
|
||||
tracing::error!(swap_id = %swap_id, error = ?e, "Failed to deserialize state");
|
||||
tracing::error!(%swap_id, error = ?e, "Failed to deserialize state");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
@ -322,7 +309,6 @@ impl Database for SqliteDatabase {
|
|||
}
|
||||
|
||||
async fn get_states(&self, swap_id: Uuid) -> Result<Vec<State>> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let swap_id = swap_id.to_string();
|
||||
|
||||
// TODO: We should use query! instead of query here to allow for at-compile-time validation
|
||||
|
@ -335,7 +321,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
let result = rows
|
||||
|
@ -359,7 +345,6 @@ impl Database for SqliteDatabase {
|
|||
swap_id: Uuid,
|
||||
proof: TransferProof,
|
||||
) -> Result<()> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let swap_id = swap_id.to_string();
|
||||
let proof = serde_json::to_string(&proof)?;
|
||||
|
||||
|
@ -373,14 +358,13 @@ impl Database for SqliteDatabase {
|
|||
swap_id,
|
||||
proof
|
||||
)
|
||||
.execute(&mut conn)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_buffered_transfer_proof(&self, swap_id: Uuid) -> Result<Option<TransferProof>> {
|
||||
let mut conn = self.pool.acquire().await?;
|
||||
let swap_id = swap_id.to_string();
|
||||
|
||||
let row = sqlx::query!(
|
||||
|
@ -391,7 +375,7 @@ impl Database for SqliteDatabase {
|
|||
"#,
|
||||
swap_id
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
if row.is_empty() {
|
||||
|
|
|
@ -27,7 +27,7 @@ use crate::cli::api::tauri_bindings::{
|
|||
|
||||
// See: https://www.moneroworld.com/#nodes, https://monero.fail
|
||||
// We don't need any testnet nodes because we don't support testnet at all
|
||||
const MONERO_DAEMONS: Lazy<[MoneroDaemon; 16]> = Lazy::new(|| {
|
||||
static MONERO_DAEMONS: Lazy<[MoneroDaemon; 16]> = Lazy::new(|| {
|
||||
[
|
||||
MoneroDaemon::new("xmr-node.cakewallet.com", 18081, Network::Mainnet),
|
||||
MoneroDaemon::new("nodex.monerujo.io", 18081, Network::Mainnet),
|
||||
|
@ -169,8 +169,9 @@ async fn choose_monero_daemon(network: Network) -> Result<MoneroDaemon, Error> {
|
|||
.build()?;
|
||||
|
||||
// We only want to check for daemons that match the specified network
|
||||
let daemons = &*MONERO_DAEMONS;
|
||||
let network_matching_daemons = daemons.iter().filter(|daemon| daemon.network == network);
|
||||
let network_matching_daemons = MONERO_DAEMONS
|
||||
.iter()
|
||||
.filter(|daemon| daemon.network == network);
|
||||
|
||||
for daemon in network_matching_daemons {
|
||||
match daemon.is_available(&client).await {
|
||||
|
|
|
@ -7,7 +7,6 @@ pub mod redial;
|
|||
pub mod rendezvous;
|
||||
pub mod swap_setup;
|
||||
pub mod swarm;
|
||||
pub mod tor_transport;
|
||||
pub mod transfer_proof;
|
||||
pub mod transport;
|
||||
|
||||
|
|
|
@ -2,13 +2,16 @@ use crate::asb::{LatestRate, RendezvousNode};
|
|||
use crate::libp2p_ext::MultiAddrExt;
|
||||
use crate::network::rendezvous::XmrBtcNamespace;
|
||||
use crate::seed::Seed;
|
||||
use crate::{asb, bitcoin, cli, env, tor};
|
||||
use crate::{asb, bitcoin, cli, env};
|
||||
use anyhow::Result;
|
||||
use arti_client::TorClient;
|
||||
use libp2p::swarm::NetworkBehaviour;
|
||||
use libp2p::SwarmBuilder;
|
||||
use libp2p::{identity, Multiaddr, Swarm};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tor_rtcompat::tokio::TokioRustlsRuntime;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn asb<LR>(
|
||||
|
@ -61,18 +64,13 @@ where
|
|||
|
||||
pub async fn cli<T>(
|
||||
identity: identity::Keypair,
|
||||
tor_socks5_port: u16,
|
||||
maybe_tor_client: Option<Arc<TorClient<TokioRustlsRuntime>>>,
|
||||
behaviour: T,
|
||||
) -> Result<Swarm<T>>
|
||||
where
|
||||
T: NetworkBehaviour,
|
||||
{
|
||||
let maybe_tor_socks5_port = match tor::Client::new(tor_socks5_port).assert_tor_running().await {
|
||||
Ok(()) => Some(tor_socks5_port),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let transport = cli::transport::new(&identity, maybe_tor_socks5_port)?;
|
||||
let transport = cli::transport::new(&identity, maybe_tor_client)?;
|
||||
|
||||
let swarm = SwarmBuilder::with_existing_identity(identity)
|
||||
.with_tokio()
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
use anyhow::Result;
|
||||
use data_encoding::BASE32;
|
||||
use futures::future::{BoxFuture, Ready};
|
||||
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
||||
use libp2p::core::transport::{ListenerId, TransportError};
|
||||
use libp2p::core::Transport;
|
||||
use libp2p::tcp::tokio::TcpStream;
|
||||
use std::borrow::Cow;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::{fmt, io};
|
||||
use tokio_socks::tcp::Socks5Stream;
|
||||
|
||||
/// A [`Transport`] that can dial onion addresses through a running Tor daemon.
|
||||
#[derive(Clone)]
|
||||
pub struct TorDialOnlyTransport {
|
||||
socks_port: u16,
|
||||
}
|
||||
|
||||
impl TorDialOnlyTransport {
|
||||
pub fn new(socks_port: u16) -> Self {
|
||||
Self { socks_port }
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for TorDialOnlyTransport {
|
||||
type Output = TcpStream;
|
||||
type Error = io::Error;
|
||||
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
|
||||
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
_id: ListenerId,
|
||||
addr: Multiaddr,
|
||||
) -> Result<(), TransportError<Self::Error>> {
|
||||
Err(TransportError::MultiaddrNotSupported(addr))
|
||||
}
|
||||
|
||||
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
let address = TorCompatibleAddress::from_multiaddr(Cow::Borrowed(&addr))?;
|
||||
|
||||
if address.is_certainly_not_reachable_via_tor_daemon() {
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
}
|
||||
|
||||
let socks_port = self.socks_port;
|
||||
|
||||
Ok(Box::pin(async move {
|
||||
tracing::debug!(address = %addr, "Establishing connection through Tor proxy");
|
||||
|
||||
let stream =
|
||||
Socks5Stream::connect((Ipv4Addr::LOCALHOST, socks_port), address.to_string())
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, e))?;
|
||||
|
||||
tracing::debug!("Connection through Tor established");
|
||||
|
||||
Ok(TcpStream(stream.into_inner()))
|
||||
}))
|
||||
}
|
||||
|
||||
fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> {
|
||||
None
|
||||
}
|
||||
|
||||
fn dial_as_listener(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
let address = TorCompatibleAddress::from_multiaddr(Cow::Borrowed(&addr))?;
|
||||
|
||||
if address.is_certainly_not_reachable_via_tor_daemon() {
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
}
|
||||
|
||||
let socks_port = self.socks_port;
|
||||
|
||||
Ok(Box::pin(async move {
|
||||
tracing::debug!(address = %addr, "Establishing connection through Tor proxy");
|
||||
|
||||
let stream =
|
||||
Socks5Stream::connect((Ipv4Addr::LOCALHOST, socks_port), address.to_string())
|
||||
.await
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, e))?;
|
||||
|
||||
tracing::debug!("Connection through Tor established");
|
||||
|
||||
Ok(TcpStream(stream.into_inner()))
|
||||
}))
|
||||
}
|
||||
|
||||
fn remove_listener(&mut self, _id: ListenerId) -> bool {
|
||||
// TODO(Libp2p Migration): What do we need to do here?
|
||||
// I believe nothing because we are not using the transport to listen.
|
||||
false
|
||||
}
|
||||
|
||||
fn poll(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<libp2p::core::transport::TransportEvent<Self::ListenerUpgrade, Self::Error>>
|
||||
{
|
||||
// TODO(Libp2p Migration): What do we need to do here?
|
||||
// See: https://github.com/libp2p/rust-libp2p/pull/2652
|
||||
// I believe we do not need to do anything here because we are not using the transport to listen.
|
||||
// But we need to verify this before merging.
|
||||
|
||||
std::task::Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an address that is _compatible_ with Tor, i.e. can be resolved by
|
||||
/// the Tor daemon.
|
||||
#[derive(Debug)]
|
||||
enum TorCompatibleAddress {
|
||||
Onion3 { host: String, port: u16 },
|
||||
Dns { address: String, port: u16 },
|
||||
Ip4 { address: Ipv4Addr, port: u16 },
|
||||
Ip6 { address: Ipv6Addr, port: u16 },
|
||||
}
|
||||
|
||||
impl TorCompatibleAddress {
|
||||
/// Constructs a new [`TorCompatibleAddress`] from a [`Multiaddr`].
|
||||
fn from_multiaddr(multi: Cow<'_, Multiaddr>) -> Result<Self, TransportError<io::Error>> {
|
||||
match multi.iter().collect::<Vec<_>>().as_slice() {
|
||||
[Protocol::Onion3(onion), ..] => Ok(TorCompatibleAddress::Onion3 {
|
||||
host: BASE32.encode(onion.hash()).to_lowercase(),
|
||||
port: onion.port(),
|
||||
}),
|
||||
[Protocol::Ip4(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Ip4 {
|
||||
address: *address,
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
[Protocol::Dns(address) | Protocol::Dns4(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Dns {
|
||||
address: format!("{}", address),
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
[Protocol::Ip6(address), Protocol::Tcp(port) | Protocol::Udp(port), ..] => {
|
||||
Ok(TorCompatibleAddress::Ip6 {
|
||||
address: *address,
|
||||
port: *port,
|
||||
})
|
||||
}
|
||||
_ => Err(TransportError::MultiaddrNotSupported(multi.into_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the address is reachable via the Tor daemon.
|
||||
///
|
||||
/// The Tor daemon can dial onion addresses, resolve DNS names and dial
|
||||
/// IP4/IP6 addresses reachable via the public Internet.
|
||||
/// We can't guarantee that an address is reachable via the Internet but we
|
||||
/// can say that some addresses are almost certainly not reachable, for
|
||||
/// example, loopback addresses.
|
||||
fn is_certainly_not_reachable_via_tor_daemon(&self) -> bool {
|
||||
match self {
|
||||
TorCompatibleAddress::Onion3 { .. } => false,
|
||||
TorCompatibleAddress::Dns { address, .. } => address == "localhost",
|
||||
TorCompatibleAddress::Ip4 { address, .. } => address.is_loopback(),
|
||||
TorCompatibleAddress::Ip6 { address, .. } => address.is_loopback(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TorCompatibleAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TorCompatibleAddress::Onion3 { host, port } => write!(f, "{}.onion:{}", host, port),
|
||||
TorCompatibleAddress::Dns { address, port } => write!(f, "{}:{}", address, port),
|
||||
TorCompatibleAddress::Ip4 { address, port } => write!(f, "{}:{}", address, port),
|
||||
TorCompatibleAddress::Ip6 { address, port } => write!(f, "{}:{}", address, port),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_tor_address_string() {
|
||||
let address = tor_compatible_address_from_str("/onion3/oarchy4tamydxcitaki6bc2v4leza6v35iezmu2chg2bap63sv6f2did:1024/p2p/12D3KooWPD4uHN74SHotLN7VCH7Fm8zZgaNVymYcpeF1fpD2guc9");
|
||||
|
||||
assert!(!address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(
|
||||
address.to_string(),
|
||||
"oarchy4tamydxcitaki6bc2v4leza6v35iezmu2chg2bap63sv6f2did.onion:1024"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tcp_to_address_string_should_be_some() {
|
||||
let address = tor_compatible_address_from_str("/ip4/127.0.0.1/tcp/7777");
|
||||
|
||||
assert!(address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(address.to_string(), "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ip6_to_address_string_should_be_some() {
|
||||
let address =
|
||||
tor_compatible_address_from_str("/ip6/2001:db8:85a3:8d3:1319:8a2e:370:7348/tcp/7777");
|
||||
|
||||
assert!(!address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(
|
||||
address.to_string(),
|
||||
"2001:db8:85a3:8d3:1319:8a2e:370:7348:7777"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn udp_to_address_string_should_be_some() {
|
||||
let address = tor_compatible_address_from_str("/ip4/127.0.0.1/udp/7777");
|
||||
|
||||
assert!(address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(address.to_string(), "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ws_to_address_string_should_be_some() {
|
||||
let address = tor_compatible_address_from_str("/ip4/127.0.0.1/tcp/7777/ws");
|
||||
|
||||
assert!(address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(address.to_string(), "127.0.0.1:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns4_to_address_string_should_be_some() {
|
||||
let address = tor_compatible_address_from_str("/dns4/randomdomain.com/tcp/7777");
|
||||
|
||||
assert!(!address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(address.to_string(), "randomdomain.com:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns_to_address_string_should_be_some() {
|
||||
let address = tor_compatible_address_from_str("/dns/randomdomain.com/tcp/7777");
|
||||
|
||||
assert!(!address.is_certainly_not_reachable_via_tor_daemon());
|
||||
assert_eq!(address.to_string(), "randomdomain.com:7777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dnsaddr_to_address_string_should_be_error() {
|
||||
let address = "/dnsaddr/randomdomain.com";
|
||||
|
||||
let _ =
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(address.parse().unwrap())).unwrap_err();
|
||||
}
|
||||
|
||||
fn tor_compatible_address_from_str(str: &str) -> TorCompatibleAddress {
|
||||
TorCompatibleAddress::from_multiaddr(Cow::Owned(str.parse().unwrap())).unwrap()
|
||||
}
|
||||
}
|
|
@ -494,8 +494,6 @@ impl BobParams {
|
|||
swap_id: Uuid,
|
||||
db: Arc<dyn Database + Send + Sync>,
|
||||
) -> Result<(cli::EventLoop, cli::EventLoopHandle)> {
|
||||
let tor_socks5_port = get_port()
|
||||
.expect("We don't care about Tor in the tests so we get a free port to disable it.");
|
||||
let identity = self.seed.derive_libp2p_identity();
|
||||
|
||||
let behaviour = cli::Behaviour::new(
|
||||
|
@ -504,7 +502,7 @@ impl BobParams {
|
|||
self.bitcoin_wallet.clone(),
|
||||
(identity.clone(), XmrBtcNamespace::Testnet),
|
||||
);
|
||||
let mut swarm = swarm::cli(identity.clone(), tor_socks5_port, behaviour).await?;
|
||||
let mut swarm = swarm::cli(identity.clone(), None, behaviour).await?;
|
||||
swarm.add_peer_address(self.alice_peer_id, self.alice_address.clone());
|
||||
|
||||
cli::EventLoop::new(swap_id, swarm, self.alice_peer_id, db.clone())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue