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

Broadcast txs over block explorer via tor #1183

Merged
merged 5 commits into from
May 25, 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
55 changes: 55 additions & 0 deletions src/cryptoadvance/specter/server_endpoints/wallets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,61 @@ def broadcast(wallet_alias):
return jsonify(success=False, error="broadcast tx request must use POST")


@wallets_endpoint.route(
"/wallet/<wallet_alias>/broadcast_blockexplorer_tor/", methods=["GET", "POST"]
)
@login_required
def broadcast_blockexplorer_tor(wallet_alias):
wallet = app.specter.wallet_manager.get_by_alias(wallet_alias)
if request.method == "POST":
tx = request.form.get("tx")
explorer = request.form.get("explorer")
res = wallet.rpc.testmempoolaccept([tx])[0]
if res["allowed"]:
try:
if app.specter.chain == "main":
url_network = ""
elif app.specter.chain == "liquidv1":
url_network = "liquid/"
elif app.specter.chain == "test" or app.specter.chain == "testnet":
url_network = "testnet/"
elif app.specter.chain == "signet":
url_network = "signet/"
else:
return jsonify(
success=False,
error=f"Failed to broadcast transaction. Network not supported.",
)
if explorer == "mempool":
explorer = "MEMPOOL_SPACE_ONION"
elif explorer == "blockstream":
explorer = "BLOCKSTREAM_INFO_ONION"
else:
return jsonify(
success=False,
error=f"Failed to broadcast transaction. Block explorer not supported.",
)
requests_session = app.specter.requests_session(force_tor=True)
requests_session.post(
f"{app.config['EXPLORERS_LIST'][explorer]['url']}{url_network}api/tx",
data=tx,
)
wallet.delete_pending_psbt(get_txid(tx))
return jsonify(success=True)
except Exception as e:
return jsonify(
success=False,
error=f"Failed to broadcast transaction with error: {e}",
)
else:
return jsonify(
success=False,
error="Failed to broadcast transaction: transaction is invalid\n%s"
% res["reject-reason"],
)
return jsonify(success=False, error="broadcast tx request must use POST")


@wallets_endpoint.route("/wallet/<wallet_alias>/decoderawtx/", methods=["GET", "POST"])
@login_required
@app.csrf.exempt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
<h1>Transaction is Ready to Broadcast</h1>
<div class="flex-center flex-column">
<button id="broadcast_local_btn" class="btn flex-item" style="width: 190px;">Send transaction</button>
{% if specter.chain != "regtest" %}
<button type="button" id="broadcast_blockstream_btn" class="btn flex-item" style="width: 190px;">Send via blockstream.info</button>
{% endif %}
<button type="button" id="broadcast_block_explorer_btn" class="btn flex-item {% if specter.chain != 'regtest' %}hidden{% endif %}" style="width: 190px;">Send via block explorer</button>
<button type="button" id="broadcast_blockstream_btn" class="btn flex-item hidden" style="width: 190px;">Send via blockstream.info</button>
<button type="button" id="broadcast_mempool_btn" class="btn flex-item hidden" style="width: 190px;">Send via mempool.space</button>
<button type="button" id="broadcast_blockstream_tor_btn" class="btn flex-item hidden" style="width: 190px;">Send via blockstream.info<br>(over Tor hidden service)</button>
<button type="button" id="broadcast_mempool_tor_btn" class="btn flex-item hidden" style="width: 190px;">Send via mempool.space<br>(over Tor hidden service)</button>
<button type="button" id="broadcast_options_btn" class="btn flex-item hidden" style="width: 190px;">Back to options</button>
<button id="save_psbt_btn" class="btn flex-item" style="width: 190px;">Save as pending</button>
<button id="copy_final_tx_btn" class="btn flex-item" style="width: 190px;">Copy raw transaction</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,32 @@
showPageOverlay("tx_broadcast");
});

document.getElementById("broadcast_block_explorer_btn").addEventListener("click", async function(e) {
e.preventDefault();
document.getElementById("broadcast_local_btn").classList.add("hidden");
document.getElementById("broadcast_block_explorer_btn").classList.add("hidden");
document.getElementById("save_psbt_btn").classList.add("hidden");
document.getElementById("copy_final_tx_btn").classList.add("hidden");
document.getElementById("broadcast_blockstream_btn").classList.remove("hidden");
document.getElementById("broadcast_mempool_btn").classList.remove("hidden");
document.getElementById("broadcast_blockstream_tor_btn").classList.remove("hidden");
document.getElementById("broadcast_mempool_tor_btn").classList.remove("hidden");
document.getElementById("broadcast_options_btn").classList.remove("hidden");
});

document.getElementById("broadcast_options_btn").addEventListener("click", async function(e) {
e.preventDefault();
document.getElementById("broadcast_local_btn").classList.remove("hidden");
document.getElementById("broadcast_block_explorer_btn").classList.remove("hidden");
document.getElementById("save_psbt_btn").classList.remove("hidden");
document.getElementById("copy_final_tx_btn").classList.remove("hidden");
document.getElementById("broadcast_blockstream_btn").classList.add("hidden");
document.getElementById("broadcast_mempool_btn").classList.add("hidden");
document.getElementById("broadcast_blockstream_tor_btn").classList.add("hidden");
document.getElementById("broadcast_mempool_tor_btn").classList.add("hidden");
document.getElementById("broadcast_options_btn").classList.add("hidden");
});

document.getElementById("broadcast_local_btn").addEventListener("click", async function(e) {
e.preventDefault();
broadcastLocal(raw);
Expand All @@ -271,7 +297,22 @@
if ("{{ specter.chain }}" != "regtest") {
document.getElementById("broadcast_blockstream_btn").addEventListener("click", async function(e) {
e.preventDefault();
broadcastBlockstream(raw);
broadcastBlockExplorer(raw, 'blockstream');
});

document.getElementById("broadcast_mempool_btn").addEventListener("click", async function(e) {
e.preventDefault();
broadcastBlockExplorer(raw, 'mempool');
});

document.getElementById("broadcast_blockstream_tor_btn").addEventListener("click", async function(e) {
e.preventDefault();
broadcastBlockExplorerTor(raw, 'blockstream');
});

document.getElementById("broadcast_mempool_tor_btn").addEventListener("click", async function(e) {
e.preventDefault();
broadcastBlockExplorerTor(raw, 'mempool');
});
}

Expand Down Expand Up @@ -391,22 +432,59 @@
}
}

function broadcastBlockstream(tx) {
showNotification("Sending transaction via blockstream...");
async function broadcastBlockExplorerTor(tx, explorer) {
showNotification("Sending transaction...", 0);
let url="{{ url_for('wallets_endpoint.broadcast_blockexplorer_tor', wallet_alias=wallet.alias) }}";

var formData = new FormData();
formData.append("csrf_token", "{{ csrf_token() }}");
formData.append("tx", tx);
formData.append("explorer", explorer);

try {
const response = await fetch(
url,
{
method: 'POST',
body: formData
}
);

const jsonResponse = await response.json();

if (jsonResponse.success) {
hidePageOverlay();
window.location.replace("{{ url_for('wallets_endpoint.history', wallet_alias=wallet.alias) }}");
} else {
showError("Server failed to broadcast transactions!\n" + jsonResponse.error);
}
} catch(e) {
showError("Server failed to broadcast transactions!\n" + e);
}
}

function broadcastBlockExplorer(tx, explorer) {
showNotification("Sending transaction via " + explorer + "...", 0);
// TODO: Use fetch instead of XMLHttpRequest
let url;
if (explorer == "blockstream") {
url = "https://blockstream.info/"
} else if (explorer == "mempool") {
url = "https://mempool.space/"
}
if ("{{ specter.chain }}" == "main") {
url="https://blockstream.info/api/tx";
url += "api/tx";
} else if("{{specter.chain}}" == "liquidv1"){
url="https://blockstream.info/liquid/api/tx";
url += "liquid/api/tx";
} else if("{{specter.chain}}" == "signet"){
url += "signet/api/tx";
} else {
url="https://blockstream.info/testnet/api/tx";
url += "testnet/api/tx";
}

var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState === 4 && xmlHttp.status === 200) {
let o = JSON.parse(this.responseText);
var deletePSBTBtn = document.getElementById("deletepsbt_btn");
deletePSBTBtn.click();
showNotification("Transaction was sent successfully!");
Expand Down