Fixing issue with indexing

This commit is contained in:
Chris Troutner
2026-06-03 07:09:51 -07:00
parent fc263534e9
commit 1bac9ff32f
3 changed files with 121 additions and 9 deletions
+23
View File
@@ -81,6 +81,29 @@ All routes are under `/level` with a consistent CRUD pattern generated from `ENT
| `processerror` | `txid` | `errorData` | txid |
| `ptx` | `txid` | `ptxData` | txid |
### Read routes (query use cases)
| Method | Path | Query params |
|--------|------|----------------|
| `GET` | `/profile/recent` | `limit` (default 100, max 100), `offset` (default 0) |
Returns profiles sorted by **block height** (newest first), using each profiles `txid` to look up `blockHeight` in `ptxs`. Tie-breaker: `seen` timestamp descending.
Response shape:
```json
{
"profiles": [
{ "addr": "bitcoincash:q...", "text": "...", "txid": "...", "seen": 123, "blockHeight": 600000 }
],
"pagination": { "limit": 100, "offset": 0, "total": 42, "hasMore": false }
}
```
Implementation: `profile-query` adapter (LevelDB scan) → `list-recent-profiles` use case → `/profile` REST controller.
**Tradeoff:** Full scan of `profiles` on each request; suitable for moderate corpus sizes. A height-indexed store would be needed for very large archives.
### Status (special case)
Matches SLP status semantics:
+50 -8
View File
@@ -111,19 +111,61 @@ export function findMemoOutputs (txDetails) {
return matches
}
/**
* Extract compressed or uncompressed pubkey from a P2PKH unlocking script.
* Mirrors Go wallet.GetP2pkhAddrFromUnlockScript (pubkey push after signature).
*/
export function getPubkeyFromUnlockScript (scriptBuf) {
if (!scriptBuf || !scriptBuf.length) return null
let decoded
try {
decoded = getBchjs().Script.decode(scriptBuf)
} catch (err) {
return null
}
if (!decoded || !decoded.length) return null
for (let i = decoded.length - 1; i >= 0; i--) {
const chunk = decoded[i]
if (Buffer.isBuffer(chunk) && (chunk.length === 33 || chunk.length === 65)) {
return chunk
}
}
return null
}
/**
* Derive cash address from unlocking script hex (P2PKH spend).
*/
export function getAddressFromUnlockScriptHex (scriptHex) {
if (!scriptHex || typeof scriptHex !== 'string') return null
try {
const scriptBuf = Buffer.from(scriptHex, 'hex')
const pubkey = getPubkeyFromUnlockScript(scriptBuf)
if (!pubkey) return null
const hash160 = getBchjs().Crypto.hash160(pubkey)
return getBchjs().Address.hash160ToCash(hash160)
} catch (err) {
return null
}
}
export function getSignerAddress (txDetails) {
if (!txDetails || !txDetails.vin) return null
for (const vin of txDetails.vin) {
if (!vin.scriptSig || !vin.scriptSig.hex) continue
try {
const scriptBuf = Buffer.from(vin.scriptSig.hex, 'hex')
const addr = getBchjs().Script.getAddressFromScriptSig(scriptBuf)
if (addr) return addr
} catch (err) {
continue
}
const scriptHex = vin.scriptSig && vin.scriptSig.hex
if (!scriptHex) continue
const addr = getAddressFromUnlockScriptHex(scriptHex)
if (addr) return addr
}
return null
}
+48 -1
View File
@@ -2,7 +2,9 @@ import { assert } from 'chai'
import {
decodeMemoOpReturn,
parseScriptPushDatas,
isMemoScript
isMemoScript,
getSignerAddress,
getAddressFromUnlockScriptHex
} from '../../../src/lib/memo-parser.js'
import { CODE_POST, CODE_PREFIX } from '../../../src/lib/memo-codes.js'
@@ -38,4 +40,49 @@ describe('#memo-parser', () => {
assert.equal(isMemoScript(POST_OP_RETURN_HEX), true)
})
})
describe('#getAddressFromUnlockScriptHex', () => {
const SCRIPT_SIG_1 =
'483045022100e15e18048b78e744fe8e440eb2687b5d4eb7009140d5e71950d4351c6e3bf2ef022031b0dab7326846a58e16f6a753e0d011514f827d2adacde63912daa3f85636c5412103833927b98fab40d5f857214d802ba42ea21087105b81e9bff57bf2486c9ff171'
const SCRIPT_SIG_2 =
'483045022100aa35ee315859b63f92e7878304364635943b28b2334dfd796a51cb2e0b284fe3022033e852b7c965f36c7d6eecc577b01218d611450c80e75af1fd41e76cfc7af81c4121035c5970c98aa4543271348bb18de4fb04122af87555fc4411c376493cc85594c3'
it('should derive cash address from real memo tx scriptSig', () => {
const addr = getAddressFromUnlockScriptHex(SCRIPT_SIG_1)
assert.isString(addr)
assert.include(addr, 'bitcoincash:')
assert.equal(
addr,
'bitcoincash:qzd7s66p0mh97s2tqkrwacx4dazwataul5m9f9yw68'
)
})
it('should derive cash address from second sample scriptSig', () => {
const addr = getAddressFromUnlockScriptHex(SCRIPT_SIG_2)
assert.equal(
addr,
'bitcoincash:qrnr8q2ndfmzgfehz5txel9jpq3lrwhvt5f270fnd4'
)
})
})
describe('#getSignerAddress', () => {
const SCRIPT_SIG_1 =
'483045022100e15e18048b78e744fe8e440eb2687b5d4eb7009140d5e71950d4351c6e3bf2ef022031b0dab7326846a58e16f6a753e0d011514f827d2adacde63912daa3f85636c5412103833927b98fab40d5f857214d802ba42ea21087105b81e9bff57bf2486c9ff171'
it('should return signer from txDetails with vin scriptSig', () => {
const txDetails = {
vin: [{ scriptSig: { hex: SCRIPT_SIG_1 } }]
}
const addr = getSignerAddress(txDetails)
assert.equal(
addr,
'bitcoincash:qzd7s66p0mh97s2tqkrwacx4dazwataul5m9f9yw68'
)
})
it('should return null when no vin', () => {
assert.equal(getSignerAddress({}), null)
})
})
})