Helper to convert eCash addresses to hash160 since Chronik only interacts via Hash160 equivalents.
Will be used in subsequent examples such as retrieving UTXOs for an address.
Details
- Reviewers
bytesofman - Group Reviewers
Restricted Project
npm test
npm run addressToHash160 <address>
Diff Detail
- Repository
- rABC Bitcoin ABC
- Branch
- addressToHash160
- Lint
Lint Passed - Unit
No Test Coverage - Build Status
Buildable 24250 Build 48110: Build Diff app-dev-examples Build 48109: arc lint + arc unit
Event Timeline
Tail of the build log:
Run `npm audit` for details. > test > mocha --reporter mocha-junit-reporter --reporter-options mochaFile=test_results/examples-junit.xml --reporter-options testsuitesTitle=Examples Unit Tests --reporter-options rootSuiteTitle=Examples Error converting address to hash160 ValidationError: Invalid value: -. at new ValidationError (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:25:17) at validate (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:43:15) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/base32.js:100:9) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/cashaddr.js:85:46) at addressToHash160 (/work/apps/examples/scripts/addressToHash160.js:14:47) at /work/apps/examples/scripts/addressToHash160.js:18:161 at Object.<anonymous> (/work/apps/examples/scripts/addressToHash160.js:18:249) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at Module.require (node:internal/modules/cjs/loader:1098:19) at require (node:internal/modules/cjs/helpers:108:18) at Object.<anonymous> (/work/apps/examples/test/addressToHash160.test.js:5:30) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15) at async formattedImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:9:14) at async Object.exports.requireOrImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:42:28) at async Object.exports.loadFilesAsync (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at async singleRun (/work/apps/examples/node_modules/mocha/lib/cli/run-helpers.js:125:3) at async Object.exports.handler (/work/apps/examples/node_modules/mocha/lib/cli/run.js:370:5) ---------------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ---------------------|---------|----------|---------|---------|------------------- All files | 64.7 | 50 | 100 | 64.7 | addressToHash160.js | 64.7 | 50 | 100 | 64.7 | 20,27-30,44-47 ---------------------|---------|----------|---------|---------|------------------- ##teamcity[blockOpened name='Code Coverage Summary'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBCovered' value='11'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBTotal' value='17'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRCovered' value='1'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMCovered' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLCovered' value='11'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLTotal' value='17'] ##teamcity[blockClosed name='Code Coverage Summary'] mv: cannot stat 'test_results/examples-junit.xml': No such file or directory Build app-dev-examples failed with exit code 1
Tail of the build log:
npm audit fix --force Run `npm audit` for details. > test > mocha --reporter mocha-junit-reporter --reporter-options mochaFile=test_results/examples-junit.xml --reporter-options testsuitesTitle=Examples Unit Tests --reporter-options rootSuiteTitle=Examples ValidationError: Invalid value: -. at new ValidationError (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:25:17) at validate (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:43:15) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/base32.js:100:9) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/cashaddr.js:85:46) at addressToHash160 (/work/apps/examples/scripts/addressToHash160.js:14:47) at /work/apps/examples/scripts/addressToHash160.js:18:160 at Object.<anonymous> (/work/apps/examples/scripts/addressToHash160.js:18:248) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at Module.require (node:internal/modules/cjs/loader:1098:19) at require (node:internal/modules/cjs/helpers:108:18) at Object.<anonymous> (/work/apps/examples/test/addressToHash160.test.js:5:30) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15) at async formattedImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:9:14) at async Object.exports.requireOrImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:42:28) at async Object.exports.loadFilesAsync (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at async singleRun (/work/apps/examples/node_modules/mocha/lib/cli/run-helpers.js:125:3) at async Object.exports.handler (/work/apps/examples/node_modules/mocha/lib/cli/run.js:370:5) ---------------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ---------------------|---------|----------|---------|---------|------------------- All files | 57.14 | 50 | 100 | 57.14 | addressToHash160.js | 57.14 | 50 | 100 | 57.14 | 20,26-29,39-42 ---------------------|---------|----------|---------|---------|------------------- ##teamcity[blockOpened name='Code Coverage Summary'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBCovered' value='8'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBTotal' value='14'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRCovered' value='1'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMCovered' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLCovered' value='8'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLTotal' value='14'] ##teamcity[blockClosed name='Code Coverage Summary'] mv: cannot stat 'test_results/examples-junit.xml': No such file or directory Build app-dev-examples failed with exit code 1
Should follow the available methods of ecashaddrjs. If there is something useful you want to do that is not available in ecashaddrjs, then we should add it there.
For example, the best way to do chronik prep is
const { prefix, type, hash } = ecashaddr.decode(chronikQueryAddress, true); console.log(prefix); // 'ecash' console.log(type); // 'p2pkh' (instead of 'P2PKH', returned without the 'true' flag) console.log(hash); // '95e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d' (instead of Uint8Array [ 149, 241, ..., 29 ], returned without the 'true' flag)
apps/examples/README.md | ||
---|---|---|
9 ↗ | (On Diff #41073) | This should be covered by npm i user should never have to npm i bs58 as this is a dependency of ecashaddrjs |
33 ↗ | (On Diff #41073) | these line breaks aren't related to this diff |
apps/examples/scripts/addressToHash160.js | ||
7 ↗ | (On Diff #41073) | we shouldn't need this |
26 ↗ | (On Diff #41073) | we have a toLegacy function in ecashaddrjs. If we are trying to demo legacy conversion, we should use this lib function |
Tail of the build log:
npm audit fix --force Run `npm audit` for details. > test > mocha --reporter mocha-junit-reporter --reporter-options mochaFile=test_results/examples-junit.xml --reporter-options testsuitesTitle=Examples Unit Tests --reporter-options rootSuiteTitle=Examples ValidationError: Invalid value: -. at new ValidationError (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:25:17) at validate (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:43:15) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/base32.js:100:9) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/cashaddr.js:85:46) at addressToHash160 (/work/apps/examples/scripts/addressToHash160.js:14:47) at /work/apps/examples/scripts/addressToHash160.js:17:158 at Object.<anonymous> (/work/apps/examples/scripts/addressToHash160.js:17:245) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at Module.require (node:internal/modules/cjs/loader:1098:19) at require (node:internal/modules/cjs/helpers:108:18) at Object.<anonymous> (/work/apps/examples/test/addressToHash160.test.js:5:30) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15) at async formattedImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:9:14) at async Object.exports.requireOrImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:42:28) at async Object.exports.loadFilesAsync (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at async singleRun (/work/apps/examples/node_modules/mocha/lib/cli/run-helpers.js:125:3) at async Object.exports.handler (/work/apps/examples/node_modules/mocha/lib/cli/run.js:370:5) ---------------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ---------------------|---------|----------|---------|---------|------------------- All files | 63.63 | 50 | 100 | 63.63 | addressToHash160.js | 63.63 | 50 | 100 | 63.63 | 19,24,34-37 ---------------------|---------|----------|---------|---------|------------------- ##teamcity[blockOpened name='Code Coverage Summary'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBCovered' value='7'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBTotal' value='11'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRCovered' value='1'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMCovered' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLCovered' value='7'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLTotal' value='11'] ##teamcity[blockClosed name='Code Coverage Summary'] mv: cannot stat 'test_results/examples-junit.xml': No such file or directory Build app-dev-examples failed with exit code 1
Looking into why the tests passes locally but phab is complaining about a validation error which is what the unit tests were expecting...
Tail of the build log:
npm audit fix --force Run `npm audit` for details. > test > mocha --reporter mocha-junit-reporter --reporter-options mochaFile=test_results/examples-junit.xml --reporter-options testsuitesTitle=Examples Unit Tests --reporter-options rootSuiteTitle=Examples ValidationError: Invalid value: -. at new ValidationError (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:25:17) at validate (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:43:15) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/base32.js:100:9) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/cashaddr.js:85:46) at addressToHash160 (/work/apps/examples/scripts/addressToHash160.js:14:47) at /work/apps/examples/scripts/addressToHash160.js:17:158 at Object.<anonymous> (/work/apps/examples/scripts/addressToHash160.js:17:245) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at Module.require (node:internal/modules/cjs/loader:1098:19) at require (node:internal/modules/cjs/helpers:108:18) at Object.<anonymous> (/work/apps/examples/test/addressToHash160.test.js:5:30) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15) at async formattedImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:9:14) at async Object.exports.requireOrImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:42:28) at async Object.exports.loadFilesAsync (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at async singleRun (/work/apps/examples/node_modules/mocha/lib/cli/run-helpers.js:125:3) at async Object.exports.handler (/work/apps/examples/node_modules/mocha/lib/cli/run.js:370:5) ---------------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ---------------------|---------|----------|---------|---------|------------------- All files | 63.63 | 50 | 100 | 63.63 | addressToHash160.js | 63.63 | 50 | 100 | 63.63 | 19,24,34-37 ---------------------|---------|----------|---------|---------|------------------- ##teamcity[blockOpened name='Code Coverage Summary'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBCovered' value='7'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBTotal' value='11'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRCovered' value='1'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMCovered' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLCovered' value='7'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLTotal' value='11'] ##teamcity[blockClosed name='Code Coverage Summary'] mv: cannot stat 'test_results/examples-junit.xml': No such file or directory Build app-dev-examples failed with exit code 1
Tail of the build log:
Run `npm audit` for details. > test > mocha --reporter mocha-junit-reporter --reporter-options mochaFile=test_results/examples-junit.xml --reporter-options testsuitesTitle=Examples Unit Tests --reporter-options rootSuiteTitle=Examples Error decoding address: --reporter ValidationError: Invalid value: -. at new ValidationError (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:25:17) at validate (/work/apps/examples/node_modules/ecashaddrjs/src/validation.js:43:15) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/base32.js:100:9) at Object.decode (/work/apps/examples/node_modules/ecashaddrjs/src/cashaddr.js:85:46) at addressToHash160 (/work/apps/examples/scripts/addressToHash160.js:14:74) at /work/apps/examples/scripts/addressToHash160.js:17:160 at Object.<anonymous> (/work/apps/examples/scripts/addressToHash160.js:17:248) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at Module.require (node:internal/modules/cjs/loader:1098:19) at require (node:internal/modules/cjs/helpers:108:18) at Object.<anonymous> (/work/apps/examples/test/addressToHash160.test.js:5:30) at Module._compile (node:internal/modules/cjs/loader:1196:14) at Module.replacementCompile (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:60:13) at Module._extensions..js (node:internal/modules/cjs/loader:1250:10) at Object.<anonymous> (/usr/lib/node_modules/nyc/node_modules/append-transform/index.js:64:4) at Module.load (node:internal/modules/cjs/loader:1074:32) at Function.Module._load (node:internal/modules/cjs/loader:909:12) at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:169:29) at ModuleJob.run (node:internal/modules/esm/module_job:193:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:530:24) at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15) at async formattedImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:9:14) at async Object.exports.requireOrImport (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:42:28) at async Object.exports.loadFilesAsync (/work/apps/examples/node_modules/mocha/lib/nodejs/esm-utils.js:100:20) at async singleRun (/work/apps/examples/node_modules/mocha/lib/cli/run-helpers.js:125:3) at async Object.exports.handler (/work/apps/examples/node_modules/mocha/lib/cli/run.js:370:5) ---------------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ---------------------|---------|----------|---------|---------|------------------- All files | 71.42 | 50 | 100 | 71.42 | addressToHash160.js | 71.42 | 50 | 100 | 71.42 | 19,25,39-42 ---------------------|---------|----------|---------|---------|------------------- ##teamcity[blockOpened name='Code Coverage Summary'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBCovered' value='10'] ##teamcity[buildStatisticValue key='CodeCoverageAbsBTotal' value='14'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRCovered' value='1'] ##teamcity[buildStatisticValue key='CodeCoverageAbsRTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMCovered' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsMTotal' value='2'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLCovered' value='10'] ##teamcity[buildStatisticValue key='CodeCoverageAbsLTotal' value='14'] ##teamcity[blockClosed name='Code Coverage Summary'] mv: cannot stat 'test_results/examples-junit.xml': No such file or directory Build app-dev-examples failed with exit code 1
I have the feeling the issue lies in the mocha call, where the --reporter option is misintepreted and used as an input for some reason.
apps/examples/scripts/addressToHash160.js | ||
---|---|---|
40 | The problem is that this is executed by mocha test, so when using the CI argv looks like: ARGV: [ '/home/fabien/.nvm/versions/node/v16.20.0/bin/node', '/home/fabien/bitcoin-abc/apps/examples/node_modules/.bin/mocha', '--reporter', 'mocha-junit-reporter', '--reporter-options', 'mochaFile=', '--reporter-options', 'testsuitesTitle= Unit Tests', '--reporter-options', 'rootSuiteTitle=' ] For sure, --reporter is not a valid eCash address. |
apps/examples/scripts/addressToHash160.js | ||
---|---|---|
17 | Unclear why we need a script that limits the functionality of cashaddr.decode Just do const {type, hash, prefix} = cashaddr.decode(address,true) and cover the full featureset of this method Wouldn't make sense to add another script to get just type or prefix The main reason Cashtab has a toHash160 function is because it was implemented there before we added the ability for the cashaddr library to simply return hash as a string instead of a uint8array -- we should also be deprecating this function in cashtab and replacing it with the lib function |
Not worth an individual diff + unit tests on a library, will use directly in txhistory/utxo retrieval examples