{output.address.slice(0,-6)}{output.address.slice(-6)}
diff --git a/client/src/components/util/LoadingAnimation.svelte b/client/src/components/util/LoadingAnimation.svelte index 371a9ad..c7f8ef1 100644 --- a/client/src/components/util/LoadingAnimation.svelte +++ b/client/src/components/util/LoadingAnimation.svelte @@ -6,6 +6,7 @@ box-sizing: border-box; border-radius: 50%; border: solid 2px var(--palette-x); + pointer-events: none; .sizer { width: 100%; diff --git a/client/src/controllers/TxController.js b/client/src/controllers/TxController.js index b5219fe..a95dbf8 100644 --- a/client/src/controllers/TxController.js +++ b/client/src/controllers/TxController.js @@ -106,7 +106,6 @@ export default class TxController { dropTx (txid) { if (this.txs[txid] && this.poolScene.drop(txid)) { - console.log('dropping tx', txid) this.txs[txid].view.update({ display: { position: { @@ -123,8 +122,6 @@ export default class TxController { this.destroyTx(txid) }, 2000) // this.poolScene.layoutAll() - } else { - console.log('dropped unknown tx', txid) } } diff --git a/client/src/utils/encodings.js b/client/src/utils/encodings.js index ccd1b8b..d31d4e0 100644 --- a/client/src/utils/encodings.js +++ b/client/src/utils/encodings.js @@ -48,6 +48,24 @@ export function SPKToAddress (spk) { } else if (spk.startsWith('6a')) { // OP_RETURN return 'OP_RETURN' + } else if (spk.length == 134 && spk.startsWith('41') && spk.endsWith('ac')) { + // uncompressed p2pk + return 'P2PK' + } else if (spk.length == 70 && spk.startsWith('21') && spk.endsWith('ac')) { + // compressed p2pk + return 'P2PK' + } else if (spk.endsWith('51ae') && spk.startsWith('51')) { + // possible p2ms (raw multisig) + return '1-of-1 P2MS' + } else if (spk.endsWith('52ae')) { + // possible p2ms (raw multisig) + if (spk.startsWith(51)) return '1-of-2 P2MS' + if (spk.startsWith(52)) return '2-of-2 P2MS' + } else if (spk.endsWith('53ae')) { + // possible p2ms (raw multisig) + if (spk.startsWith(51)) return '1-of-3 P2MS' + if (spk.startsWith(52)) return '2-of-3 P2MS' + if (spk.startsWith(53)) return '3-of-3 P2MS' } } diff --git a/client/src/utils/search.js b/client/src/utils/search.js index 7dee2bb..7b35778 100644 --- a/client/src/utils/search.js +++ b/client/src/utils/search.js @@ -14,20 +14,22 @@ function matchQuery (query) { const asInt = parseInt(q) // Remember to update the bounds in if (!isNaN(asInt) && asInt >= 0 && `${asInt}` === q) { - return null /*{ + return { query: 'blockheight', + label: 'block height', height: asInt, value: asInt - }*/ + } } // Looks like a block hash? if (/^0{8}[a-f0-9]{56}$/.test(q)) { - return null /* { + return { query: 'blockhash', + label: 'block hash', hash: query, value: query, - }*/ + } } // Looks like a transaction input? @@ -35,6 +37,7 @@ function matchQuery (query) { const parts = q.split(':') return { query: 'input', + label: 'transaction input', txid: parts[1], output: parts[0], value: q @@ -46,6 +49,7 @@ function matchQuery (query) { const parts = q.split(':') return { query: 'output', + label: 'transaction output', txid: parts[0], output: parts[1], value: q @@ -56,6 +60,7 @@ function matchQuery (query) { if (/^[a-f0-9]{64}$/.test(q)) { return { query: 'txid', + label: 'transaction', txid: q, value: q } @@ -72,6 +77,7 @@ function matchQuery (query) { return { query: 'address', + label: 'address', encoding: 'base58', addressType, address: query, @@ -93,6 +99,7 @@ function matchQuery (query) { return { query: 'address', + label: 'address', encoding: 'bech32', addressType, address: query, @@ -108,30 +115,37 @@ export {matchQuery as matchQuery} async function fetchTx (txid) { if (!txid) return - try { - const response = await fetch(`${api.uri}/api/tx/${txid}`, { - method: 'GET' - }) + const response = await fetch(`${api.uri}/api/tx/${txid}`, { + method: 'GET' + }) + if (!response) throw new Error('null response') + if (response.status == 200) { const result = await response.json() const txData = result.tx - txData.block = { height: result.blockheight, hash: result.blockhash, time: result.time * 1000 } + if (result.blockheight != null && result.blockhash != null) { + txData.block = { height: result.blockheight, hash: result.blockhash, time: result.time * 1000 } + } return new BitcoinTx(txData, null, (txData.inputs && txData.inputs[0] && txData.inputs[0].prev_txid === "0000000000000000000000000000000000000000000000000000000000000000")) - } catch (err) { - console.log("failed to fetch tx ", txid) - return null + } else { + throw new Error(response.status) } } export async function searchTx(txid, input, output) { - const searchResult = await fetchTx(txid) - if (searchResult) { - selectedTx.set(searchResult) - detailTx.set(searchResult) - overlay.set('tx') - if (input != null || output != null) highlightInOut.set({txid, input, output}) - return true - } else { - return false + try { + const searchResult = await fetchTx(txid) + if (searchResult) { + selectedTx.set(searchResult) + detailTx.set(searchResult) + overlay.set('tx') + if (input != null || output != null) highlightInOut.set({txid, input, output}) + return null + } else { + return '500' + } + } catch (err) { + console.log('error fetching tx ', err) + return err.message } } diff --git a/server/lib/router.ex b/server/lib/router.ex index 1518d6f..ab93286 100644 --- a/server/lib/router.ex +++ b/server/lib/router.ex @@ -55,8 +55,9 @@ defmodule BitcoinStream.Router do end defp get_tx(txid) do - with {:ok, 200, %{"hex" => hex, "blockhash" => blockhash}} <- RPC.request(:rpc, "getrawtransaction", [txid, true]), - {:ok, 200, %{"height" => height, "time" => time}} <- RPC.request(:rpc, "getblockheader", [blockhash, true]), + with {:ok, 200, verbosetx} <- RPC.request(:rpc, "getrawtransaction", [txid, true]), + %{"hex" => hex, "blockhash" => blockhash} <- Map.merge(%{"blockhash" => nil}, verbosetx), + {:ok, 200, %{"height" => height, "time" => time}} <- (if blockhash != nil do RPC.request(:rpc, "getblockheader", [blockhash, true]) else {:ok, 200, %{"height" => nil, "time" => nil}} end), rawtx <- Base.decode16!(hex, case: :lower), {:ok, txn } <- BitcoinTx.decode(rawtx), inflated_txn <- BitcoinTx.inflate(txn, false),