bitcoinjs / indexd

An external bitcoind index management service module
ISC License
53 stars 23 forks source link

Mapping addresses to script IDs #16

Closed dcousens closed 6 years ago

dcousens commented 6 years ago

If your tooling uses addresses... you probably want to transcode addresses to their scId (sha256(script)):

    let bitcoin = require('bitcoinjs-lib')

    // ...
    let tasks = {}

    addrs.forEach((address) => {
      let script = bitcoin.address.toOutputScript(address)
      let scId = bitcoin.crypto.sha256(script).toString('hex')

      tasks[address] = (next) => indexd.adapter.transactionsByScriptId(scId, height, next)
    })

Then you can easily map the task results back to each address involved...

List in README? Or not necessary?

dcousens commented 6 years ago

@chiguireitor thoughts?

chiguireitor commented 6 years ago

This would allow to have a "normalized" map be it segwit, multisig or common P2SH addresses, right? dunno if it's necessary to list in readme. I would rather create a reference server that does this and have a rationale in its README

dcousens commented 6 years ago

@chiguireitor as is, we use the normalized form, SHA256(script) for indexing; it is forwards and backwards compatible, and fast, with minimal transcoding... at the adapter level.

Not a problem, but, a documentation consideration in that it may not be clear for how you can use this library.

If you use the above snippet, you can take any address (Bech32, Base58 P2SH, P2PKH, etc), SegWit or otherwise, and easily map it the SHA256(script), but, I wasn't sure if that is "clear" from the code.

Hence, README note required?

chiguireitor commented 6 years ago

Aaah gotcha... it would certainly help for compatibility going forward then to specify this on the README, different implementors could choose a different path and that would create some friction on third party software that expects more or less same behavior.

Makes sense to add on the README.

deweller commented 6 years ago

How many different types of scripts are there to pay to an address?

HASH160 <20 byte script hash> EQUAL
DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG
<pubkey> CHECKSIG

Are there others?

dcousens commented 6 years ago
Address: Base58(0x00 <pubKeyHash> <checksum>)
Address: Base58(0x05 <scriptHash> <checksum>)

And bech32.

<pubkey> CHECKSIG has no address.

deweller commented 6 years ago

I guess what I'm asking is this:

For a given base58 address, how many different script IDs do I need to lookup in order to find all of the possible UTXOs for that address? And what are those script IDs?

I don't think DUP HASH160 <pubkeyhash> EQUALVERIFY CHECKSIG covers every possible UTXO. Or does it?

dcousens commented 6 years ago

@deweller I think the confusion is on your definition of an "address". An address has only 1 script ID, as it has only 1 script associated with it.

You may be confusing "address" and "public key", as a public key can be used in many different script types, and therefore have many different possible scripts, and therefore many script IDs. A public key does not have an "address" per say, but in colloquial terms that phrase has come to mean the equivalent of the P2PKH address.

dcousens commented 6 years ago

If we rephrase your question

For a given public key, how many different script IDs do I need to lookup in order to find all of the possible UTXOs for that pubkey? And what are those script IDs?

The answer would be, assuming you only use the "standard" script templates, in order of likelihood:

type acronym scriptPubKey
pay-to-pubkeyhash P2PKH OP_DUP OP_HASH160 {hash160 pubkey} OP_EQUALVERIFY OP_CHECKSIG
pay-to-witness-pubkeyhash P2WPKH 0 {hash160 pubkey}
pay-to-scripthash(P2PWKH) P2SH(P2WPKH) OP_HASH160 {hash160 script} OP_EQUAL
pay-to-pubkey P2PK {pubKey} OP_CHECKSIG

There are probably others you could think of, but I'd say that is the limit of what you would want to check if you wanted to check the most common types.

KanoczTomas commented 6 years ago

Hello,

I know after some upgrades (probably MAST) other script OPs will be available to use, so e.g. a now non standard script (but completely valid on testnet) with scriptPubkey(locking script): OP_ADD 7 EQ and scriptSig(unlocking script): 5 2 has no address, but can be spent if you reference the input correctly. Would be nice to be able to find it though, but hashing the script only for more transactions would give the same results, right?

So all transactions that involve crypto stuff (pubkey, hashes, etc) will hash to a unique value, but scripts that are more generic, will not. Is this ment as a unique way of finding those transactions, or I can get all that have the same script with that call?

So just wanted to ask your thoughts about this ... those types of scripts are not standard now, so maybe it is off topic to think about it now.

chiguireitor commented 6 years ago

Afaik the hashing of spendable scripts is just a convenience process to flatten the leveldb key space. You can pick whatever means of storing the unspents on your db.

dcousens commented 6 years ago

@KanoczTomas as @chiguireitor said, I use sha256(scriptPubKey), because it is 99% usable. It does mean some information that could be indexable is lost , but, IMHO the ability to reference any scriptPubKey has been generally worthwhile.

Even with MAST, a script will have a static scriptPubKey, that is unchanging AFAIK. What changes is the scriptSig or witness contents, but we don't sha256 that.

The spending transaction can easily be found by looking at the spentIndex chains in 1 go.

KanoczTomas commented 6 years ago

@dcousens thanks for clarifying ...

dcousens commented 6 years ago

The example demonstrates this, and if users struggle, I can refer them here.