コード例 #1
0
 public function testPayToPubKeyHashSignedTransaction()
 {
     $data = [1 => ['tx' => '010000000869c2997e9dd8ce50f9481a33971f0308e8d525ef8bf079f455fc7936d13f375a1f0000008a47304402202de0d834112506ed10549f751ce142094243390f3e035444f105b4764056314302205dfddc421b377c8b089182ddb3928ce02e73c86e5dfb9e66ca6a98810d7a2ac5014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffab9aae4a00230f30795cd928225e9f69f7c0e6146c535b641541cb81aa09b5297b0000008a47304402205604456b1ed6dcae5e5f370568dd71c8bfb44823d583e3fa781ae8117ed831a30220154ee1c49bfca8bd1970953255498cb6bc347de1df267ed1b0f70385bca29184014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffc036184c5aa93f74530359251e6ff63ab9e17ce7eb6f5d467c42675e318696e5010000008a47304402206c756a38757443794196d16e887c95b9b769b11c608b425e7580e4fcd8456642022040613fbff5e5412c8aa0c3a91b651a6fe6fcf793596a5e29bbc7bc5d73fc683a014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff727107bfb37c254f12b4dfdda9ded7544ea6e44298a657ecb1863e00f88e0700110000008c493046022100c24b9c50820d19457fc5842a124500bf2371397144fc6166bdaa4a94275e9dda022100fc6c59286cfdc2fca4cca62d0a1b4e7dd8125a18aee59e630877f85101aa441a014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5fffffffffb862000126a61dba547524f7302bc68ea177cf00f7a49c5b834c0fd397c4dfe390000008b483045022100c837ec9105ddaa75250a38e9942a624754ecacb025feb024adfa8a77914e6eff0220538a1407d7ed8b7417421113ee29c3d9699f87780907b4121068740f1eb31d68014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffdb35b57c65cf0fcdea54bfdebda43942d728001a06a9df0404a07801c87ccd8a090000008b483045022100b00faaa1b6a7c1cbe4c47791e302bbcbf1d4fee54cb3d1195d82ef05df0f8f0702207382b68bb44e8fadb0ae7b44f22a18df93e8e8e000d28c88f4fdff78d92a8316014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff539ff8e14dab98db92dbbaff03dda50136470bb30bf9fb5b844eb356bc31362d1f0000008b48304502205e41d2112c190396173562d7957b16e0bba64a40adbe466cfe98778d30d91fa20221009f62ac2e345dbd16639b4269c86f156c050e5747013d2a452cdd8c25b8c9aeb9014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffbc0dabbf27d0a58f0e2f5a36c11e7f270737ddc92ef0d8d1baacdeff24f39ed7110000008a473044021f3cfe420bd8a5baca342a3df2501f03165e8b8b76fea6fbc82dd05047c99fcd022100bfa829bce78d4f463abefbba943ea54dbbd931b5d7712e263eaf76d2779cf053014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff023011e100000000001976a91431b07b8df3c19573388bb688b4fd89f6233f5d7988acf4f31400000000001976a914d17e062579b71bfe199a80991a253d929f8bd35b88ac00000000', 'inputs' => [["txid" => "5a373fd13679fc55f479f08bef25d5e808031f97331a48f950ced89d7e99c269", "vout" => 31, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "29b509aa81cb4115645b536c14e6c0f7699f5e2228d95c79300f23004aae9aab", "vout" => 123, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "e59686315e67427c465d6febe77ce1b93af66f1e25590353743fa95a4c1836c0", "vout" => 1, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "00078ef8003e86b1ec57a69842e4a64e54d7dea9dddfb4124f257cb3bf077172", "vout" => 17, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "fe4d7c39fdc034b8c5497a0ff07c17ea68bc02734f5247a5db616a12002086fb", "vout" => 57, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "8acd7cc80178a00404dfa9061a0028d74239a4bddebf54eacd0fcf657cb535db", "vout" => 9, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "2d3631bc56b34e845bfbf90bb30b473601a5dd03ffbadb92db98ab4de1f89f53", "vout" => 31, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"], ["txid" => "d79ef324ffdeacbad1d8f02ec9dd3707277f1ec1365a2f0e8fa5d027bfab0dbc", "vout" => 17, "scriptPubKey" => "76a914d17e062579b71bfe199a80991a253d929f8bd35b88ac"]], 'outputs' => ["1L6hCPsCq7C5rNzq7wSyu4eaQCq8LeipmG" => 0.01373172]]];
     foreach ($data as $test) {
         $this->assertTrue(RawTransaction::validate_signed_transaction($test['tx'], json_encode($test['inputs']), '00'));
     }
 }
コード例 #2
0
 public function testPushDataOps()
 {
     $data = json_decode(file_get_contents(__DIR__ . "/data/pushdataops.json"), true);
     foreach ($data as $row) {
         $script = RawTransaction::pushdata($row['string']);
         $op = substr($script, 0, 2);
         $this->assertSame($row['op'], $op);
     }
 }
コード例 #3
0
 public function testdecoderawtransaction()
 {
     $arr = ["010000000869c2997e9dd8ce50f9481a33971f0308e8d525ef8bf079f455fc7936d13f375a1f0000008a47304402202de0d834112506ed10549f751ce142094243390f3e035444f105b4764056314302205dfddc421b377c8b089182ddb3928ce02e73c86e5dfb9e66ca6a98810d7a2ac5014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffab9aae4a00230f30795cd928225e9f69f7c0e6146c535b641541cb81aa09b5297b0000008a47304402205604456b1ed6dcae5e5f370568dd71c8bfb44823d583e3fa781ae8117ed831a30220154ee1c49bfca8bd1970953255498cb6bc347de1df267ed1b0f70385bca29184014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffc036184c5aa93f74530359251e6ff63ab9e17ce7eb6f5d467c42675e318696e5010000008a47304402206c756a38757443794196d16e887c95b9b769b11c608b425e7580e4fcd8456642022040613fbff5e5412c8aa0c3a91b651a6fe6fcf793596a5e29bbc7bc5d73fc683a014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff727107bfb37c254f12b4dfdda9ded7544ea6e44298a657ecb1863e00f88e0700110000008c493046022100c24b9c50820d19457fc5842a124500bf2371397144fc6166bdaa4a94275e9dda022100fc6c59286cfdc2fca4cca62d0a1b4e7dd8125a18aee59e630877f85101aa441a014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5fffffffffb862000126a61dba547524f7302bc68ea177cf00f7a49c5b834c0fd397c4dfe390000008b483045022100c837ec9105ddaa75250a38e9942a624754ecacb025feb024adfa8a77914e6eff0220538a1407d7ed8b7417421113ee29c3d9699f87780907b4121068740f1eb31d68014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffdb35b57c65cf0fcdea54bfdebda43942d728001a06a9df0404a07801c87ccd8a090000008b483045022100b00faaa1b6a7c1cbe4c47791e302bbcbf1d4fee54cb3d1195d82ef05df0f8f0702207382b68bb44e8fadb0ae7b44f22a18df93e8e8e000d28c88f4fdff78d92a8316014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff539ff8e14dab98db92dbbaff03dda50136470bb30bf9fb5b844eb356bc31362d1f0000008b48304502205e41d2112c190396173562d7957b16e0bba64a40adbe466cfe98778d30d91fa20221009f62ac2e345dbd16639b4269c86f156c050e5747013d2a452cdd8c25b8c9aeb9014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffffbc0dabbf27d0a58f0e2f5a36c11e7f270737ddc92ef0d8d1baacdeff24f39ed7110000008a473044021f3cfe420bd8a5baca342a3df2501f03165e8b8b76fea6fbc82dd05047c99fcd022100bfa829bce78d4f463abefbba943ea54dbbd931b5d7712e263eaf76d2779cf053014104b3d8c8c5896b0ed9537ccbdcfdf3f05cd4299988c72d078b841e0491bab198702c4befaa3da367c117c7c6217cd478c54b572e13de6ddd22c948f4b66c1562b5ffffffff023011e100000000001976a91431b07b8df3c19573388bb688b4fd89f6233f5d7988acf4f31400000000001976a914d17e062579b71bfe199a80991a253d929f8bd35b88ac00000000", "01000000074829be5251cac2c2f6bc5bb71b37a7cd57504408d42010b4a924dc4dd60dabba000000006b483045022100921b883c6a42e14a3718fa2b0b9cc72225c761121710fd380e8ffc25766b3f8302200c436640eeeb6dded3950d9782bb101ca6ebd6f3a7371a4f94f4d769d0e09292012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff7841ac6b34686946bff2996ee7a8c347efc4906f565ca15dec507faa085ed8a9000000006a47304402207499620cb0e7db680df261b10beca91988746389b51664f0906f30a8e96a7db60220410ca07f12a3edfb1521bd5c9b18c83f6ccc2ced62ff1fb910b4d2a4ad73ef16012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff7806bbe4b6e2b43c677f86845cee3e43d43e4e6da2f387cd15b3fcbafde436fb000000006a47304402201200e9c0a2a452f59ce94fff83128b1795cb2d241a79cd49ea90e56972e70d320220403640d7d103366a2b2f1e0782c3bbb5166c7947b500303b448e8fde27c02987012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff129ef9ae1bf2382bd123005102723eaeab4cd9a2287286c1286db74a836c68d6000000006a47304402206392c220d6cd142e9423d559791cc318f3be87d91049d6ee76fdeddec69ceb0d02201240b24be64041ef6a3b0ae94935b23d357a8dbcb1e379ee7d2a58e33b66e72a012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff2d918344bedaabd0a8406368518e2ba0ac0f48edd5733ef17909dfab6146789d000000006b483045022100bbdd6943c2233340de453f44f17641846df5d0e319782af48965eee9a2f40de80220304f7b200086b519b4f9b583c598e949f63df96539706391b813f0262a94beb4012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0efffffffffa83a3af885f23269b4fe583d38510a9902924399816ede03a95160c3cb87b3f000000006a4730440220397bfa4185f41910f80d18bc9ef29cb9583299b668175cf1fd01c0f62176ffc302206d11ba8807a7de0033553a44ef5535f100e62158f04e2cff7140506afef761de012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff3a0645bd4adcd0094d1e3c06104dd5037f53f14b7f533dacf5c3c02ffdd41a90000000006b4830450221009accebcf34cda23a9ded8dacaa6f80c87eaa734c2bc80b8aeaab4fe9b7ef9a1502202ce314930e89cee1a527daed448a52fe11bb77867aa5a8e33b07e24a2246ae96012103417cff182cd9886e693868f474d26af984e9af82b3d83116eb5bb591bbb87e0effffffff02676df004000000001976a9141713a60c250ad7e1b909baf09c3291257eef381188acbbde2500000000001976a914e3cf40e4218cdf11d9f3f339035a4b0937ba0a5888ac00000000", "01000000049c90b31e3ea1b3f157b64c6c12832292b3da372c23458fab097f660728f8d72b010000006a473044022008cc581b5a99c35683beb551770ffbebad6605f84a35118c25cc1d7685b5aeb402207b158c110b72cd635213eed7305ca762922ec464583c2d5dfb0f4e43562250b10121022235905741eb82e063b9736a3ced9e3686c0ca4fb14c9bb6e0c8cbdf308cf41dffffffffdb16fbc52a0b77fa466f4501b7dc8af2d9218e32d852f0a6a77e3d0063acb8f9000000006a47304402206c441ed1020c8a36ad6edd1f0c7296ee3d2f390cfca8893973c0714073a9c9cc022023ac27df5e8017c1933847dcbcb471e1349941a81bc83e98b358eea54f01d20a012103829a75e07a0c490f413455798cc7f4a6330f9a403491e063b44862f542b622caffffffff9e65c29ac0ae80db55c72915ecef387f2d2c4ad066694e6b6e3ea5868cb788b6010000006b483045022100a7544728bf36ad8e80927caae7fe6d8d74129f03ba37a841edf8984cc467fd2602203e2603ecf5fdd56e4ed5cde8034ee731535e980e4b84e2759471f7df76cda164012103d8959922eba9a927dec4d742f940e9421c705ae661c15b1a47e3e0baafbc0547ffffffffacffa835a861226cfc63f9b491fc1d5f782b0a9d82f9ee62c99a65eac8ff90a5000000006b483045022100b3aadc533e6de0fe5d9b14861526feddc988cf9e7d7c80eee9ccbd8b2883276502206bf589498a08b44e82b6e5f398d95820ad1e766844189dea202b8b390954176b0121037d14b11915f8f58ba90e6f219abbdb4bc48fdf412094dda6d5790f0edf084cf2ffffffff0aab3ccc10000000001976a9149a305f166390604123d628af06c8897324ae1b6688ac20965904000000001976a9140c0850e3da96e15fc722545f28bced12b46ff5bb88ac66409005000000001976a9149191be4fd37c3391e918a641626cfaf39594923a88ac107c5a00000000001976a914b46a76ad1f35e26f41251a79f68e65fb873d361688acc1b90f00000000001976a9143d0119812e60b1d71e42867dbc6ec09507d618d188ace0e76d01000000001976a914bdd386cd9deeace2557eabc489dcf2a699b82cb388ac7f420f00000000001976a9147c554abe9bf802a53b0cfd70c95c3860fdfefd3588ac4b765509000000001976a914f33c0d7be35d6d146d4618f665d4118b622d200d88acc4d55d0a000000001976a914396da404b5d95fa2261928de51157cc1052ccce188acec314100000000001976a914f09c529f3ebd2097ab81fc50145ba104058c938f88ac00000000", "0100000004bf3ff395d579649914060b71487e466e6fd09604eb62f57ffb63ce702b0c60ab000000008c493046022100896c3dcdaf7c01cf86d9a8105bc54b9065bc26a8a9ea478a491d244b466bf64c0221009377176af0277c45b9c81433d9983d34bb1cdbc37a7479d4a8bbdde4a5d192a0014104a5ed97469860bbe8f05b9964dbc83bb17e5d14383a54fc4395e1e698d01011f6827632c50871df697d46faab766a267cd3b12a17244db5af311133953b440e31ffffffff7010eb5de98223f6048c4e048b4c47b9078b5e6ea679f7d5a4e78d88def33002000000008b48304502206773a142ab11bd4bcac34f55f64ffd488dbdc8dc2a9197d75b1f3bf1da5c00ff022100c4c65d5ea66b00162a3744a9ff3ae60aeb19507e9c30a5ea9ea27fc26306007b014104a5ed97469860bbe8f05b9964dbc83bb17e5d14383a54fc4395e1e698d01011f6827632c50871df697d46faab766a267cd3b12a17244db5af311133953b440e31ffffffff705d8a483f532355a9a3cc4c2f8e9604ec5da99df9689319f0eb75378fd2b5a5000000008b48304502202e5299ab19138468421b4c48c5a78d7ed9e4783a266dd827b915dc27051755a002210093b4377bf0a0bf1ff0a40a996255463bc706ca49a7b23f45999125774c0b7d75014104a5ed97469860bbe8f05b9964dbc83bb17e5d14383a54fc4395e1e698d01011f6827632c50871df697d46faab766a267cd3b12a17244db5af311133953b440e31ffffffff8a0dfdaa0b30c5af535a1791ce3f0f158e197f311d6696b20b6ff56f89f27602000000008b4830450220472537228e29b49a06a9255b86323c2cf5a230fce789ef3b0a308aa58f9dafd4022100a14cfbafbbc682759d5491a2c4dfa1f8287649fafa88c0166fb7b9ef9e77d999014104a5ed97469860bbe8f05b9964dbc83bb17e5d14383a54fc4395e1e698d01011f6827632c50871df697d46faab766a267cd3b12a17244db5af311133953b440e31ffffffff0234b13c00000000001976a914794e3a3f5f542ebb3f2e640ea9417e3c7d41e40b88acfc4d2a00000000001976a914b526df90f2bb0c5830b469b8b8f96d25e127de5d88ac00000000", "01000000011aaebeeb686e02c3471f0cf9f12eb6d69e45c3dd89cc0fa135e26ca72ec8d2c1020000006b483045022100f119173e52f8950dc0f369c64546746b900d621633f7a1d9b386232b5c21d6430220197f389584d087f34d250ffc8e5908a6ec9651fd02f64f200d3a60abe0df4287012102a1c5150347aa359ad363b7ccaf8602e7538de37935ebb2bb1656e20bfc6cd111ffffffff02b421e428000000001976a91443d6d50fb700dc1d98494942f8c378b8cbbb0def88ac80969800000000001976a9148e10169967933a59a77260277bb6f4d2869ed53088ac00000000"];
     foreach ($arr as $tx) {
         $real = $this->client->decoderawtransaction($tx);
         $decode = RawTransaction::decode($tx);
         $count = count($real['vin']);
         for ($i = 0; $i < $count; $i++) {
             $this->assertEquals($real['vin'][$i]['scriptSig']['hex'], $decode['vin'][$i]['scriptSig']['hex']);
         }
         $count = count($real['vout']);
         for ($i = 0; $i < $count; $i++) {
             $this->assertEquals($real['vout'][$i]['scriptPubKey']['hex'], $decode['vout'][$i]['scriptPubKey']['hex']);
         }
     }
 }
コード例 #4
0
ファイル: Onchainlib.php プロジェクト: tzmg/BitWasp
 public function handle_sign_post_request($post_request)
 {
     $this->CI->load->model('order_model');
     $this->CI->load->model('bip32_model');
     $this->CI->load->library('bw_bitcoin');
     if (!isset($post_request['auth_id'])) {
         // Need this in order to delete it later, as the action is a write action.
         return 'Unable to proceed, no auth ID';
     }
     $decode_tx = \BitWasp\BitcoinLib\RawTransaction::decode($post_request['tx']);
     if ($decode_tx == FALSE) {
         return 'Invalid transaction';
     }
     $order = $this->CI->order_model->get($post_request['sign_order_id']);
     $signing_user = $post_request['user_id'] == $order['buyer']['id'] ? $order['buyer'] : $order['vendor'];
     $signing_pubkey_id = $order[strtolower($signing_user['user_role']) . '_public_key'];
     $user_key = $this->CI->bip32_model->get_child_key($signing_pubkey_id);
     $handle = $this->CI->bw_bitcoin->handle_order_tx_submission($order, $post_request['tx'], $user_key);
     if (is_string($handle)) {
         echo $handle;
     }
     return $handle;
     //$this->CI->onchain_model->clear_auth($post_request['auth_id']);
 }
コード例 #5
0
 public function js_html($redeem_script, $raw_transaction)
 {
     if (strlen($redeem_script) == '0' || strlen($raw_transaction) == '0') {
         return '';
     }
     $this->CI->load->model('transaction_cache_model');
     $decode_rs = \BitWasp\BitcoinLib\RawTransaction::decode_redeem_script($redeem_script);
     $pubkey_list = '';
     foreach ($decode_rs['keys'] as $i => $key) {
         $pubkey_list .= '    "' . $key . '"' . ($i < 2 ? ',' : '') . "\n";
     }
     $p2sh_info = \BitWasp\BitcoinLib\RawTransaction::create_multisig(2, $decode_rs['keys']);
     $decode_tx = \BitWasp\BitcoinLib\RawTransaction::decode($raw_transaction);
     $utxos = "";
     foreach ($decode_tx['vin'] as $vin => $input) {
         $tx_info = $this->CI->transaction_cache_model->get_payment($input['txid']);
         $utxos .= "\n{\n    address: '{$p2sh_info['address']}',\n    txid: '{$tx_info['tx_id']}',\n    vout: {$tx_info['vout']},\n    scriptPubKey: '{$tx_info['pkScript']}',\n    confirmations: 10,\n    amount: " . $tx_info['value'] . "\n}" . ($vin < count($decode_tx['vin']) - 1 ? ',' : '') . "\n";
         //".($current_block-$tx_info['block_height']).",
     }
     $outs = '';
     foreach ($decode_tx['vout'] as $vout => $output) {
         $outs .= '{
 address: "' . $output['scriptPubKey']['addresses'][0] . '",
 amount: ' . $output['value'] . "\n}" . ($vout < count($decode_tx['vout']) - 1 ? ',' : '');
     }
     $json = "\nvar pubkeys = [\n{$pubkey_list}\n];\n\nvar opts = {\n    nreq: 2,\n    pubkeys: pubkeys\n};\n\nvar serialized_pubkeys = [];\nfor (var i=0; i<3; i++) {\n    serialized_pubkeys.push(new bitcore.buffertools.Buffer(opts.pubkeys[i],'hex'));\n}\n\nvar script = bitcore.Script.createMultisig(opts.nreq, serialized_pubkeys, {noSorting: true});\nvar hash   = bitcore.util.sha256ripe160(script.getBuffer());\n\n\nvar p2shScript = script.serialize().toString('hex');\nvar p2shAddress = new bitcore.Address.fromScript(p2shScript).toString();\nconsole.log('got address: '+p2shAddress);\n\nvar utxos = [\n{$utxos}\n];\n\nvar outs = [\n{$outs}\n];\n\nvar hashMap = {};\nhashMap[p2shAddress] = p2shScript;\n        ";
     return $json;
 }
コード例 #6
0
 /**
  * Process
  */
 public function process()
 {
     // Die if the callback is already running
     if ($this->bw_config->bitcoin_callback_running == 'true') {
         // Hack to get the script running again if it's been running for over 5 minutes.
         if (time() - $this->bw_config->bitcoin_callback_starttime > 5 * 60) {
             echo "Reset callback running\n";
             $this->config_model->update(array('bitcoin_callback_running' => 'false'));
         } else {
             echo "Fail, as still running\n";
             // If not over 10 minutes, it might still be working, so just do nothing.
             return FALSE;
         }
     }
     $this->load->model('transaction_cache_model');
     $this->broadcast();
     // Load the cached transactions to process. Die if nothing to do.
     $list = $this->transaction_cache_model->cache_list();
     if ($list == FALSE) {
         return FALSE;
     }
     $this->load->model('order_model');
     $this->load->model('bitcoin_model');
     // No problems, so prevent other instances from running!
     $this->config_model->update(array('bitcoin_callback_running' => 'true', 'bitcoin_callback_starttime' => time()));
     // Load watched addresses, and payments received on addresses.
     $watched_addresses = $this->bitcoin_model->watch_address_list();
     $payments_list = $this->transaction_cache_model->payments_list('order');
     // Try to scrape payments to and from our multisig addresses.
     $order_finalized = array();
     $received_payments = array();
     foreach ($list as $cached_tx) {
         // Raw_transaction library is way faster than asking bitcoind.
         $tx = RawTransaction::decode($cached_tx['tx_raw']);
         // Check inputs of these transactions against our list of payments.
         if (count($tx['vin']) > 0 and $payments_list !== FALSE) {
             $spending_transactions = $this->transaction_cache_model->check_inputs_against_payments($tx['vin'], $payments_list);
             if (count($spending_transactions) > 0) {
                 foreach ($spending_transactions as $tmp) {
                     $check = $this->transaction_cache_model->check_if_expected_spend($tx['vout'], $tmp['order_id']);
                     // Put transaction into scam or successful array.
                     $order_finalized[] = array('final_id' => $cached_tx['tx_id'], 'address' => $tmp['assoc_address'], 'valid' => $check);
                 }
             }
         }
         // Check outputs against our list of addresses.
         if (count($tx['vout']) > 0) {
             $output_list = $this->transaction_cache_model->parse_outputs_into_array($cached_tx['tx_id'], $cached_tx['block_height'], $tx['vout']);
             if (count($output_list) > 0) {
                 foreach ($output_list as $tmp) {
                     // Someone is paying money to a watched address. Record the transaction.
                     if (in_array($tmp['address'], $watched_addresses['addresses'])) {
                         $tmp['purpose'] = $watched_addresses['data'][$tmp['address']]['purpose'];
                         $received_payments[] = $tmp;
                     }
                 }
             }
         }
         $delete_cache[] = array('tx_id' => $cached_tx['tx_id']);
     }
     // Log all incoming payments.
     if (count($received_payments) > 0) {
         echo "Handling " . count($received_payments) . " received_payments\n";
         $this->transaction_cache_model->add_payments_list($received_payments);
     }
     // Log all outgoing payments: orders being finalized.
     if (count($order_finalized) > 0) {
         echo "Handling " . count($order_finalized) . " order_finalized\n";
         $this->order_model->order_finalized_callback($order_finalized);
     }
     // Delete payments from the block cache.
     if (count($delete_cache) > 0) {
         echo "Clearing cache (" . count($delete_cache) . ")\n";
         $this->transaction_cache_model->delete_cache_list($delete_cache);
     }
     // This could be made into an autorun job:
     $this->order_model->order_paid_callback();
     $this->config_model->update(array('bitcoin_callback_running' => 'false'));
 }
コード例 #7
0
 /**
  * Create Spend Transaction
  *
  * This function takes a $from_address, an order address, and a $tx_outs array,
  * specifying who the transaction should pay.
  *
  * Returns TRUE if the transaction is successfully created, and previous details
  * removed, or else a string containing an error if it fails.
  *
  * @param string $from_address
  * @param array $tx_outs
  * @param string $script
  * @return bool|string
  */
 public function create_spend_transaction($from_address, array $tx_outs = array(), $script)
 {
     if (count($tx_outs) < 1) {
         return 'No outputs specified in transaction.';
     }
     $this->load->model('transaction_cache_model');
     // Add the inputs at the multisig address.
     $payments = $this->transaction_cache_model->payments_to_address($from_address);
     if (count($payments) == 0) {
         return 'No spendable outputs found for this address';
     }
     $order_id = $payments[0]['order_id'];
     // Create the transaction inputs
     $tx_ins = array();
     $tx_pkScripts = array();
     foreach ($payments as $pmt) {
         $tx_ins[] = array('txid' => $pmt['tx_id'], 'vout' => $pmt['vout']);
         $tx_pkScripts[] = array('txid' => $pmt['tx_id'], 'vout' => (int) $pmt['vout'], 'scriptPubKey' => $pmt['pkScript'], 'redeemScript' => $script);
     }
     $json = json_encode($tx_pkScripts);
     $tx_outs = array_map('strval', $tx_outs);
     $raw_transaction = RawTransaction::create($tx_ins, $tx_outs);
     if ($raw_transaction == FALSE) {
         return 'An error occurred creating the transaction!';
     } else {
         // Embed redeem script into all tx's
         $new_tx = RawTransaction::decode($raw_transaction);
         foreach ($new_tx['vin'] as &$input_ref) {
             //$empty_input = $script;
             $input_ref['scriptSig']['hex'] = $script;
         }
         $raw_transaction = RawTransaction::encode($new_tx);
         $decoded_transaction = RawTransaction::decode($raw_transaction);
         if ($this->update_order($order_id, array('unsigned_transaction' => $raw_transaction . " ", 'json_inputs' => "'{$json}'", 'partially_signed_transaction' => '', 'partially_signed_time' => '', 'partially_signing_user_id' => ''))) {
             $this->transaction_cache_model->clear_expected_for_address($from_address);
             $this->transaction_cache_model->log_transaction($decoded_transaction['vout'], $from_address, $order_id);
             return TRUE;
         }
         return 'An error occured updating the order!';
     }
 }
コード例 #8
0
 /**
  * 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));
 }
コード例 #9
0
$inputs = array(array('txid' => '6737e1355be0566c583eecd48bf8a5e1fcdf2d9f51cc7be82d4393ac9555611c', 'vout' => 0, 'value' => 0.0002, 'scriptPubKey' => '76a9147e3f939e8ded8c0d93695310d6d481ae5da3961688ac'));
// sum up the total amount of coins we're spending
$inputsTotal = 0;
foreach ($inputs as $input) {
    $inputsTotal += $input['value'];
}
// fixed fee
$fee = 0.0001;
// information of who we're sending coins to and how much
$to = '1PGa6cMAzzrBpTtfvQTzX5PmUxsDiFzKyW';
$send = 5.0E-5;
// calculate change
$change = $inputsTotal - $send - $fee;
// this is our own address
$changeAddress = "1CWYJZ4vSoemSCrfBvXreqEtojEeCUeKw3";
// create ouputs, one to recipient and one to change
$outputs = array($to => BitcoinLib::toSatoshi($send), $changeAddress => BitcoinLib::toSatoshi($change));
// import private key
$wallet = array();
RawTransaction::private_keys_to_wallet($wallet, array('L2V4QgXVUyWVoMGejTj7PrRUUCEi9D9Y1AhUM8E6f5yJm7gemgN6'), '00');
// crate unsigned raw transaction
$raw_transaction = RawTransaction::create($inputs, $outputs);
// sign the transaction
// to broadcast transaction take this value and `bitcoin-cli sendrawtransaction <hex>`
$sign = RawTransaction::sign($wallet, $raw_transaction, json_encode($inputs));
print_r($sign);
echo "\n";
// set the transaction hash from the raw transaction
$txid = RawTransaction::txid_from_raw($sign['hex']);
print_r($txid);
echo "\n";
コード例 #10
0
ファイル: Orders.php プロジェクト: luisangellopez/BitWasp
 /**
  * Details
  * Buyer URI: purchases/details/<order_id>
  * Vendor URI: orders/details/<order_id>
  * Admin URI: admin/orders/<order_id>
  *
  * Order details page. Shows buyer/vendor/admin the details of the
  * the order.
  *
  * @param    int $order_id
  */
 public function details($order_id)
 {
     if (!(is_numeric($order_id) && $order_id >= 0)) {
         redirect('');
     }
     $data['order'] = $this->order_model->get($order_id);
     // no restriction on buyer/vendor
     if ($data['order'] == FALSE) {
         redirect('');
     }
     // Work out if the user is allowed to view this order.
     if (!$this->current_user->user_role == 'Admin' && !($this->current_user->user_id == $data['order']['buyer']['id']) && !($this->current_user->user_id == $data['order']['vendor']['id'])) {
         redirect('');
     }
     // Only allow access when the order is confirmed by the buyer.
     if ($data['order']['progress'] == '0') {
         redirect('');
     }
     if ($this->current_user->user_role == 'Buyer') {
         $data['action_page'] = 'purchases/details/' . $order_id;
         $data['cancel_page'] = 'purchases';
     } else {
         if ($this->current_user->user_role == 'Vendor') {
             $data['action_page'] = 'orders/details/' . $order_id;
             $data['cancel_page'] = 'orders';
         } else {
             if ($this->current_user->user_role == 'Admin') {
                 $data['action_page'] = 'admin/order/' . $order_id;
                 $data['cancel_page'] = 'admin/orders';
             }
         }
     }
     $this->load->model('transaction_cache_model');
     $this->load->model('bip32_model');
     $this->load->model('review_model');
     $child_key_id = $data['order'][strtolower($this->current_user->user_role) . '_public_key'];
     $data['my_multisig_key'] = $this->bip32_model->get_child_key($child_key_id);
     $data['wallet_salt'] = $this->users_model->wallet_salt($this->current_user->user_id);
     $this->load->library('bw_bitcoin');
     $html = $this->bw_bitcoin->js_html($data['order']['redeemScript'], $data['order']['unsigned_transaction']);
     if (is_array($data['my_multisig_key'])) {
         $data['signing_info'] = array('parent_extended_public_key' => $data['my_multisig_key']['parent_extended_public_key'], 'extended_public_key' => $data['my_multisig_key']['extended_public_key'], 'bip32_provider' => $data['my_multisig_key']['provider'], 'full_key_index' => "m/0'/0/" . $data['my_multisig_key']['key_index'], 'key_index' => "m/0'/0/" . $data['my_multisig_key']['key_index'], 'public_key' => $data['my_multisig_key']['public_key'], 'partially_signed_transaction' => $data['order']['partially_signed_transaction'], 'unsigned_transaction' => $data['order']['unsigned_transaction'], 'wallet_salt' => $data['wallet_salt'], 'crafted_html' => $html);
         $ident = strtolower($data['my_multisig_key']['provider']);
         $this->_partial("sign_form_output", "orders/details_form_" . $ident);
         if ($ident == 'js') {
             $data['header_meta'] = $this->load->view('orders/add_signature_js', $data['signing_info'], TRUE);
             $this->load->model('users_model');
         } elseif ($ident == 'onchain') {
             $this->load->library('onchainlib');
             $tx_crc = substr(hash('sha256', $data['order']['partially_signed_transaction'] == '' ? $data['order']['unsigned_transaction'] : $data['order']['partially_signed_transaction']), 0, 8);
             $data['onchain_sign'] = $this->onchainlib->sign_request($data['order']['id'], $tx_crc);
         }
     }
     // Only allow a vendor to refund, if the progress is either 3 or 4 (not yet dispatched)
     $data['can_refund'] = ($this->current_user->user_role == 'Vendor' and in_array($data['order']['progress'], array('3', '4')));
     $data['display_sign_form'] = (bool) (($data['order']['vendor_selected_upfront'] == '1' or $data['order']['vendor_selected_escrow'] == '0') and $data['order']['progress'] == '3' && $this->current_user->user_role == 'Buyer' or $data['order']['progress'] == '4' && $this->current_user->user_role == 'Vendor' or ($data['order']['vendor_selected_escrow'] == '1' and $data['order']['vendor_selected_upfront'] == '0' and $data['order']['progress'] == '4' && $this->current_user->user_role == 'Vendor' or $data['order']['progress'] == '5' && $this->current_user->user_role == 'Buyer') or ($data['order']['progress'] == '6' and $data['order']['partially_signed_transaction'] == '' or $data['order']['partially_signed_transaction'] !== '' and $data['order']['partially_signing_user_id'] !== $this->current_user->user_id) or ($data['order']['progress'] == '8' and $data['order']['partially_signed_transaction'] == '' or $data['order']['partially_signed_transaction'] !== '' and $data['order']['partially_signing_user_id'] !== $this->current_user->user_id));
     $data['display_sign_msg'] = $data['order']['partially_signed_transaction'] == '' ? 'Please add first signature.' : 'Please sign to complete transaction.';
     // Only allow access to the form handling script if the form is allowed to be displayed.
     if ($data['display_sign_form'] == TRUE) {
         // JS
         if ($this->input->post('submit_js_signed_transaction') == 'Submit Transaction') {
             if ($this->form_validation->run('submit_js_signed_transaction') == TRUE) {
                 $check = $this->bw_bitcoin->handle_order_tx_submission($data['order'], $this->input->post('js_transaction'), $data['my_multisig_key']);
                 if (is_string($check)) {
                     $data['invalid_transaction_error'] = $check;
                 } else {
                     if ($check == TRUE) {
                         if (strlen($data['order']['partially_signed_transaction']) > 0) {
                             $this->current_user->set_return_message('Transaction has been submitted, and will be processed shortly.', 'success');
                             redirect($data['action_page']);
                         } else {
                             if ($data['order']['progress'] == '3') {
                                 // Buyer must sign early before vendor dispatches.
                                 $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                 $this->order_model->progress_order($order_id, '3', '4', $update);
                             } else {
                                 if ($data['order']['progress'] == '4') {
                                     // Vendor indicates they have dispatched.
                                     $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time(), 'dispatched_time' => time(), 'dispatched' => '1');
                                     $this->order_model->progress_order($order_id, '4', '5', $update);
                                 } else {
                                     if ($data['order']['progress'] == '6') {
                                         $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                         $this->order_model->update_order($order_id, $update);
                                     } else {
                                         if ($data['order']['progress'] == '8') {
                                             $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                             $this->order_model->update_order($order_id, $update);
                                         }
                                     }
                                 }
                             }
                             $this->current_user->set_return_message('Your partially signed transaction has been saved!', 'success');
                             redirect($data['action_page']);
                         }
                     }
                 }
             }
         }
         // Manual
         if ($this->input->post('submit_signed_transaction') == 'Submit Transaction') {
             if ($this->form_validation->run('input_transaction') == TRUE) {
                 $validate = $this->bw_bitcoin->handle_order_tx_submission($data['order'], $this->input->post('partially_signed_transaction'), $data['my_multisig_key']);
                 if (is_string($validate)) {
                     $data['invalid_transaction_error'] = $validate;
                 } else {
                     if ($validate == TRUE) {
                         if (strlen($data['order']['partially_signed_transaction']) > 0) {
                             $this->current_user->set_return_message('Transaction has been submitted, and will be processed shortly.', 'success');
                             redirect($data['action_page']);
                         } else {
                             if ($data['order']['progress'] == '3') {
                                 // Buyer must sign early before vendor dispatches.
                                 $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                 $this->order_model->progress_order($order_id, '3', '4', $update);
                             } else {
                                 if ($data['order']['progress'] == '4') {
                                     // Vendor indicates they have dispatched.
                                     $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time(), 'dispatched_time' => time(), 'dispatched' => '1');
                                     $this->order_model->progress_order($order_id, '4', '5', $update);
                                 } else {
                                     if ($data['order']['progress'] == '6') {
                                         $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                         $this->order_model->update_order($order_id, $update);
                                     } else {
                                         if ($data['order']['progress'] == '8') {
                                             $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time());
                                             $this->order_model->update_order($order_id, $update);
                                         }
                                     }
                                 }
                             }
                             $this->current_user->set_return_message('Your partially signed transaction has been saved!', 'success');
                             redirect($data['action_page']);
                         }
                     }
                 }
             }
         }
     }
     $data['redeem_script'] = RawTransaction::decode_redeem_script($data['order']['redeemScript']);
     $data['addrs'] = array($data['order']['buyer_payout'] => 'buyer', $data['order']['vendor_payout'] => 'vendor');
     if (isset($data['order']['public_keys']['admin'])) {
         $data['addrs'][BitcoinLib::public_key_to_address($data['order']['public_keys']['admin']['public_key'], $this->bw_config->currencies[0]['crypto_magic_byte'])] = 'admin';
     }
     if (strlen($data['order']['partially_signed_transaction']) > 0) {
         $data['raw_tx'] = RawTransaction::decode($data['order']['partially_signed_transaction']);
         $data['signer'] = $this->accounts_model->get(array('id' => $data['order']['partially_signing_user_id']));
     } else {
         if (strlen($data['order']['unsigned_transaction']) > 0) {
             $data['raw_tx'] = RawTransaction::decode($data['order']['unsigned_transaction']);
         }
     }
     $checkStrangeAddress = function () use($data) {
         $tx_addrs = array();
         foreach ($data['raw_tx']['vout'] as $vout) {
             $tx_addrs[] = $vout['scriptPubKey']['addresses'][0];
         }
         return count($tx_addrs) != count(array_intersect($tx_addrs, array_keys($data['addrs'])));
     };
     $data['strange_address'] = isset($data['raw_tx']) ? $checkStrangeAddress() : FALSE;
     $data['fees']['shipping_cost'] = $data['order']['shipping_costs'];
     $data['fees']['fee'] = $data['order']['fees'];
     $data['fees']['escrow_fees'] = $data['order']['extra_fees'];
     $data['fees']['total'] = $data['order']['shipping_costs'] + $data['order']['fees'];
     if ($this->current_user->user_role == 'Buyer' && $data['order']['paid_time'] == '') {
         $this->load->library('ciqrcode');
         $data['payment_url'] = "bitcoin:{$data['order']['address']}?amount={$data['order']['order_price']}&message=Order+{$data['order']['id']}&label=Order+{$data['order']['id']}";
         $data['qr'] = $this->ciqrcode->generate_base64(array('data' => $data['payment_url']));
     }
     $data['page'] = 'orders/details';
     $data['title'] = 'Order Details: #' . $data['order']['id'];
     $this->_render($data['page'], $data);
 }
コード例 #11
0
$redeem_script = "522103c0b1fd07752ebdd43c75c0a60d67958eeac8d4f5245884477eae094c4361418d2102ab1fae8dacd465460ad8e0c08cb9c25871782aa539a58b65f9bf1264c355d0982102dc43b58ee5313d1969b939718d2c8104a3365d45f12f91753bfc950d16d3e82e53ae";
$inputs = array(array("txid" => "83c5c88e94d9c518f314e30ca0529ab3f8e5e4f14a8936db4a32070005e3b61f", "vout" => 0, "scriptPubKey" => "a9145fe34588f475c5251ff994eafb691a5ce197d18b87", "redeemScript" => $redeem_script));
$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));
print_r($sign);
var_dump(2 == $sign['req_sigs'], 1 == $sign['sign_count'], '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));
print_r($sign);
var_dump(2 == $sign['req_sigs'], 2 == $sign['sign_count'], '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));
print_r($sign);
var_dump(2 == $sign['req_sigs'], 3 == $sign['sign_count'], 'true' === $sign['complete']);
コード例 #12
0
 /**
  * BIP32 Private Keys To Wallet
  *
  * This function accepts $wallet - a reference to an array containing
  * wallet info, indexed by hash160 of expected address.
  * It will attempt to add each key to this wallet, as well as all the
  * details that could be needed later on: public key, uncompressed key,
  * address, an indicator for address compression. Type is always set
  * to pubkeyhash for private key entries in the wallet.
  *
  * @param       $wallet
  * @param array $keys
  * @param null  $magic_byte
  */
 public static function bip32_keys_to_wallet(&$wallet, array $keys, $magic_byte = null)
 {
     $magic_byte = BitcoinLib::magicByte($magic_byte);
     RawTransaction::private_keys_to_wallet($wallet, array_map(function ($key) {
         return BIP32::import($key[0]);
     }, $keys), $magic_byte);
 }
コード例 #13
0
ファイル: multisig.php プロジェクト: mdance/bitcoin-lib-php
<?php

use BitWasp\BitcoinLib\BitcoinLib;
use BitWasp\BitcoinLib\RawTransaction;
require_once __DIR__ . '/../vendor/autoload.php';
$m = 2;
$public_keys = array('0379ddc228d8c44a85ae30c877a6b037ec3d627e0507f223a0412790a83a46cd5f', '024d1cf2ca917f4d679fc02df2a39c0a8110a1b6935b27ae6762a0ceeec7752801', '0258f70f6400aa6f60ff0d21c3aaf1ca236d177877d2b9ad9d2c55280e375ab2d2');
// Create redeem script
$redeem_script = RawTransaction::create_redeem_script($m, $public_keys);
// Obtain 20-byte hash of script
$hash160 = BitcoinLib::hash160($redeem_script);
// Convert to address with version 0x05.
$address = BitcoinLib::hash160_to_address($hash160, '05');
// Display data
$c = 0;
echo "Public Keys\n";
for ($i = 0; $i < count($public_keys); $i++) {
    echo "{$i} : " . $public_keys[$i] . "\n";
}
echo "\nRedeem Script\n";
echo "{$redeem_script}\n\n";
echo "Hash160\n";
echo "{$hash160}\n\n";
echo "Address\n";
echo "{$address}\n\n";
コード例 #14
0
                if ((int) $a[$i] < (int) $b[$i]) {
                    return -1;
                } else {
                    if ((int) $a[$i] > (int) $b[$i]) {
                        return 1;
                    } else {
                        continue;
                    }
                }
            }
        }
    }
    return 0;
});
// Create redeem script
$redeem_script = RawTransaction::create_redeem_script($m, $sorted_keys);
// Obtain 20-byte hash of script
$hash160 = BitcoinLib::hash160($redeem_script);
// Convert to address with version 0x05.
$address = BitcoinLib::hash160_to_address($hash160, '05');
// Display data
$c = 0;
echo "Public Keys\n";
print_r($public_keys);
echo "\n";
echo "\nSorted Keys: \n";
print_r($sorted_keys);
echo "\nRedeem Script\n";
echo "{$redeem_script}\n\n";
echo "Hash160\n";
echo "{$hash160}\n\n";
コード例 #15
0
<?php

use BitWasp\BitcoinLib\RawTransaction;
require_once __DIR__ . '/../vendor/autoload.php';
// Supply a raw transaction to verify
$raw_tx = '01000000010a74a5750934ce563a9f18812b73dea945e3796d08be5e2c7e817197b4b0665b000000006a47304402203e2b56c1728f6cdcd531d006f7a17e6608513432113290229762de1d1bc0e76902205a9a41c196845d40dc98b67641fa2a1ae52f714094c9ad1e6b99514fd567d187012103161f0ec2a99876733c7b7f63bdb3cede0980e39f18abd50adad2774bd8fe0917ffffffff02426f0f00000000001976a91402a82b3afaff3c4113d86005f7029301c770c61188acbd0e3f0e010000001976a9146284bcf16e0507a35d28c1608ee1708ed26c839488ac00000000';
// Look up the TxIn transactions to learn about the scriptPubKey..
$json_string = '[{"txid":"5b66b0b49771817e2c5ebe086d79e345a9de732b81189f3a56ce340975a5740a","vout":0,"scriptPubKey":"76a91416489ece44cc457e14f4e882fd9a0ae082fdf6c688ac"}]';
// Perform signature validation!
$verify = RawTransaction::validate_signed_transaction($raw_tx, $json_string);
var_dump($verify);
コード例 #16
0
$wallet[1] = BIP32::master_key('b861e093a58718e145b9791af35fb222');
$wallet[2] = BIP32::master_key('b861e093a58718e145b9791af35fb333');
print_r($wallet);
echo "Now we will generate a m/0' extended key. These will yield a private key\n";
$user[0] = BIP32::build_key($wallet[0][0], "3'");
$user[1] = BIP32::build_key($wallet[1][0], "23'");
$user[2] = BIP32::build_key($wallet[2][0], "9'");
print_r($user);
// As the previous is a private key, we should convert to the corresponding
// public key: M/0'
echo "As the previous is a private key, we should convert it to the corresponding\n";
echo "public key: M/0' \n";
$pub[0] = BIP32::extended_private_to_public($user[0]);
$pub[1] = BIP32::extended_private_to_public($user[1]);
$pub[2] = BIP32::extended_private_to_public($user[2]);
print_r($pub);
echo "This is the key you will ask your users for. For repeated transactions\n";
echo "BIP32 allows you to deterministically generate public keys, meaning less\n";
echo "effort for everyone involved\n\n";
echo "Now we can generate many multisignature addresses from what we have here: \n";
for ($i = 0; $i < 3; $i++) {
    $bip32key[0] = BIP32::build_key($pub[0], "0/{$i}");
    $bip32key[1] = BIP32::build_key($pub[1], "0/{$i}");
    $bip32key[2] = BIP32::build_key($pub[2], "0/{$i}");
    print_r($bip32key);
    $pubkey[0] = BIP32::extract_public_key($bip32key[0]);
    $pubkey[1] = BIP32::extract_public_key($bip32key[1]);
    $pubkey[2] = BIP32::extract_public_key($bip32key[2]);
    print_r($pubkey);
    print_r(RawTransaction::create_multisig(2, $pubkey));
}
コード例 #17
0
 public function testDecodeScriptPubKeyMatchBitcoinCore()
 {
     $vectors = ["51210240852c3c09ee317bd1373a5731a6af9ef8eea52c8c6870072c1c32aa6a36ded52103eb6972fe40be87fdeff93dc56764b3058c0d0fa2d282f680e818f26f558b1a3541049958b1816ebd74ee1a94ab80dd6557c439388ffccbc532bc852568fa0efcf096f0169639ac8103eff80ecea4acce7f7aae528c4ccee393c05000d17edc9e5d3c53ae" => "1 0240852c3c09ee317bd1373a5731a6af9ef8eea52c8c6870072c1c32aa6a36ded5 03eb6972fe40be87fdeff93dc56764b3058c0d0fa2d282f680e818f26f558b1a35 049958b1816ebd74ee1a94ab80dd6557c439388ffccbc532bc852568fa0efcf096f0169639ac8103eff80ecea4acce7f7aae528c4ccee393c05000d17edc9e5d3c 3 OP_CHECKMULTISIG"];
     foreach ($vectors as $hex => $asm) {
         $this->assertEquals($asm, RawTransaction::_decode_scriptPubKey($hex, true));
     }
 }
コード例 #18
0
<?php

use BitWasp\BitcoinLib\BitcoinLib;
use BitWasp\BitcoinLib\RawTransaction;
require_once __DIR__ . '/../vendor/autoload.php';
$m = 2;
$publicKeys = ['0379ddc228d8c44a85ae30c877a6b037ec3d627e0507f223a0412790a83a46cd5f', '024d1cf2ca917f4d679fc02df2a39c0a8110a1b6935b27ae6762a0ceeec7752801', '0258f70f6400aa6f60ff0d21c3aaf1ca236d177877d2b9ad9d2c55280e375ab2d2'];
// It's recommended that you sort the public keys before creating multisig
// Someday this might be standardized in BIP67; https://github.com/bitcoin/bips/pull/146
// Many other libraries already do this too!
RawTransaction::sort_multisig_keys($publicKeys);
// Create redeem script
$redeemScript = RawTransaction::create_multisig($m, $public_keys);
// Display data
echo "Public Keys: \n";
foreach ($publicKeys as $i => $publicKey) {
    echo "{$i} : {$publicKey} \n";
}
echo "\n";
echo "Redeem Script: \n";
echo "{$redeemScript['redeem_script']} \n\n";
echo "Address: \n";
echo "{$redeemScript['address']} \n\n";
コード例 #19
0
echo "             : " . BIP32::key_to_address($pub[0]) . "\n";
/////////////////////////////
// We're gonna spent the first txout from this tx:
//  https://www.blocktrail.com/BTC/tx/4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8
// Set up inputs here
$inputs = array(array('txid' => '4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8', 'vout' => 0));
// Set up outputs here
$outputs = array('1KuE17Fbcdsn3Ns5T9Wzi1epurRnKC9qVr' => BitcoinLib::toSatoshi(0.0004));
////////////////////////////
// Parameters for signing.
// Create JSON inputs parameter
// - These can come from bitcoind, or just knowledge of the txid/vout/scriptPubKey,
//   and redeemScript if needed.
$json_inputs = json_encode(array(array('txid' => '4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8', 'vout' => 0, 'scriptPubKey' => '76a914' . 'bf012bde5bd12eb7f9a66de5697b241b65a9a3c9' . '88ac')));
// build wallet from private key(s)
$wallet = array();
BIP32::bip32_keys_to_wallet($wallet, array($key), '00');
// Create raw transaction
$raw_transaction = RawTransaction::create($inputs, $outputs);
// Sign the transaction
$signed = RawTransaction::sign($wallet, $raw_transaction, $json_inputs);
print_r($signed);
echo "\n";
// Decode and print the TX
// print_r(RawTransaction::decode($sign['hex']));
// To broadcast the transaction onto the network
//  - grab the $signed['hex']
//  - `bitcoind sendrawtransaction <singed HEX>`
//    or use an API that supports sendraw
// This transaction was broadcasted and confirmed here:
//  https://www.blocktrail.com/BTC/tx/e04c14270b2a9fcff548bc0bdd16b22ec6c2903ea6aaf9f7656b81f1c4c6153b
コード例 #20
0
 /**
  * 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));
 }
コード例 #21
0
    $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);
コード例 #22
0
 /**
  * add OP_RETURN output
  *
  * $data will be bin2hex and will be prefixed with a proper OP_PUSHDATA
  *
  * @param string $data
  * @param bool   $allowNonStandard  when TRUE will allow scriptPubKey > 40 bytes (so $data > 39 bytes)
  * @throws BlocktrailSDKException
  */
 public function addOpReturn($data, $allowNonStandard = false)
 {
     $pushdata = RawTransaction::pushdata(bin2hex($data));
     if (!$allowNonStandard && strlen($pushdata) / 2 > 40) {
         throw new BlocktrailSDKException("OP_RETURN data should be <= 39 bytes to remain standard!");
     }
     $this->addOutput(['scriptPubKey' => self::OP_RETURN . RawTransaction::pushdata(bin2hex($data)), 'value' => 0]);
 }
コード例 #23
0
 /**
  * send the transaction using the API
  *
  * @param string    $identifier             the identifier of the wallet
  * @param string    $rawTransaction         raw hex of the transaction (should be partially signed)
  * @param array     $paths                  list of the paths that were used for the UTXO
  * @param bool      $checkFee               let the server verify the fee after signing
  * @return string                           the complete raw transaction
  * @throws \Exception
  */
 public function sendTransaction($identifier, $rawTransaction, $paths, $checkFee = false)
 {
     $data = ['raw_transaction' => $rawTransaction, 'paths' => $paths];
     // dynamic TTL for when we're signing really big transactions
     $ttl = max(5.0, count($paths) * 0.25) + 4.0;
     $response = $this->client->post("wallet/{$identifier}/send", ['check_fee' => (int) (!!$checkFee)], $data, RestClient::AUTH_HTTP_SIG, $ttl);
     $signed = self::jsonDecode($response->body(), true);
     if (!$signed['complete'] || $signed['complete'] == 'false') {
         throw new \Exception("Failed to completely sign transaction");
     }
     // create TX hash from the raw signed hex
     return RawTransaction::txid_from_raw($signed['hex']);
 }
コード例 #24
0
 /**
  * verify a signed message
  *
  * @param $address
  * @param $signature
  * @param $message
  * @return bool
  * @throws \Exception
  */
 public static function verifyMessage($address, $signature, $message)
 {
     $math = EccFactory::getAdapter();
     $generator = EccFactory::getSecgCurves($math)->generator256k1();
     // extract parameters
     $address = substr(hex2bin(self::base58_decode($address)), 0, -4);
     if (strlen($address) != 21 || $address[0] != hex2bin(self::magicByte())) {
         throw new \InvalidArgumentException('invalid Bitcoin address');
     }
     $signature = base64_decode($signature, true);
     if ($signature === false) {
         throw new \InvalidArgumentException('invalid base64 signature');
     }
     if (strlen($signature) != 65) {
         throw new \InvalidArgumentException('invalid signature length');
     }
     $recoveryFlags = ord($signature[0]) - 27;
     if ($recoveryFlags < 0 || $recoveryFlags > 7) {
         throw new \InvalidArgumentException('invalid signature type');
     }
     $isCompressed = ($recoveryFlags & 4) != 0;
     // message is <varInt><prefix><varInt><message>
     $messageHash = "Bitcoin Signed Message:\n" . hex2bin(RawTransaction::_encode_vint(strlen($message))) . $message;
     $messageHash = hash('sha256', hash('sha256', $messageHash, true), true);
     try {
         $pubkey = self::recoverPubKey($math->hexDec(bin2hex(substr($signature, 1, 32))), $math->hexDec(bin2hex(substr($signature, 33, 32))), $math->hexDec(bin2hex($messageHash)), $recoveryFlags, $generator);
     } catch (\Exception $e) {
         throw new \Exception("unable to recover key", 0, $e);
     }
     if ($pubkey === false) {
         throw new \Exception('unable to recover key');
     }
     $point = $pubkey->getPoint();
     // see that the key we recovered is for the address given
     if (!$isCompressed) {
         $pubBinStr = "" . str_pad(hex2bin(self::padHex($math->decHex($point->getX()))), 32, "", STR_PAD_LEFT) . str_pad(hex2bin(self::padHex($math->decHex($point->getY()))), 32, "", STR_PAD_LEFT);
     } else {
         $pubBinStr = ($math->mod($point->getY(), 2) == 0 ? "" : "") . str_pad(hex2bin(self::padHex($math->decHex($point->getX()))), 32, "", STR_PAD_LEFT);
     }
     $derivedAddress = hex2bin(self::magicByte()) . hash('ripemd160', hash('sha256', $pubBinStr, true), true);
     return $address === $derivedAddress;
 }