Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building a transaction with multiple P2PKH inputs and Single P2WPKH and 2 outputs #39

Open
kaning opened this issue Jul 29, 2020 · 18 comments

Comments

@kaning
Copy link

kaning commented Jul 29, 2020

Given this payload of transaction data

"unspentAddressOutputs": {
     "8db82fe48d275647df6e01246978594dffcf8166d080a58868be51ed63dc94cf": [
       {
         "value": 100000,
         "script": "76a9142b9bc14f739fbab340142f9e1ec800ff654e15d188ac",
         "addr": "mjVXwMisfn1hv7pb1a6BuU8aaBWmyNtT3G",
         "spent": false,
         "type": 0,
         "n": 1
       }
     ],
     "b8a654afc77292d2011c7ae79d1e2ef469add829d2f1ff4ec3d287216da9d2c1": [
       {
         "value": 1006,
         "script": "76a9145c654954c781d522d3d965d78bc7ff5fb983b5a888ac",
         "addr": "mowVoD35wRZWSueDN1UPDSdzVHZLh22gj7",
         "spent": false,
         "type": 0,
         "n": 0
       },
       {
         "value": 98736,
         "script": "00142b9bc14f739fbab340142f9e1ec800ff654e15d1",
         "spent": false,
         "type": 0,
         "n": 1
       }
     ],
}

I am trying to construct a transaction using these unspent outputs but it fails on building the transaction

final TransactionBuilder txb = TransactionBuilder(network: wallet.network);
txb.addInput('8db82fe48d275647df6e01246978594dffcf8166d080a58868be51ed63dc94cf', 1);
txb.addInput('b8a654afc77292d2011c7ae79d1e2ef469add829d2f1ff4ec3d287216da9d2c1', 0);
txb.addInput('b8a654afc77292d2011c7ae79d1e2ef469add829d2f1ff4ec3d287216da9d2c1', 1); //<- think this one is P2WPKH

// total is 199742
txb.addOutput('mowVoD35wRZWSueDN1UPDSdzVHZLh22gj7', 109742);
txb.addOutput('mjVXwMisfn1hv7pb1a6BuU8aaBWmyNtT3G', 90000 - fee);

txb.sign(vin: 0, keyPair: keypair);
txb.sign(vin: 1, keyPair: keypair);
txb.sign(vin: 2, keyPair: keypair, witnessValue: 98736);

txb.build.toHex() // this throws exception 'length called on null' and that comes from transaction.dart:253

when I remove

txb.addInput('b8a654afc77292d2011c7ae79d1e2ef469add829d2f1ff4ec3d287216da9d2c1', 1); //<- think this one is P2WPKH

and just sign

txb.sign(vin: 0, keyPair: keypair);
txb.sign(vin: 1, keyPair: keypair);

I get

0100000002cf94dc63ed51be6888a580d06681cfff4d59786924016edf4756278de42fb88d010000006a473044022067fe36a90b583006c491bb4ae22b6112ebf01d98095f71c18c6f21fc4e148edc02202a4553192d3c4f17181bce74d1be5692fb37d3b0757002f3286baf8902861ce3012102b2ed1998d523265ee7b28772ac5f43753cf83ceb5cb624a8cc136830745b26b1ffffffffc1d2a96d2187d2c34efff1d229d8ad69f42e1e9de77a1c01d29272c7af54a6b8000000006b483045022100f610387f519a51e6312ce015264f896f240c5dbf3e43a2fc377c80320c510835022048ff8890ae6350121a7ee0b1f6fc159dd413b2e0b0b11cabbab7e2f79eb02d02012102b2ed1998d523265ee7b28772ac5f43753cf83ceb5cb624a8cc136830745b26b1ffffffff024c270000000000001976a9145c654954c781d522d3d965d78bc7ff5fb983b5a888acea5d0100000000001976a9142b9bc14f739fbab340142f9e1ec800ff654e15d188ac00000000

basically equal to Script failed an OP_EQUALVERIFY operation

Am I using the library wrong?

@longhoangwkm
Copy link
Collaborator

Thanks for using @kaning, I will check it soon

@SFzxc
Copy link
Collaborator

SFzxc commented Aug 2, 2020

txb.addInput('b8a654afc77292d2011c7ae79d1e2ef469add829d2f1ff4ec3d287216da9d2c1', 1); //<- think this one is P2WPKH

It correct. But P2WPKH utxo need to add in a different way. You can take a look here: https://github.com/dart-bitcoin/bitcoin_flutter/blob/master/test/integration/transactions_test.dart#L73-L78

@SFzxc
Copy link
Collaborator

SFzxc commented Aug 2, 2020

Or you can give me testnet keyPair, I can give a try

@kaning
Copy link
Author

kaning commented Aug 5, 2020

Thanks for the response I will try that out.. I have since destroyed that wallet so I can't get you a keypair to test right now... But I will try this out and if I still have issues I will let you know.

Thanks again.

@kaning
Copy link
Author

kaning commented Aug 11, 2020

So given this hex, is it possible to tell me why I get Script failed an OP_EQUALVERIFY operation
0100000004227cb7f672c79c66908b7368ae9c4927f4f9432c567cb7933c8b7ef9ba48d3ff000000006a4730440220452883eab215ad0281f2e1a5a79131f9f8873fc9799bbef0791cf5004a389543022033bf0fdf741781811581673ee84666d2f5c95f1a938be237dc7096a2bf446ed80121024403d100458333779be6156c45943493accb7b2f7673f3a92cffcd6cf7efcdcdffffffff227cb7f672c79c66908b7368ae9c4927f4f9432c567cb7933c8b7ef9ba48d3ff010000006b483045022100e0a4aa0d490d9e3e046be4aba717b0b870392f0c7325c278432cbf175cda729502204c1bc11270dca78a78c7136aeeaf6b42b11e7f5316871dc880739cf7b9b3543e0121024403d100458333779be6156c45943493accb7b2f7673f3a92cffcd6cf7efcdcdffffffffadadaacaf2986e3b24f056fee473295f79b150b306fcedd5a74a6b40aaef44cc000000006a47304402201083956c539cf3d5da25493c92af5ee9bcf4ca3624864dbb3b4e2bc06e8c3f2d02201a7e71d52667b39f6eb01b569288dfc2519d3163299d7863c6244f78d944864b0121024403d100458333779be6156c45943493accb7b2f7673f3a92cffcd6cf7efcdcdffffffffdaa7e89b1667eea2e30950d5be79915aba925146e61b0371e568044973f9064f010000006a47304402204ec1001bd1dde42cdbeead07bd970d7b8a2e973155ba982b0a802ea33ddb5f3602202fa3289f07cd1cba374a747fa8489a2f4a3f540da80ed6efcbee3b28f0dda5500121024403d100458333779be6156c45943493accb7b2f7673f3a92cffcd6cf7efcdcdffffffff0288061700000000001976a914a560a38c175c6384797b06227a0fff49ef2c568988acf2770a00000000001976a914f9cb3042e698e21346bbcea183c7cd047774318988ac00000000

@longhoangwkm
Copy link
Collaborator

Could you show the code ?!

@brunocalmels
Copy link

Hey guys. I'm having trouble also using one legacy P2KPH and one P2WPKH input.

Is it even possible with the library as-is? Cause from exploring the code, I see that when there's one input with witness, it assumes every input has a witness.

@longhoangwkm
Copy link
Collaborator

longhoangwkm commented Nov 5, 2020

@brunocalmels

Is it even possible with the library as-is?

Possible, Could you show your trouble ?!

@brunocalmels
Copy link

This is a test trying to use 1 legacy and 1 segwit UTXO, which fails. Being bob, alice_segwit and alice_legacy three wallets:

      final utxo_legacy = alice_legacy.utxos.last;
      final utxo_segwit = alice_segwit.utxos.last;
      final balance_legacy = utxo_legacy['value'];
      final balance_segwit = utxo_segwit['value'];
      var minerFee = 3000;
      var tx_value_legacy = balance_legacy ~/ 10;
      var tx_value_segwit = balance_segwit ~/ 10;

      final txb = TransactionBuilder(network: specific_network);
      txb.setVersion(1);

      final p2wpkh = P2WPKH(
              data: PaymentData(pubkey: alice_segwit.pubNode.publicKey),
              network: specific_network)
          .data;

      txb.addInput(
        utxo_segwit['hash'],
        utxo_segwit['index'],
        null,
        p2wpkh.output,
      );

      txb.addInput(
        utxo_legacy['hash'],
        utxo_legacy['index'],
      );

      txb.addOutput(bob.publicAddr, tx_value_legacy);

      final change = balance_legacy +
          balance_segwit -
          tx_value_legacy -
          tx_value_segwit -
          minerFee;
      txb.addOutput(alice_legacy.publicAddr, change);

      final alice_signer_legacy = ECPair.fromPrivateKey(
        alice_legacy.privNode.privateKey,
        network: specific_network,
      );

      final alice_signer_segwit = ECPair.fromPrivateKey(
        alice_segwit.privNode.privateKey,
        network: specific_network,
      );

      txb.sign(
        vin: 0,
        keyPair: alice_signer_segwit,
        witnessValue: tx_value_segwit,
      );
      txb.sign(
        vin: 1,
        keyPair: alice_signer_legacy,
      );

      final rawTx = txb.build();

I'm getting:

NoSuchMethodError: The getter 'length' was called on null.
  Receiver: null
  Tried calling: length 

when building the transaction. The trace is:

Transaction.vectorSize package:bitcoin_flutter/src/transaction.dart:259
Transaction._byteLength.<fn> package:bitcoin_flutter/src/transaction.dart:254
ListMixin.fold (dart:collection/list.dart:237:22)
Transaction._byteLength package:bitcoin_flutter/src/transaction.dart:254
Transaction.weight package:bitcoin_flutter/src/transaction.dart:266
Transaction.virtualSize package:bitcoin_flutter/src/transaction.dart:275
TransactionBuilder._build package:bitcoin_flutter/src/transaction_builder.dart:255
TransactionBuilder.build package:bitcoin_flutter/src/transaction_builder.dart:209
main.<fn>.<fn>

Let me add that when using 2 legacy or 2 segwit UTXOs, it doesn't fail (as long as both are the same type).

@brunocalmels
Copy link

Hi @longhoangwkm! Any updates on this issue?

@gitcoinbot
Copy link

Issue Status: 1. Open 2. Started 3. Submitted 4. Done


This issue now has a funding of 0.003 BTC (102.52 USD @ $34171.73/BTC) attached to it.

@brunocalmels
Copy link

I've created a Gitcoin Issue with a bounty in order to get this handy project going forward. Hope it works and helps the project!

@gitcoinbot
Copy link

Issue Status: 1. Open 2. Started 3. Submitted 4. Done


Work has been started.

These users each claimed they can complete the work by 265 years, 6 months from now.
Please review their action plans below:

1) vmenond has started work.

Just faced a similar issue and found that our solution was in how we were deriving the keys used to sign the outputs.

Could you please share details about the key you are using to sign?

Learn more on the Gitcoin Issue Details page.

@brunocalmels
Copy link

I'm just signing using bitcoin_flutter's TransactionBuilder.sign() method, since txa and txb are TransactionBuilder objects.

@i5hi
Copy link

i5hi commented May 18, 2021

@brunocalmels How are you generating your keys? The error is most likely there.

@brunocalmels
Copy link

I really don't think so. Both using Legacy or Segwit UTXOs on their own work without any problem.

@brunocalmels
Copy link

I've created a test in order to make it reproducible. You can find it here. Just run the test and you should find a stack trace showing the error:

RangeError (byteOffset): Invalid value: Not in inclusive range 0..338: 339
dart:typed_data                                 _ByteDataView.setUint32
Transaction._toBuffer.writeUInt32               lib/src/transaction.dart:328
...

This could interest @i5hi who was after the issue also.

@i5hi
Copy link

i5hi commented Aug 16, 2021

@brunocalmels our team has been working on a Dart-C FFI for bdk. We will be open sourcing it soon too.

https://github.com/i5hi/rust-mobile has a starting point and tutorial for the Rust side of things. Will update with the Dart side soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants