Author

Topic: Understanding Basic Transaction Structure (Read 846 times)

hero member
Activity: 742
Merit: 500
Ok, that makes a bit more sense.  Thank you for clearing that up for me.  Do you have a tip address?
donator
Activity: 1218
Merit: 1079
Gerald Davis
Quote
Exactly my question.  I feel like I'm missing something fundamental here; how would a client calculate a 'balance' to be displayed in this kind of situation?
It wouldn't unless the wallet had the required number of private keys.

Quote
When I say "bitcoind getbalance", it sums up all the unspent outputs I have available to me.  I'd like to programatically do the same for an arbitrary list of public keys.
When you decode the output PayToPubKeyHash are easy it is a 1:1 relationship between unspent outputs and the pubkey.

To properly show the "balance" for native multisig you would need to decode the script and follow the "instructions".  If the script requires 2 of 5 signatures from a list of PubKeys (P1 to P5) and you have P1 and P4 in your wallet then you can "spend" that output so it would be logical to say that balance is available.  If you only have 1 of those keys P1 well how you show it will depend on what you are trying to show.  You could just consider it unspendable as 1 of 5 keys is insufficient.  You could show it as a seperate balance (additional keys/signatures needed).

P2SH works very similar except the script is not in the output.  You will need a copy of the redeem script which hashes to produce the ScriptHash in the output.  If you do not have the redeem script you can't even verify if you have the required PubKeys (as they are unknown).  If you do have the redeem script it would be parsed similar to multisig above.

As for how do existing clients do it.  My understanding is that the bitcoin-core client's "balance" reflects all unspent outputs which can be spent.  For single key it means the private key is in the wallet, for native multisig it means the required private keys are in the wallet, for P2SH the P2SH address, redeem script, and required private keys are in the wallet.  It may help to think of "balance" as the sum of value of all outputs the wallet has the ability to spend.

hero member
Activity: 742
Merit: 500
Well there is no address in any transaction so you don't need to decode the address (but you will need to decode the output script).

Ok, so when I see the "addresses" array in the bitcoind verbose output, is the bitcoind server doing some calculating for me?

There is no such thing as a balance, when a wallet says it has an X balance it means the sum of the value of the unspent outputs it has the ability to spend is X.

I understand that the protocol itself does not keep track of balances, which is part of the reason I'm tackling this issue.  When I say "bitcoind getbalance", it sums up all the unspent outputs I have available to me.  I'd like to programatically do the same for an arbitrary list of public keys.

If I have to parse the scripts then I'll do so, I'm just trying to get a handle on exactly what is required to calculate the available unspent outputs.  For now I'll stub out all other script formats besides the "normal" one, and tackle those later.  

We often talk about "sending coins to this address" but that kinda breaks down at the actual protocol level.  All outputs (as in all even "normal" transactions) are scripts.  The script defines what is required to spend that output.  If you use term like "balance of pubkey" in the case of multisig (either native or P2SH) which PubKey "has" the balance of the output?

Exactly my question.  I feel like I'm missing something fundamental here; how would a client calculate a 'balance' to be displayed in this kind of situation?  I'll probably have to do some testnet transaction creation to understand a bit more how this all works.

If you wanted to limit it to "normal" transactions (PayToPubKeyHash) you could just ignore all outputs which don't match this template
OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG


This may be a good first step.

For the moment I'll probably do this just so I can have some info to work with, but eventually I'll need to handle all the cases.  
donator
Activity: 1218
Merit: 1079
Gerald Davis
Well there is no address in any transaction so you don't need to decode the address (but you will need to decode the output script).  There is no such thing as a balance, when a wallet says it has an X balance it means the sum of the value of the unspent outputs it has the ability to spend is X.    There are just inputs and outputs.  Inputs reference a prior unspent output so you don't need to add them.  Outputs are either spent or unspent.  If an output is referenced is a future transaction input then it is spent.  Only unspent outputs can be spent in the future so your "balance" is just the sum of the outputs which are not yet referenced in an existing transaction's input.

There isn't necessarily a 1:1 relationship between outputs and public keys as outputs are actually scripts and can be in a variety of formats.  So if you want to handle all possible outputs your parser will need to decode the scripts.

The most common formats are
PayToPubKey (obsolete was used in early generation "coinbase" transactions)
PayToPubKeyHash (what most people think of as a "normal" transaction)
PayToScriptHash (aka P2SH, the address encodes a script hash not a pubkeyhash so payments are locked by the terms of a specific script)
Native Multisig (output script contains multiple public keys and OP_CHECKMULTISIG opcode)

P2SH and native Multisig are both methods to encumber an output with multiple keys.  They do the same thing in different ways.  In native, the output contains the actual script.  In P2SH the output contains the hash of the script needed to "spend" the output. P2SH is more common now and is often just called multisig which can make it complicated.

Here is a transaction with a native multisig (1 of 2) in the output (vout[0]): 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1
Here is a transaction with a P2SH output (vout[5]): d9a2ef9c07ab71ac12680df72cbbbf6153e7bb7ea511eb8ca764f434d378bbea

Yes Bitcoin is complicated.

We often talk about "sending coins to this address" but that kinda breaks down at the actual protocol level.  All outputs (as in all even "normal" transactions) are scripts.  The script defines what is required to spend that output.  If you use term like "balance of pubkey" in the case of multisig (either native or P2SH) which PubKey "has" the balance of the output?  With native multisig there are multiple pubkeys and a single output.  With P2SH you may not even know the script yet (just a hash of the script) so you have no way to determine which PubKey(s) can spend it.

If you wanted to limit it to "normal" transactions (PayToPubKeyHash) you could just ignore all outputs which don't match this template
OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG


This may be a good first step.
hero member
Activity: 742
Merit: 500
There are two types of multisig.  There is "native" multisig where the script and pubkeyhashes are in the vout however that makes for very large addresses.   P2SH was added later.  With P2SH the output is a hash of the script and that makes the address compact.

With native multisig there would be multiple pubkeyhashes in the output.  With P2SH there is just a single scripthash in the output. 

While bitcoin may show addresses understand that addresses are encoded hashes (either PubKeyHashes or ScriptHashes) and they don't exist in the protocol itself.  When you provide an address to a client it decodes the address to the reslting hashtype and the Hash is what is actually placed in the output of the transaction.

I'm sorry I'm not quite sure I understand.

Maybe if I tell you my intent it'll help understand where I'm lost.  I'm trying to write an algorithm to calculate the balance of a public key.  I had figured to add up all the inputs and subtract out all the outputs as I scanned along the block chain. 

From what I gather I'll have to decode the address to the resulting hash type and compare that to the hash that is placed in the output of each transaction I parse?
donator
Activity: 1218
Merit: 1079
Gerald Davis
There are two types of multisig.  There is "native" multisig where the script and pubkeyhashes are in the vout however that makes for very large addresses.   P2SH was added later.  With P2SH the output is a hash of the script and that makes the address compact.

With native multisig there would be multiple pubkeyhashes in the output.  With P2SH there is just a single scripthash in the output. 

While bitcoin may show addresses understand that addresses are encoded hashes (either PubKeyHashes or ScriptHashes) and they don't exist in the protocol itself.  When you provide an address to a client it decodes the address to the reslting hashtype and the Hash is what is actually placed in the output of the transaction.
legendary
Activity: 2053
Merit: 1356
aka tonikt
Oh, I see.
You're right - it doesn't seem to make much sense, having multiple addresses record there.

You'd need to ask then guys who put it in there.
hero member
Activity: 742
Merit: 500
Sorry, this I don't know.
Seems like you are talking about specifics of some source code that I am not familiar with.

No I'm referring to the bitcoind output.  if you look at the output for the transaction spending "from" the multi-sig, you'll get this:

Request:
Code:
bitcoind getrawtransaction d9a2ef9c07ab71ac12680df72cbbbf6153e7bb7ea511eb8ca764f434d378bbea 1

Response:
Code:
{
    "hex" : "0100000001e90191367cd56649ff96f45be2d21ba7e360aaea496b72c262dec4020826914c01000000fd8c0100483045022100adeac51e47a88cf6d3c1476550f9b34e5dbe5b347ef4ef590b5739a15bd7e0b2022006c24b4231028a8e1ad051aee5cb03884e763962d0d30fa94b51395c5107c79f01493046022100c6c3594f88b6ce4a71bd68a7dc8b0871176573cde99169a0e29611087e61e74102210095606fb6ad2c830013705101ad3762196e5c5c8577a48d9829d236dbb8c9a6e501483045022100b11868f0f99f0bb1e9ad2653358f8a420e29a0f56fb5426903d26d72520ad00f02206d87c4dba546045dddbc4cd3f23f5c53b51f8d53054718b67cdbc4d3601faf58014cad532102de57a0ac92a982903599cc1125f3ad6c360f5e091be2667bd2a07efae637d68a2102f0003265a9c7f5acdb7a40b9b98ace45f3111f421274c7b94f697faa337ac4c02103938fcd91c0a318876975a5648053eccb9ef275a0bade7b79f35d0f90694866652103a145418c25662a857248a9f49ff10ee4a53d28ce144a6954b19a71bbdc68c0c12103cf2e5b02d6f02340f5a9defbbf710c388b8451c82145b1419fe9696837b1cdef55aeffffffff0600a3e111000000001976a914a133373fb270ac403dc1a0bc2ccefcaf25261eef88ac00a3e111000000001976a9145749515e39e6962521072cd322c51939b7d9ff5c88ac00a3e111000000001976a914b87d8c0c149020ca55616a798bf71618b76e31d888ac00a3e111000000001976a914c3323e8f2a4acca83f0a07aaee359f8b0bd3e79488ac00e1f505000000001976a9145cc3df6331431526585aeba326406cfa9add2edd88acb01df5050000000017a9140136d001619faba572df2ef3d193a57ad29122d98700000000",
    "txid" : "d9a2ef9c07ab71ac12680df72cbbbf6153e7bb7ea511eb8ca764f434d378bbea",
    "version" : 1,
    "locktime" : 0,
    "vin" : [
        {
            "txid" : "4c91260802c4de62c2726b49eaaa60e3a71bd2e25bf496ff4966d57c369101e9",
            "vout" : 1,
            "scriptSig" : {
                "asm" : "0 3045022100adeac51e47a88cf6d3c1476550f9b34e5dbe5b347ef4ef590b5739a15bd7e0b2022006c24b4231028a8e1ad051aee5cb03884e763962d0d30fa94b51395c5107c79f01 3046022100c6c3594f88b6ce4a71bd68a7dc8b0871176573cde99169a0e29611087e61e74102210095606fb6ad2c830013705101ad3762196e5c5c8577a48d9829d236dbb8c9a6e501 3045022100b11868f0f99f0bb1e9ad2653358f8a420e29a0f56fb5426903d26d72520ad00f02206d87c4dba546045dddbc4cd3f23f5c53b51f8d53054718b67cdbc4d3601faf5801 532102de57a0ac92a982903599cc1125f3ad6c360f5e091be2667bd2a07efae637d68a2102f0003265a9c7f5acdb7a40b9b98ace45f3111f421274c7b94f697faa337ac4c02103938fcd91c0a318876975a5648053eccb9ef275a0bade7b79f35d0f90694866652103a145418c25662a857248a9f49ff10ee4a53d28ce144a6954b19a71bbdc68c0c12103cf2e5b02d6f02340f5a9defbbf710c388b8451c82145b1419fe9696837b1cdef55ae",
                "hex" : "00483045022100adeac51e47a88cf6d3c1476550f9b34e5dbe5b347ef4ef590b5739a15bd7e0b2022006c24b4231028a8e1ad051aee5cb03884e763962d0d30fa94b51395c5107c79f01493046022100c6c3594f88b6ce4a71bd68a7dc8b0871176573cde99169a0e29611087e61e74102210095606fb6ad2c830013705101ad3762196e5c5c8577a48d9829d236dbb8c9a6e501483045022100b11868f0f99f0bb1e9ad2653358f8a420e29a0f56fb5426903d26d72520ad00f02206d87c4dba546045dddbc4cd3f23f5c53b51f8d53054718b67cdbc4d3601faf58014cad532102de57a0ac92a982903599cc1125f3ad6c360f5e091be2667bd2a07efae637d68a2102f0003265a9c7f5acdb7a40b9b98ace45f3111f421274c7b94f697faa337ac4c02103938fcd91c0a318876975a5648053eccb9ef275a0bade7b79f35d0f90694866652103a145418c25662a857248a9f49ff10ee4a53d28ce144a6954b19a71bbdc68c0c12103cf2e5b02d6f02340f5a9defbbf710c388b8451c82145b1419fe9696837b1cdef55ae"
            },
            "sequence" : 4294967295
        }
    ],
    "vout" : [
        {
            "value" : 3.00000000,
            "n" : 0,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 a133373fb270ac403dc1a0bc2ccefcaf25261eef OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a914a133373fb270ac403dc1a0bc2ccefcaf25261eef88ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "1FhM9RUTswvr1RPPDLC7ddm1d1kMPQ85oD"
                ]
            }
        },
        {
            "value" : 3.00000000,
            "n" : 1,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 5749515e39e6962521072cd322c51939b7d9ff5c OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a9145749515e39e6962521072cd322c51939b7d9ff5c88ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "18xXcuLXhJmFcKoiLHqbjcpG4ip66pSf3E"
                ]
            }
        },
        {
            "value" : 3.00000000,
            "n" : 2,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 b87d8c0c149020ca55616a798bf71618b76e31d8 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a914b87d8c0c149020ca55616a798bf71618b76e31d888ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "1HpVjTeSnoqCkoCsX2iwMYqWrDy5UTzGC1"
                ]
            }
        },
        {
            "value" : 3.00000000,
            "n" : 3,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 c3323e8f2a4acca83f0a07aaee359f8b0bd3e794 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a914c3323e8f2a4acca83f0a07aaee359f8b0bd3e79488ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "1Jo6xSw431qX7GoVwc7oMTccLQwhfQVG6w"
                ]
            }
        },
        {
            "value" : 1.00000000,
            "n" : 4,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 5cc3df6331431526585aeba326406cfa9add2edd OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a9145cc3df6331431526585aeba326406cfa9add2edd88ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "19TVp7iN6FjSQJTA6DNS9nfauR6PM3Mb8N"
                ]
            }
        },
        {
            "value" : 0.99950000,
            "n" : 5,
            "scriptPubKey" : {
                "asm" : "OP_HASH160 0136d001619faba572df2ef3d193a57ad29122d9 OP_EQUAL",
                "hex" : "a9140136d001619faba572df2ef3d193a57ad29122d987",
                "reqSigs" : 1,
                "type" : "scripthash",
                "addresses" : [
                    "31oSGBBNrpCiENH3XMZpiP6GTC4tad4bMy"
                ]
            }
        }
    ],
    "blockhash" : "00000000000000000ce0a18c852d827e4936e800a81c58c3f1f8bfd7103ab5f4",
    "confirmations" : 1123,
    "time" : 1399840827,
    "blocktime" : 1399840827
}

The output has an array of "vouts".  Each "vout" has a "scriptPubKey" property, and each "scriptPubKey" property has an array "addresses".  I'm curious what the "addresses" array is in the serialized rawtransaction output from bitcoind.

legendary
Activity: 2053
Merit: 1356
aka tonikt
Sorry, this I don't know.
Seems like you are talking about specifics of some source code that I am not familiar with.
hero member
Activity: 742
Merit: 500
Ok, so it looks like multisig outputs each still only have one address in the "addresses" property of scriptPubKey property of the vout, and the only difference is the script that must be executed to unlock the output.

I guess I wrongly assumed that the vout.scriptPubKey.addresses[] property would list the addresses that can spend the output.

What is this array for?  It looks like it always just holds the output public key.  Is that correct?  In what scenario would this array have multiple addresses?
legendary
Activity: 2053
Merit: 1356
aka tonikt
Does anyone know of a multi-sig transaction I could look up on the blockchain to see it's structure?
Sending to ma multisig address looks like this: https://blockchain.info/tx/a93bd9eeaebcf4cd28e5822d28dddeb3e766e65e01e140168a90f928144e1c38 (first output)

And spending from it, like this: https://blockchain.info/tx/d9a2ef9c07ab71ac12680df72cbbbf6153e7bb7ea511eb8ca764f434d378bbea
Actually this one spends from multisig address and sends the change to itself (6th output)


Quote
How do you determine the target address of the multi-sig output?
The target address is basically a hash of the script that can spend it.

Taking as an example the transaction from the previous link, inside the input script you can find the spend script:
Code:
532102de57a0ac92a982903599cc1125f3ad6c360f5e091be2667bd2a07efae637d68a2102f0003265a9c7f5acdb7a40b9b98ace45f3111f421274c7b94f697faa337ac4c02103938fcd91c0a318876975a5648053eccb9ef275a0bade7b79f35d0f90694866652103a145418c25662a857248a9f49ff10ee4a53d28ce144a6954b19a71bbdc68c0c12103cf2e5b02d6f02340f5a9defbbf710c388b8451c82145b1419fe9696837b1cdef55ae
Now when you hash this data with rimped160(sha256(data)) it will give you:
Code:
0136d001619faba572df2ef3d193a57ad29122d9
That is the hash of the actual address: https://blockchain.info/address/31oSGBBNrpCiENH3XMZpiP6GTC4tad4bMy

To turn this Hash160 into a text-representation, you do this: https://en.bitcoin.it/wiki/Base58Check_encoding
You will use 0x05 as the version byte for a multisig address.
hero member
Activity: 742
Merit: 500
I'm trying to understand the internal workings of a transaction, so I executed the following command against bitcoind
Code:
bitcoind getrawtransaction fd3d049c9e75f96f9786b965b77b99fa0e7d39fa95e0b126682658299e71ac70 1

Here's the response:

Code:
{
    "hex" : "0100000001359815939bba9941e3bc0f9ffedea4e6b1c5c1885250b54cc11a20bc9c7fae51010000008c493046022100fbb4a90b868bdbd9229d7cc834373b502aa00eebb3d045088e8173be714f6943022100a26707f25a9955c23e71819300c1b32224881d8c09f65333503cb09d4fe62d4a014104558f3b743874639994ea070955847e85824b8bb9327c0297647f468bfd18e669c31ede14c44ae06af1b0bc4ffd06d6ffe564560e9c725b060bfd1ce89c843f2cffffffff028861706b030000001976a9148ca2fb6f0fcc4447764c6e4ed7929ed06f9797de88ac7874a112000000001976a9144640f7994705548593e476856e3680c42a641f8788ac00000000",
    "txid" : "fd3d049c9e75f96f9786b965b77b99fa0e7d39fa95e0b126682658299e71ac70",
    "version" : 1,
    "locktime" : 0,
    "vin" : [
        {
            "txid" : "51ae7f9cbc201ac14cb5505288c1c5b1e6a4defe9f0fbce34199ba9b93159835",
            "vout" : 1,
            "scriptSig" : {
                "asm" : "3046022100fbb4a90b868bdbd9229d7cc834373b502aa00eebb3d045088e8173be714f6943022100a26707f25a9955c23e71819300c1b32224881d8c09f65333503cb09d4fe62d4a01 04558f3b743874639994ea070955847e85824b8bb9327c0297647f468bfd18e669c31ede14c44ae06af1b0bc4ffd06d6ffe564560e9c725b060bfd1ce89c843f2c",
                "hex" : "493046022100fbb4a90b868bdbd9229d7cc834373b502aa00eebb3d045088e8173be714f6943022100a26707f25a9955c23e71819300c1b32224881d8c09f65333503cb09d4fe62d4a014104558f3b743874639994ea070955847e85824b8bb9327c0297647f468bfd18e669c31ede14c44ae06af1b0bc4ffd06d6ffe564560e9c725b060bfd1ce89c843f2c"
            },
            "sequence" : 4294967295
        }
    ],
    "vout" : [
        {
            "value" : 146.87429000,
            "n" : 0,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 8ca2fb6f0fcc4447764c6e4ed7929ed06f9797de OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a9148ca2fb6f0fcc4447764c6e4ed7929ed06f9797de88ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "1Dpcr4DhdAF8HaNKEnYgv9PJgBjErdUdnM"
                ]
            }
        },
        {
            "value" : 3.12571000,
            "n" : 1,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 4640f7994705548593e476856e3680c42a641f87 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a9144640f7994705548593e476856e3680c42a641f8788ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "17QU8RmoQT9T2uQadi24piJ2nE1rDjfn8g"
                ]
            }
        }
    ],
    "blockhash" : "000000000000050f650c03af06696d141dfaf39a213d1cd8aa46837fd37e425b",
    "confirmations" : 101258,
    "time" : 1348383754,
    "blocktime" : 1348383754
}

In a multi-sig scenario, I'm assuming the "reqSigs" under scriptPubKey (which is 1 in this example) would be higher than 1 and there'd be multiple addresses in the "addresses" array.  So here's my questions

  • Does anyone know of a multi-sig transaction I could look up on the blockchain to see it's structure?
  • How do you determine the target address of the multi-sig output?

I've tried some preliminary googling but can't seem to get a straight answer on the JSON representation of a multi-sig transaction.

Thanks.
Jump to: