Going by the example here: https://bitcoinj.github.io/working-with-contracts

I believe I've done everything correctly. Yet my program fails either to propagate correctly or because of a tx error and I cannot determine why

A few things I believe to be the reason

1) My peergroup.broadcastTransaction(spendTx) is not broadcasting properly 2) A malformed raw transaction or scriptsig ( I assume it is this, but again, no errors) 3) Generally not understanding the best method of linking outputs to inputs and signing them appropriately (for instance, do I use UTXO class, or TransactionSignature) 3) Trying to spend funds from a watched address. I have the necessary keys to unlock the UTXO's but I would like to see if I can spend the funds without the use of the wallet class 4) Multisig support in general for bitcoinj is lacking or incomplete. i hope it's not this as I would really like to get this working. But -- I don't think this is the biggest issue because I ran the unit tests and they still all check out clean.

A step through the code to be thorough:

Create 3 ECKeys for a 2-of-3 multisig contract, put them into a list, create a redeem script that sorts keys in lexicographical order and writes a m-of-n multisigoutputscript, then instantiate a Transaction object and assign it as the OUTPUT that I will be using as my INPUT (amount + redeemscript) AKA the UTXO that I will be spending (EDIT: Quick mention. The ECKeys I'm really using are hardcoded values that I made a while ago, these are for illustration purposes. I also should mention that this is a P2SH multisig, not the raw non-standard multisig.

ECKey keyA = new ECKey();
ECKey keyB = new ECKey();
ECKey keyC = new ECKey();

List<ECKey> keys = ImmutableList.of(key1, key2, key3);

Script script = ScriptBuilder.createRedeemScript(2, keys);
Script scriptPubKey = ScriptBuilder.createP2SHOutputScript(script);

Transaction contract = new Transaction(params);
TransactionOutput multiSigOutput = contract.addOutput(Coin.valueOf(50000), scriptPubKey);

Create a second transaction object that I will be using to assemble the output script AKA the (value + destination) address that i will be signing my UTXO over to. Also where the sigHash is signed by 2 of my keys and added to the scriptSig of the transaction

                        Transaction spendTx = new Transaction(params);
                        Address address = Address.fromBase58(params, "19EfMrs5WkcvtBBnuEqP6v1yppeWww61Kc");
                        Script outputScript = ScriptBuilder.createOutputScript(address);
                        spendTx.addOutput(multiSigOutput.getValue(), outputScript);
//                        System.out.println(spendTx.getOutputs());
                        TransactionInput input = spendTx.addInput(multiSigOutput);

now manually sign the inputs...(signatures are in same order as they are in script)

//sign transaction manually
Sha256Hash sigHash = spendTx.hashForSignature(0, script, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = list.get(0).sign(sigHash);
ECKey.ECDSASignature signature1 = list.get(1).sign(sigHash);
TransactionSignature txSig = new TransactionSignature(signature, Transaction.SigHash.ALL, false);
TransactionSignature txSig1 = new TransactionSignature(signature1, Transaction.SigHash.ALL, false);

...now create multisiginputscript, validate and broadcast tx

                        Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript((ImmutableList.of(txSig, txSig1)));
//                        System.out.println(inputScript);


                        System.out.println("transaction broadcasted");

ok...this doesn't propagate, but the verification checks out. and I don't even know if it's so much a network problem as it is a code problem because when I change the value in the output script to > the balance of the UTXO it doesn't throw a InsufficientMoneyException like I imagine it should. I'd show some error logs but there aren't any. The only error is when I change the createmultisiginputscript to createP2SHmultisiginputscript, the console puts out a non-null nulldummy error which I also have problems fixing, so I've never been able to know if changing to that method is the correct fix either. I think I set up the connection to the peergroup correctly as well

File chainFile = new File(this.getFilesDir(), "test.spvchain");
System.out.println("does chainfile exist?"  + chainFile.exists());
if(chainFile.exists()) {
    try {
        SPVBlockStore chainStore = new SPVBlockStore(params, chainFile);
        BlockChain chain = new BlockChain(params, chainStore);
        peerGroup = new PeerGroup(params, chain);
        peerGroup.addPeerDiscovery(new DnsDiscovery(params));
    } catch (BlockStoreException e) {

So I don't really get it... I've come to the conclusion my understanding is off somehow. Sorry for the confusing long post. It's been days. Can anyone help?

EDIT: Here's the raw transaction

In hex: 0100000001d917c0a19e19fa1cf2314baf037fdf952877daa4da845ab35d44ef33b45838c300000000fc00473044022022b97b9372d35acaea70f3735dee290f5697cab7b5d6be6f7cdfe31139fba4f90220651091b83570843d4fe8afe02d81417194908b0f6af6f8f3b8f1ad020592409f01473044022036eff4f54b8bf3f834f7bb6e417a04a6a696047f5c75a896c6f9b624ad87680a02200bf2115b64b3b15647178b69151d4588d8a4ade16a4d66e375d0e1265c79fad6014c695221025ab78e076801b45ccb2172bce562103cce1714edbeb02ce6123ce1235eb08c762102d1b74577050b696d5886a7afa61d099ea7ab0a3797766f9819dbd72526b0ce512103facf04db5d9bee657151e30c21e839489c326a277891ebcf75b736ec1e17fc1f53aeffffffff0150c30000000000001976a9145a566f4eda18e818b8d5ca04ee7c5fa3cfbf0e0088ac00000000

In logs:


01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: in 0[] PUSHDATA(71)[3044022022b97b9372d35acaea70f3735dee290f5697cab7b5d6be6f7cdfe31139fba4f90220651091b83570843d4fe8afe02d81417194908b0f6af6f8f3b8f1ad020592409f01] PUSHDATA(71)[3044022036eff4f54b8bf3f834f7bb6e417a04a6a696047f5c75a896c6f9b624ad87680a02200bf2115b64b3b15647178b69151d4588d8a4ade16a4d66e375d0e1265c79fad601] PUSHDATA1[5221025ab78e076801b45ccb2172bce562103cce1714edbeb02ce6123ce1235eb08c762102d1b74577050b696d5886a7afa61d099ea7ab0a3797766f9819dbd72526b0ce512103facf04db5d9bee657151e30c21e839489c326a277891ebcf75b736ec1e17fc1f53ae] 0.0005 BTC 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: outpoint:c33858b433ef445db35a84daa4da772895df7f03af4b31f21cfa199ea1c017d9:0 hash160:6d49586d7529626aaab49812bcd7839aee7e5800 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: out DUP HASH160 PUSHDATA(20)[5a566f4eda18e818b8d5ca04ee7c5fa3cfbf0e00] EQUALVERIFY CHECKSIG 0.0005 BTC 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: fee 0.00 BTC/kB, 0.00 BTC for 337 bytes 01-12 17:49:20.670 2507-2507/com.cryptoapp.app I/System.out: prps UNKNOWN


A couple comments from inspecting the Transaction data you posted.

1) I checked the UTXO you are spending from, which is UTXO

  • 9e7562d19165077d566af47bfbc18283629ed6799da8862660dfb037c353de11
  • Index 0

However, your transaction input is currently referencing the following UTXO:

  • c33858b433ef445db35a84daa4da772895df7f03af4b31f21cfa199ea1c017d9
  • Index 0

Which is not a confirmed transaction on main net.

2) Your input script seems properly formed to spend your P2SH(Multisig) output:

  • zero
  • [3044022022b97b9372d35acaea70f3735dee290f5697cab7b5d6be6f7cdfe31139fba4f90220651091b83570843d4fe8afe02d81417194908b0f6af6f8f3b8f1ad020592409f01]
  • [3044022036eff4f54b8bf3f834f7bb6e417a04a6a696047f5c75a896c6f9b624ad87680a02200bf2115b64b3b15647178b69151d4588d8a4ade16a4d66e375d0e1265c79fad601]
  • [2 [025ab78e076801b45ccb2172bce562103cce1714edbeb02ce6123ce1235eb08c76] [02d1b74577050b696d5886a7afa61d099ea7ab0a3797766f9819dbd72526b0ce51] [03facf04db5d9bee657151e30c21e839489c326a277891ebcf75b736ec1e17fc1f] 3 checkmultisig]

The final element is the embedded script, and should hash to the 20B digest in your UTXO you are spending: it does indeed hash160 correctly to 6d49586d7529626aaab49812bcd7839aee7e5800.

For your reference the P2SH(Multisig) output script of your UTXO is: "hash160 [6d49586d7529626aaab49812bcd7839aee7e5800] equal", note that the hashes are the same, so that's good.

3) You haven't included a fee in your transaction. The output amount of 50000 sats is identical to the UTXO amount. There needs to be a minimum fee for this transaction to be accepted by the mempool.

I hope this helps.

  • Thanks for your comment. It does verify. If it did not it would throw an error. – Stephen Jan 12 at 7:42
  • Script script = ScriptBuilder.createRedeemScript(2, keys); and Script script = ScriptBuilder.createMultiSigOutputScript(2, keys); are the same thing except createRedeemScript puts the keys in lexicographical order but it returns the same function – Stephen Jan 12 at 7:44
  • Can u post both raw tx here, would be easier to help debug. – James C. Jan 12 at 7:44
  • Ah ok. So u still need to confirm the first tx before broadcasting the second. – James C. Jan 12 at 7:45
  • So I'm a little bit confused. I thought the first tx was an output script which creates the template for the UTXO as context for the second transaction(and the verification). So you're saying I have to broadcast where i created the multisig script and then broadcast the spend as well? – Stephen Jan 12 at 7:48

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.