2

I am using golang's btcd as a basis for creating some server-side tools for handling transactions. I found a good example for creating a basic one-input-one-output transaction to get me started on the implementation, and I have also read the documentation heavily on the technical specifics here. I have also looked at the other btcsuite libraries pretty heavily to try to gain more insight. To be clear, I am NOT expecting any of these tools to issue the transaction or anything like that; I understand that this was written out of btcd in particular for very, very good reasons. I am just trying to use these tools to create valid transactions that I can issue later.

I am still incredibly confused on the particulars in implementing multiple input, multiple output transactions and the scripts that we use on them. A few topics:

  • I'm familiar with the script tools in btcd, the link goes to the most common one used, but all of these scripts are used for one specific output. There seems to be absolutely no documentation anywhere about how to provide scripting for multiple outputs. If I'm doing a normal P2PK or P2PKH transaction, do I simply concatenate the scripts for all the various outputs, or what?
  • In the create Transaction example in the HelloBitcoin example I've linked above, the overall magic happens near the end with:

    buffer.Write(version)
    buffer.Write(inputs)
    buffer.Write(inputTransactionBytesReversed)
    buffer.Write(outputIndexBytes)
    buffer.WriteByte(byte(scriptSigLength))
    buffer.Write(scriptSig)
    buffer.Write(sequence)
    buffer.Write(numOutputs)
    buffer.Write(satoshiBytes)
    buffer.WriteByte(byte(scriptPubKeyLength))
    buffer.Write(scriptPubKey)
    buffer.Write(lockTimeField)
    

And I feel like there are a lot of unanswered questions on how to expand this to handle multiple inputs and multiple outputs. For the inputs, is it as simple as taking all the input transactions into little-endian, noting the correct number in inputs, and going from there? For outputs, do you just have an individual block of to satoshiBytes to scriptPubKey? I can't find in the documentation how this is supposed to all glue together, and at this point I feel like I need some help with the nuts and bolts of this. Thanks in advance for any help - if we can get these two points answered I might end up making more questions from the stuff that will inevitably result from this.

2

There might not be an easy answer, but the developper documentation is probably a first stop (https://bitcoin.org/en/developer-examples#complex-raw-transaction). Also I used regularily a block explorer (e.g. blockchain.info) to display the transaction and also its "raw" format. This allows to see the tx details in it's JSON format. Also the book from Andreas helped alot (Mastering Bitcoin). And finally there is also this forum here (the search function is good), and bitcointalk.org. Oh, then there is the wiki as well: https://en.bitcoin.it/wiki/Protocol_documentation#tx.

For the inputs, is it as simple as taking all the input transactions into little-endian, noting the correct number in inputs, and going from there?

No, I don't think so. There is no such thing as simple :-) You are on the right path, additionally when assembling a raw, unsigned transaction, and you have to deal with field lengths, and with "var_int", which are explained in developper docs. Here is a sample tx, so you get an idea:

VERSION                                 01000000
TX_IN COUNT [var_int]:                  hex=03, decimal=3
 TX_IN[0]
  TX_IN[0] OutPoint hash (char[32])     94FAE0AC28792796063F23F4A4BA4F977A9599D1579C5AAE7CE6DDA4F8A6B1BB
  TX_IN[0] OutPoint index (uint32_t)    hex=14040000, reversed=00000414, decimal=1044
  TX_IN[0] Script Length (var_int)      hex=19, decimal=25
  TX_IN[0] Script Sig (uchar[])         76A914A438060482FCD835754EA4518C70CC2085AF48FA88AC
  TX_IN[0] Sequence (uint32_t)          FFFFFFFF
 TX_IN[1]
  TX_IN[1] OutPoint hash (char[32])     A3E719B12275357B15FC5DECD9088A0964FE860D49F026F2152E71F681AC3FA4
  TX_IN[1] OutPoint index (uint32_t)    hex=31040000, reversed=00000431, decimal=1073
  TX_IN[1] Script Length (var_int)      hex=19, decimal=25
  TX_IN[1] Script Sig (uchar[])         76A914A438060482FCD835754EA4518C70CC2085AF48FA88AC
  TX_IN[1] Sequence (uint32_t)          FFFFFFFF
 TX_IN[2]
  TX_IN[2] OutPoint hash (char[32])     874CD4C4E1683C43A98A9DAA0926BEA37C10616F165AC35481E8181BFD449C65
  TX_IN[2] OutPoint index (uint32_t)    hex=E0010000, reversed=000001E0, decimal=480
  TX_IN[2] Script Length (var_int)      hex=19, decimal=25
  TX_IN[2] Script Sig (uchar[])         76A914A438060482FCD835754EA4518C70CC2085AF48FA88AC
  TX_IN[2] Sequence (uint32_t)          FFFFFFFF

TX_OUT COUNT                            hex=01, decimal=1
 TX_OUT[0]
  TX_OUT[0] Value (uint64_t)            hex=8038010000000000, reversed_hex=0000000000013880, dec=80000, bitcoin=0.00080000
  TX_OUT[0] PK_Script Length (var_int)  hex=19, dec=25
  TX_OUT[0] pk_script (uchar[])         76A914C2DF275D78E506E17691FD6F0C63C43D15C897FC88AC
LOCK_TIME                               00000000

For outputs, do you just have an individual block of to satoshiBytes to scriptPubKey?

It is similiar to the example above, just don't have one at hand. But the majority of tx have a spend-to address, and a return address, so you might look a tx up in the block explorer... Happy coding ! :-)

  • Did you create this particular transaction? If so, can I get an idea of how you went about doing it? I don't care if it's in golang or not, I'm just trying to get a feel for how all of these pieces glue together. – tmesser Nov 12 '17 at 21:59
  • yup, manually assembled with a set of shell scripts. When you are on unixoide systems, they work with Linux, MacOS and OpenBSD. Here: github.com/pebwindkraft/trx_cl_suite – pebwindkraft Nov 12 '17 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.