Bit-Wasp/bitcoin-php 的簡單使用:
這裡簡單介紹了一下最最最基礎的 Bit-Wasp/bitcoin-php 的用法,如果你對 bitcoin 還很陌生,推薦 【回形針PaperClip】區塊鏈到底是什麼? 瞭解 bitcoin 和 比特幣交易如何防偽?私鑰公鑰地址啥意思?李永樂老師講比特幣(2) 大致瞭解 bitcoin 的交易流程。想進一步瞭解 bitcoin,推薦閱讀 《精通比特幣》。
建立錢包
不同於中心化的錢包( 支付寶 / 微信 ),建立 Bitcoin 錢包不需要網路,只需要一個足夠隨機的數字 n ( 1 < n < 1.158 * 10^77 -1 ,略小於 2^256 ,關於這個數是否足夠安全,可以看這個影片:256位加密有多安全?),公鑰和地址都是由這個 n 生成,它被稱作 私鑰。
建立錢包本質上就是找到一個隨機數。
但是你不能用 php 自帶的隨機數生成函式!!!因為 php 自帶的這些隨機數生成函式並不是密碼學安全的隨機數生成器(它是基於 unix時間戳 / mac地址 / etc 生成的數字,並不是真正的隨機數)。
但是我們可以使用 Bit-Wasp/bitcoin-php 中密碼學安全的隨機數生成器生成一個隨機數來作為我們的錢包:
在 Laravel Job 中的實現<?php namespace App\Jobs\Bitcoin; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use App\Models\Bitcoin\Wallet; use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Crypto\Random\Random; use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory; class GenerateWallet implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Execute the job. * * @return void */ public function handle() { $random = new Random(); $private_key_factory = new PrivateKeyFactory(); $private_key = $private_key_factory->generateCompressed($random); $public_key = $private_key->getPublicKey(); // p2pkh 格式的地址 $address = new PayToPubKeyHashAddress($public_key->getPubKeyHash()); // 將生成的錢包儲存到資料庫中 $wallet = new Wallet; $wallet->wif = $private_key->toWif($network); $wallet->address = $address->getAddress(); $wallet->save(); // 儲存到日誌檔案中 $log = "wif: ". $wallet->wif . PHP_EOL . "address: ". $wallet->address . PHP_EOL . "-------------". date('Y-m-d Hs') ."------------" . PHP_EOL; file_put_contents('./wallets.log', $log, FILE_APPEND); } }
下面就是我們建立的一個新錢包的示例:
wif 是一種私鑰的格式,也是各個交易所、錢包所通用的私鑰匯入格式,原始的二進位制數主要用於程式內部。建立交易
我們首先來看一下一個已完成的交易有那些內容:
此標準交易的主要組成部分採用顏色編碼:交易ID(以黃色突出顯示)
描述符和後設資料(藍色花括號在右邊詳細說明)
輸入(粉色區域)
輸出(綠色區域)
我們要做的就是要離線構造一個如上的資料,在透過第三方或者你自己的結點廣播出去,待區塊確認後,即可視為完成了交易。
在這裡需要注意以下幾點:
交易資訊裡面,收款人的資訊在輸出裡面,鎖定指令碼(scriptPubKey)將限制使用人,也就是地址所對的私鑰。
交易時需要提供上次交易的 id,來證明你對 bitcoin 的所有權
bitcoin 的地址存在幾種型別,這裡暫不討論,這裡將根據提供的 p2pkh 地址傳送到 p2wpkh 地址
在 Laravel Job 中的實現<?php namespace App\Jobs\Bitcoin; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory; use BitWasp\Bitcoin\Script\Interpreter\InterpreterInterface as I; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Transaction\Factory\Signer; use BitWasp\Bitcoin\Transaction\Factory\TxBuilder; use BitWasp\Bitcoin\Transaction\OutPoint; use BitWasp\Bitcoin\Transaction\TransactionOutput; use BitWasp\Buffertools\Buffer; use BitWasp\Bitcoin\Transaction\Factory\SignData; use BitWasp\Bitcoin\Script\WitnessScript; use BitWasp\Bitcoin\Script\P2shScript; use BitWasp\Bitcoin\Address\SegwitAddress; use BitWasp\Bitcoin\Script\WitnessProgram; use BitWasp\Bitcoin\Address\AddressCreator; use GuzzleHttp\Client; use GuzzleHttp\Exception\ClientException; class Transfer implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Execute the job. * * @return void */ public function handle() { // 支付錢包的私鑰(wif 格式) $wif = 'KxwUMCtXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxEGooz'; // 支付錢包上一次交易的 id $txid = '4c7a031a31fe794e64ef5ca2714bdd9dd10ceae44650bce025952282bdeeda8b'; // 收款錢包地址(p2pkh 格式) $address = '1LRqwmjqLNNybJ3M2zQHiwvyA6ikbQQkyS'; $privKeyFactory = new PrivateKeyFactory; $key = $privKeyFactory->fromWif($wif); $witnessScript = new WitnessScript( ScriptFactory::scriptPubKey()->payToPubKeyHash($key->getPubKeyHash()) ); $dest = new SegwitAddress( WitnessProgram::v0( (new AddressCreator())->fromString($address)->getHash() ) ); // UTXO $outpoint = new OutPoint(Buffer::hex($txid, 32), 0); // 這裡一共將支出 100000 聰(0.00000001 BTC = 1 聰) $txOut = new TransactionOutput(100000, $witnessScript); // 收款人將收到 90000 聰,中間的差將作為礦工的手續費 $builder = (new TxBuilder()) ->spendOutPoint($outpoint) ->payToAddress(90000, $dest); // 簽署交易 $signer = new Signer($builder->get(), Bitcoin::getEcAdapter()); $input = $signer->input(0, $txOut); $input->sign($key); $signed = $signer->get(); // 需要進行廣播的交易 $broadcast = $signed->getBaseSerialization()->getHex(); // 我這裡使用 blockchain.info 的介面進行廣播,你可以使用你自己的結點,或者現成的 RPC 介面 $client = new Client; try { $response = $client->request('POST', 'https://blockchain.info/pushtx', [ 'form_params' => [ 'tx' => $signed->getBaseSerialization()->getHex() ] ]); var_dump(json_decode($response->getBody(), true)); } catch (ClientException $e) { var_dump($e->getResponse()); } }
待 10-15 分鐘後,交易被寫入區塊,再等待後續生成 2-3 個區塊,即可視為交易完成。
你可以在 Electrum 這樣的開源錢包中檢視你收到的錢
關於手續費:
你完全可以一毛不拔,一聰都不給,但是就沒有礦工願意打包你的交易,你的交易將永遠無法完成。bitcoin 礦工的收入來自打包完成的系統獎勵(到 2024 年就沒有了)和該區塊中的所有交易的手續費,所以礦工總是優先打包手續費多的交易。
本作品採用《CC 協議》,轉載必須註明作者和本文連結