Add output address highlighting

This commit is contained in:
Mononaut 2022-02-08 13:55:48 -06:00
parent 8f03a9056c
commit 0cce3ca92f
4 changed files with 118 additions and 15 deletions

View File

@ -1,13 +1,17 @@
<script>
import SearchIcon from '../assets/icon/cil-search.svg'
import { matchQuery } from '../utils/search.js'
import { highlight } from '../stores.js'
let query
$: {
$highlight = [{
id: query
}]
if (query) {
const matchedQuery = matchQuery(query.trim())
if (matchedQuery) {
$highlight = [matchedQuery]
} else $highlight = []
} else $highlight = []
}
</script>
@ -28,6 +32,6 @@ $: {
<div class="search tab-content">
<div class="input-wrapper">
<input class="search-input" type="text" bind:value={query} placeholder="Enter a txid...">
<input class="search-input" type="text" bind:value={query} placeholder="Enter an address or txid...">
</div>
</div>

View File

@ -30,16 +30,6 @@ export default class BitcoinTx {
this.time = time
this.highlight = false
// Highlight transactions to the static donation address
// if (config.donationHash && this.outputs) {
// this.outputs.forEach(output => {
// if (output.script_pub_key.includes(config.donationHash)) {
// console.log('donation!', this)
// this.highlight = true
// }
// })
// }
// is a coinbase transaction?
if (this.inputs && this.inputs.length === 1 && this.inputs[0].prev_txid === "0000000000000000000000000000000000000000000000000000000000000000") {
const cbInfo = this.inputs[0].script_sig
@ -101,8 +91,14 @@ export default class BitcoinTx {
applyHighlighting (criteria, color = highlightColor) {
this.highlight = false
criteria.forEach(criterion => {
if (criterion.id === this.id) {
if (criterion.txid === this.id) {
this.highlight = true
} else if (criterion.address && criterion.scriptPubKey) {
this.outputs.forEach(output => {
if (output.script_pub_key === criterion.scriptPubKey) {
this.highlight = true
}
})
}
})
this.view.setHighlight(this.highlight, color)

View File

@ -0,0 +1,27 @@
import { Buffer } from 'buffer/'
window.Buffer = Buffer
import bech32 from 'bech32-buffer'
import { base58_to_binary } from 'base58-js'
// Extract a raw script hash from an address
export function addressToSPK (address) {
if (address.startsWith('bc1')) {
const result = bech32.BitcoinAddress.decode(address)
let prefix
if (result.scriptVersion == 1) prefix = '5120' // taproot (OP_PUSHNUM_1 OP_PUSHBYTES_32)
else if (address.length == 62) prefix = '0020' // p2wsh (OP_0 OP_PUSHBYTES_32)
else prefix = '0014' // p2wpkh (OP_0 OP_PUSHBYTES_20)
return prefix + Buffer.from(result.data).toString('hex')
} else {
const result = base58_to_binary(address)
let prefix, postfix
if (address.charAt(0) === '1') {
prefix = '76a914' // p2pkh (OP_DUP OP_HASH160 OP_PUSHBYTES_20)
postfix = '88ac' // p2pkh (OP_EQUALVERIFY OP_CHECKSIG)
} else {
prefix = 'a914' // p2sh (OP_HASH160 OP_PUSHBYTES_20)
postfix = '87' // p2sh (OP_EQUAL)
}
return prefix + Buffer.from(result).toString('hex').slice(2, -8) + postfix
}
}

View File

@ -0,0 +1,76 @@
import { addressToSPK } from './encodings.js'
// Quick heuristic matching to guess what kind of search a query is for
// ***does not validate that a given address/txid/block is valid***
export function matchQuery (query) {
if (!query || !query.length) return
const q = query.toLowerCase()
// Looks like a block height?
const asInt = parseInt(q)
// Remember to update the bounds in
if (!isNaN(asInt) && asInt >= 0 && `${asInt}` === q) {
return {
query: 'blockheight',
height: asInt
}
}
// Looks like a block hash?
if (/^0{8}[a-f0-9]{56}$/.test(q)) {
return {
query: 'blockhash',
hash: q
}
}
// Looks like a transaction id?
if (/^[a-f0-9]{64}$/.test(q)) {
return {
query: 'txid',
txid: q
}
}
// Looks like an address
if ((q.length >= 26 && q.length <= 34) || q.length === 42 || q.length === 62) {
// Looks like a legacy address
if (/^[13]\w{24,33}$/.test(q)) {
let addressType
if (q[0] === '1') addressType = 'p2pkh'
else if (q[0] === '3') addressType = 'p2sh'
else return null
return {
query: 'address',
encoding: 'base58',
addressType,
address: query,
scriptPubKey: addressToSPK(query)
}
}
// Looks like a bech32 address
if (/^bc1\w{39}(\w{20})?$/.test(q)) {
let addressType
if (q.startsWith('bc1q')) {
if (q.length === 42) addressType = 'p2wpkh'
else if (q.length === 62) addressType = 'p2wsh'
else return null
} else if (q.startsWith('bc1p') && q.length === 62) {
addressType = 'p2tr'
} else return null
return {
query: 'address',
encoding: 'bech32',
addressType,
address: query,
scriptPubKey: addressToSPK(query)
}
}
}
return null
}