Bit-Wasp / bitcoin-php

Bitcoin implementation in PHP
The Unlicense
1.05k stars 419 forks source link

Script was NOT verified successfully.. #883

Closed mindkind closed 3 years ago

mindkind commented 3 years ago

`<?php

require_once(DIR . "/modules/bitcoin-php/vendor/autoload.php");

use BitWasp\Bitcoin\Bitcoin;

use BitWasp\Bitcoin\Address\Address; use BitWasp\Bitcoin\Address\AddressCreator; use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress; use BitWasp\Bitcoin\Address\ScriptHashAddress; use BitWasp\Bitcoin\Address\SegwitAddress; use BitWasp\Bitcoin\Script\P2shScript; use BitWasp\Bitcoin\Script\WitnessScript; use BitWasp\Bitcoin\Script\WitnessProgram;

use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;

use BitWasp\Buffertools\Buffer; use BitWasp\Bitcoin\Transaction\Factory\Signer; use BitWasp\Bitcoin\Transaction\Factory\TxBuilder; use BitWasp\Bitcoin\Transaction\OutPoint; use BitWasp\Bitcoin\Transaction\Transaction; use BitWasp\Bitcoin\Transaction\TransactionOutput; use BitWasp\Bitcoin\Transaction\TransactionInput; use BitWasp\Bitcoin\Transaction\TransactionFactory;

use BitWasp\Bitcoin\Script\Interpreter\InterpreterInterface as I; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Script\Script; use BitWasp\Bitcoin\Network\NetworkFactory; use BitWasp\Bitcoin\Transaction\Factory\SignData;

Bitcoin::setNetwork(NetworkFactory::bitcoinTestnet());

// Setup network and private key to segnet $privKeyFactory = new PrivateKeyFactory(); $key = $privKeyFactory->fromWif("cMwnKaFRvP9No8qdRUcuMzsMhyyCm8UEoNWhmfxW5F6Nn4Ak2rUA");

// Script is P2SH | P2WSH | P2PKH $witnessScript = new WitnessScript(ScriptFactory::scriptPubKey()->payToPubKeyHash($key->getPubKeyHash())); $p2shScript = new P2shScript($witnessScript);

$address = $p2shScript->getAddress()->getAddress();

// UTXO $outpoint = new OutPoint(Buffer::hex('cf1d74ef626b36eb0c9295f5dc7a45fcefece44b34ac8a02be4a114a8946bc1a', 32), 0); $txOut = new TransactionOutput(1947304, $p2shScript->getOutputScript());

$addressCreator = new AddressCreator();

// Create unsigned transaction $tx = (new TxBuilder()) ->spendOutPoint($outpoint) ->payToAddress(1946804, $addressCreator->fromString("mmQTeNks2M8roQBiup8fD8cfw5DiqxoYGn"));

// Sign the transaction

$signData = (new SignData()) ->p2sh($p2shScript) ->p2wsh($witnessScript);

$signer = new Signer($tx->get(), Bitcoin::getEcAdapter()); $input = $signer->input(0, $txOut, $signData); $input->sign($key);

$signed = $signer->get();

// Verify what we've produced

$consensus = ScriptFactory::consensus(); echo "Script validation result: " . ($input->verify(I::VERIFY_P2SH | I::VERIFY_WITNESS) ? "yay\n" : "nay\n");

echo PHP_EOL; echo "Witness serialized transaction: " . $signed->getHex() . PHP_EOL. PHP_EOL; echo "Base serialized transaction: " . $signed->getBaseSerialization()->getHex() . PHP_EOL;`

mindkind commented 3 years ago

I'm trying to spend this transaction but since its not a p2pkh address i am lost, can someone please help me.

afk11 commented 3 years ago

Hi, thanks for opening the issue

I glanced over the code and nothing seemed off with regards how you are using the library, I ran the script and saw "Script validation result: yay" so I took this to mean testnet3 wasn't accepting your signed transaction

https://blockstream.info/testnet/tx/cf1d74ef626b36eb0c9295f5dc7a45fcefece44b34ac8a02be4a114a8946bc1a

When I look at the transaction, I can spot the issue - the value you used in $txOut doesn't match the value of the output on the block explorer. This would explain why bitcoin php verified the transaction, but the network failed it - segwit signatures commit to the amount of the output being spent, to protect against certain attacks. Since the same value for 'amount' was used for signing + verification, the signature was 'valid' to bitcoin-php, but when the network verifies, it's using the actual value for 'amount' and so the signature fails

The fix happens on these two lines:

// this line, use 1946804
$txOut = new TransactionOutput(1947304, $p2shScript->getOutputScript());
...
// on this line, use an appropriate number that's smaller than 1946804 to allow for fees
 ->payToAddress(1946804, $addressCreator->fromString("mmQTeNks2M8roQBiup8fD8cfw5DiqxoYGn"));

I think if you make these alterations the transaction will broadcast - good luck and let me know if there's anything else

mindkind commented 3 years ago

Thank you sir ;)

afk11 commented 3 years ago

Glad you got it sorted!

zvrop1 commented 1 year ago

and how about me?, fail too...

Bitcoin::setNetwork(NetworkFactory::bitcoinTestnet());

// Setup network and private key to segnet $privKeyFactory = new PrivateKeyFactory(); $key = $privKeyFactory->fromWif("cTcRivQrRrbZXQ5YkeRV29BHGe3aBJuLsLcivZe35fHrTibFfCmB");

// Script is P2SH | P2WSH | P2PKH $witnessScript = new WitnessScript(ScriptFactory::scriptPubKey()->payToPubKeyHash($key->getPubKeyHash())); $p2shScript = new P2shScript($witnessScript);

$address = $p2shScript->getAddress()->getAddress();

// UTXO $outpoint = new OutPoint(Buffer::hex('7c2892e947cda2edfbec3e47a68949a3af995fb2aec41bb4dd190466ec2c79fb', 32), 0); $txOut = new TransactionOutput(100000, $p2shScript->getOutputScript());

$addressCreator = new AddressCreator();

// Create unsigned transaction $tx = (new TxBuilder()) ->spendOutPoint($outpoint) ->payToAddress(90000, $addressCreator->fromString("mvCR6zv4rY4p4NSEMKw38WKZEq5QSX1Zra"));

// Sign the transaction

$signData = (new SignData()) ->p2sh($p2shScript) ->p2wsh($witnessScript);

$signer = new Signer($tx->get(), Bitcoin::getEcAdapter()); $input = $signer->input(0, $txOut, $signData); $input->sign($key);

$signed = $signer->get();

sendrawtransaction RPC error: {"code":-26,"message":"mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)"}