mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-28 04:52:29 +02:00
Add output address highlighting
This commit is contained in:
parent
8f03a9056c
commit
0cce3ca92f
@ -1,13 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import SearchIcon from '../assets/icon/cil-search.svg'
|
import SearchIcon from '../assets/icon/cil-search.svg'
|
||||||
|
import { matchQuery } from '../utils/search.js'
|
||||||
import { highlight } from '../stores.js'
|
import { highlight } from '../stores.js'
|
||||||
|
|
||||||
let query
|
let query
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
$highlight = [{
|
if (query) {
|
||||||
id: query
|
const matchedQuery = matchQuery(query.trim())
|
||||||
}]
|
if (matchedQuery) {
|
||||||
|
$highlight = [matchedQuery]
|
||||||
|
} else $highlight = []
|
||||||
|
} else $highlight = []
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -28,6 +32,6 @@ $: {
|
|||||||
|
|
||||||
<div class="search tab-content">
|
<div class="search tab-content">
|
||||||
<div class="input-wrapper">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,16 +30,6 @@ export default class BitcoinTx {
|
|||||||
this.time = time
|
this.time = time
|
||||||
this.highlight = false
|
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?
|
// is a coinbase transaction?
|
||||||
if (this.inputs && this.inputs.length === 1 && this.inputs[0].prev_txid === "0000000000000000000000000000000000000000000000000000000000000000") {
|
if (this.inputs && this.inputs.length === 1 && this.inputs[0].prev_txid === "0000000000000000000000000000000000000000000000000000000000000000") {
|
||||||
const cbInfo = this.inputs[0].script_sig
|
const cbInfo = this.inputs[0].script_sig
|
||||||
@ -101,8 +91,14 @@ export default class BitcoinTx {
|
|||||||
applyHighlighting (criteria, color = highlightColor) {
|
applyHighlighting (criteria, color = highlightColor) {
|
||||||
this.highlight = false
|
this.highlight = false
|
||||||
criteria.forEach(criterion => {
|
criteria.forEach(criterion => {
|
||||||
if (criterion.id === this.id) {
|
if (criterion.txid === this.id) {
|
||||||
this.highlight = true
|
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)
|
this.view.setHighlight(this.highlight, color)
|
||||||
|
27
client/src/utils/encodings.js
Normal file
27
client/src/utils/encodings.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
76
client/src/utils/search.js
Normal file
76
client/src/utils/search.js
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user