public function testSignP2SH() { BitcoinLib::setMagicByteDefaults('bitcoin-testnet'); $redeem_script = "522103c0b1fd07752ebdd43c75c0a60d67958eeac8d4f5245884477eae094c4361418d2102ab1fae8dacd465460ad8e0c08cb9c25871782aa539a58b65f9bf1264c355d0982102dc43b58ee5313d1969b939718d2c8104a3365d45f12f91753bfc950d16d3e82e53ae"; $inputs = array(array("txid" => "83c5c88e94d9c518f314e30ca0529ab3f8e5e4f14a8936db4a32070005e3b61f", "vout" => 0, "scriptPubKey" => "a9145fe34588f475c5251ff994eafb691a5ce197d18b87", "redeemScript" => $redeem_script, "value" => 0.0001)); $outputs = array("n3P94USXs7LzfF4BKJVyGv2uCfBQRbvMZJ" => BitcoinLib::toSatoshi(0.0001)); $raw_transaction = RawTransaction::create($inputs, $outputs); /* * sign with first key */ $wallet = array(); RawTransaction::private_keys_to_wallet($wallet, array("cV2BRcdtWoZMSovYCpoY9gyvjiVK5xufpAwdAFk1jdonhGZq1cCm")); RawTransaction::redeem_scripts_to_wallet($wallet, array($redeem_script)); $sign = RawTransaction::sign($wallet, $raw_transaction, json_encode($inputs)); $this->assertEquals(2, $sign['req_sigs']); $this->assertEquals(1, $sign['sign_count']); $this->assertEquals('false', $sign['complete']); /* * sign with second key */ $wallet = array(); RawTransaction::private_keys_to_wallet($wallet, array("cMps8Dg4Z1ThcwvPiPpshR6cbosYoTrgUwgLcFasBSxsdLHwzoUK")); RawTransaction::redeem_scripts_to_wallet($wallet, array($redeem_script)); $sign = RawTransaction::sign($wallet, $sign['hex'], json_encode($inputs)); $this->assertEquals(2, $sign['req_sigs']); $this->assertEquals(2, $sign['sign_count']); $this->assertEquals('true', $sign['complete']); /* * sign with third key */ $wallet = array(); RawTransaction::private_keys_to_wallet($wallet, array("cNn72iUvQhuzZCWg3TC31fvyNDYttL8emHgMcFJzhF4xnFo8LYCk")); RawTransaction::redeem_scripts_to_wallet($wallet, array($redeem_script)); $sign = RawTransaction::sign($wallet, $sign['hex'], json_encode($inputs)); $this->assertEquals(2, $sign['req_sigs']); $this->assertEquals(3, $sign['sign_count']); $this->assertEquals('true', $sign['complete']); BitcoinLib::setMagicByteDefaults('bitcoin'); }
/** * signs a raw transaction * * @param $rawTransaction * @param $inputs * @return array */ protected function signTransaction($rawTransaction, $inputs) { $wallet = []; $keys = []; $redeemScripts = []; foreach ($inputs as $input) { //create private keys for signing $path = BIP32Path::path($input['path'])->privatePath(); $keys[] = $this->primaryPrivateKey->buildKey($path); $keys[] = $this->backupPrivateKey->buildKey($path->unhardenedPath()); $redeemScripts[] = $input['redeemScript']; } //add the keys and redeem scripts to a wallet to sign the transaction with BIP32::bip32_keys_to_wallet($wallet, array_map(function (BIP32Key $key) { return $key->tuple(); }, $keys)); RawTransaction::redeem_scripts_to_wallet($wallet, $redeemScripts); return RawTransaction::sign($wallet, $rawTransaction, json_encode($inputs)); }
$line = trim(fgets(STDIN)); $decode_redeem_script = RawTransaction::decode_redeem_script($line); if ($decode_redeem_script == FALSE) { echo "[ERROR]- Not a valid script!\n"; unset($decode_redeem_script); } else { $redeem_script = $line; echo "Learned about {$decode_redeem_script['m']} of {$decode_redeem_script['n']} address: " . BitcoinLib::public_key_to_address($redeem_script, '05') . "\n"; } } echo "Enter WIF encoded private keys: \n (1): "; $private_keys = array(); while ("\n" != ($line = fgets(STDIN))) { $line = trim($line); $t = BitcoinLib::validate_WIF($line, '80'); var_dump($t); if (BitcoinLib::validate_WIF($line, '80') == TRUE) { $private_keys[] = $line; } else { echo "Not a valid private key.\n"; } echo " (" . (count($private_keys) + 1) . "): "; } // Initialize wallet $wallet = array(); RawTransaction::private_keys_to_wallet($wallet, $private_keys, '00'); RawTransaction::redeem_scripts_to_wallet($wallet, array($redeem_script), '05'); $raw_transaction = '01000000018240b84b90a3ae326e13219dc8a2781661fa28e23129b26fea848dd8e01a0c520000000000ffffffff02d8270000000000001976a914b7119dfb9b5c8aa7157fec48fbe640ea347dc92b88ac584d0000000000001976a914592fb6dc8cf6cd561ec86fd5fbc2a140e5ac7bc988ac00000000'; $json = '[{"txid":"520c1ae0d88d84ea6fb22931e228fa611678a2c89d21136e32aea3904bb84082","vout":0,"scriptPubKey":"a914fb56f0d4845487cc9da00c3e91e63503245f151787","redeemScript":"52210385fae44cb9f0cf858e0d404baecf78d026fae4cc9dd4343b8562059473c2af7b2102f34a1b64155db258d3a910625bd80fae6adf67d7e5b5f3de03265a4208b552d841040fa9a86f3237237423dd8331dc481c0a949fe11594c5dfa0b54bdc105daa319f9de6547d97c22296d4211073e7cffa71c8d6cd4da639607ca64fca2705e562a353ae"}]'; $sign = RawTransaction::sign($wallet, $raw_transaction, $json); print_r($sign);
<?php use BitWasp\BitcoinLib\RawTransaction; require_once __DIR__ . '/../vendor/autoload.php'; // Transaction this created was spent in: 7f3bf55fdfd7c7858c6a9119ad13d2c2e10cd07186c0f6050bbb7c8b626c8642 // Private keys and redeem scripts $pks = array('5KKNNaV63GB68zCJAF6CnJTx3Zp71vNDBXcjHTLr6wjd9c2ETmu', 'KynFytiTLa2x8keQQwoEVKvewL5z5D1Hti4FDMU1v8kC3pk5BBhr'); $rs = array('52210385fae44cb9f0cf858e0d404baecf78d026fae4cc9dd4343b8562059473c2af7b2102f34a1b64155db258d3a910625bd80fae6adf67d7e5b5f3de03265a4208b552d841040fa9a86f3237237423dd8331dc481c0a949fe11594c5dfa0b54bdc105daa319f9de6547d97c22296d4211073e7cffa71c8d6cd4da639607ca64fca2705e562a353ae'); // Initialize wallet $wallet = array(); RawTransaction::private_keys_to_wallet($wallet, $pks, '00'); RawTransaction::redeem_scripts_to_wallet($wallet, $rs, '05'); $raw_transaction = '01000000018240b84b90a3ae326e13219dc8a2781661fa28e23129b26fea848dd8e01a0c520000000000ffffffff02d8270000000000001976a914b7119dfb9b5c8aa7157fec48fbe640ea347dc92b88ac584d0000000000001976a914592fb6dc8cf6cd561ec86fd5fbc2a140e5ac7bc988ac00000000'; $json = '[{"txid":"520c1ae0d88d84ea6fb22931e228fa611678a2c89d21136e32aea3904bb84082","vout":0,"scriptPubKey":"a914fb56f0d4845487cc9da00c3e91e63503245f151787","redeemScript":"52210385fae44cb9f0cf858e0d404baecf78d026fae4cc9dd4343b8562059473c2af7b2102f34a1b64155db258d3a910625bd80fae6adf67d7e5b5f3de03265a4208b552d841040fa9a86f3237237423dd8331dc481c0a949fe11594c5dfa0b54bdc105daa319f9de6547d97c22296d4211073e7cffa71c8d6cd4da639607ca64fca2705e562a353ae"}]'; $sign = RawTransaction::sign($wallet, $raw_transaction, $json); print_r($sign);
/** * sign a raw transaction with the private keys that we have * * @param string $raw_transaction * @param array[] $inputs * @return array response from RawTransaction::sign * @throws \Exception */ protected function signTransaction($raw_transaction, array $inputs) { $wallet = []; $keys = []; $redeemScripts = []; foreach ($inputs as $input) { $redeemScript = null; $key = null; if (isset($input['redeemScript'], $input['path'])) { $redeemScript = $input['redeemScript']; $path = BIP32Path::path($input['path'])->privatePath(); $key = $this->primaryPrivateKey->buildKey($path); $address = $this->getAddressFromKey($key, $path); if ($address != $input['address']) { throw new \Exception("Generated address does not match expected address!"); } } else { throw new \Exception("No redeemScript/path for input"); } if ($redeemScript && $key) { $keys[] = $key; $redeemScripts[] = $redeemScript; } } BIP32::bip32_keys_to_wallet($wallet, array_map(function (BIP32Key $key) { return $key->tuple(); }, $keys)); RawTransaction::redeem_scripts_to_wallet($wallet, $redeemScripts); return RawTransaction::sign($wallet, $raw_transaction, json_encode($inputs)); }