比特幣錢包開發:隔離見證剖析與程式設計實踐
目標
- 理解什麼是隔離見證
- 交易地址型別
- 程式設計實踐:生成隔離見證地址
大家可能會想,這個隔離見證對我們比特幣錢包開發有什麼影響呢?接下來你就知道了。
一、什麼是隔離見證
隔離見證的英文叫做SegWit,是Segregated Witness的簡稱,隔離見證是對比特幣提出的一種升級方案,用於解決比特幣面臨的一系列嚴重問題,由Pieter Wuille(比特幣核心開發人員、Blockstream聯合創始人)在2015年12月首次提出。主要由BIP-141定義。
我們可以這樣來理解隔離見證:
見證:在比特幣裡指的是對交易合法性的驗證,用於證明自己擁有某些交易的輸出的見證資料。
隔離:就是把見證資料從交易信息裡抽離出來,單獨存放。
SegWit解決的問題
SegWit是由Bitcoin Core的擬議更新,Bitcoin Core是當前最受歡迎的比特幣標準客戶端,大多數企業使用。最初,該更新旨在解決交易的可擴充套件性,這也是比特幣軟體中眾所周知的弱點。雖然這種攻擊向量對使用者來說並不是最具破壞性的,但目前為止已經在多個攻擊案例中被利用,因此也就凸顯了修補這一漏洞的必要性。
目前,比特幣可擴充套件性問題主要源自區塊容量不足,這裡的問題就在於當前區塊的硬編碼限制為1兆位元組,而這並不足以承擔使用者每分鐘嘗試傳送的數百筆交易。因此,很多使用者必須排隊等候,直到他們的交易得到確認,這個等待的時間可能是幾個小時,甚或是幾天。隨著網路規模的擴大,交易強度也隨之增加,但區塊容量限制則保持不變,這就意味著問題會不斷惡化。
SegWit的解決方案由兩部分組成的:
- 第一,它可以立即將區塊容量限制增加到4兆位元組。這裡就有一點需要注意:4 MB是絕對最大值,而實際區塊容量將取決於網路條件。SegWit啟用後,專家預測區塊容量將在2到2.1兆的範圍內。
- 第二,解決交易的可擴充套件性,將大量交易移出區塊鏈使用雷電網路(Lightning Network)進行快速處理,預計將大大增加網路容量。
segwit的優點
- 增加塊可以執行的事務數。
- 降低交易費用。
- 減少每筆交易的規模。
- 現在可以更快地確認交易,因為等待時間將減少。
- 有助於比特幣的可擴充套件性。
- 由於每個區塊的交易數量將增加,因此可能會增加礦工可能收取的總費用。
- 消除交易延展性。
- 有助於啟用雷電協議。
二、交易地址型別
地址是使用Base58check格式化的20位元組雜湊值,去生成P2PKH或P2SH比特幣地址。目前最常用的方式是使用者交換支付資訊。
普通的比特幣交易地址有兩種型別:
- P2PKH(Pay-to-Public-Key-Hash):支付給公鑰雜湊。是最常用的模板,它被中本聰定義,允許簡單的支付給一個單一的公鑰。
- P2SH(Pay-to-Script-Hash):支付到指令碼,這是多重簽名交易輸出。在BIP16定義,它允許付款到任意複雜的指令碼。
隔離見證為比特幣建立了兩種新的交易地址:
- P2WPKH(Pay-to-Witness-Public-Key-Hash):支付到隔離見證公鑰雜湊,類似P2PKH,在BIP141新定義的。它嵌入在P2SH指令碼中,所以它可以被不知道segwit的錢包使用。
- P2WSH(Pay-to-Witness-Script-Hash):支付到多重簽名隔離見證指令碼雜湊,類似P2SH,是BIP141定義的另一個新的指令碼格式。它可以嵌入到P2SH指令碼和地址中,使得任何錢包都可以進行與segwit相容的支付。
隔離見證不會在整個網路中同時實施,為了新老客戶可以共存,錢包開發人員將應獨立升級錢包軟體以新增隔離見證功能。都升級為segwit的錢包後,使用P2WPKH和P2WSH付款型別,傳統的錢包使用P2PKH和P2SH付款型別。兩種形式的見證指令碼P2WPKH和P2WSH都可以嵌入到P2SH地址中,是以“3”開始的地址。P2PKH是以“1”開頭的地址。
舉個例子,假設有兩個人:lixu、zhangsan,lixu的錢包沒有升級到segwit,但是zhangsan的錢包已經升級,可以處理segwit交易。lixu和zhangsan都可以使用正常地址交易,但是zhangsan很可能會使用segwit來降低交易費用。在這種情況下,zhangsan的錢包就需要構建一個包含一個segwit指令碼的P2SH地址。lixu的錢包認為這是一個正常的P2SH地址,並可以在沒有任何segwit的知識的情況下付款。然後,zhangsan的錢包可以通過隔離交易來支付這筆款項,充分利用隔離交易並降低交易費用。
因此我們需要構建segwit地址相容普通地址。
三、程式設計實踐:生成隔離見證地址
程式碼
var bitcoin = require('bitcoinjs-lib'); var bip39 = require("bip39") var bip32 = require("bip32") const myNetwork = bitcoin.networks.bitcoin const mnemonic = 'eternal list thank chaos trick paper sniff ridge make govern invest abandon' // const mnemonic = bip39.generateMnemonic() const seed = bip39.mnemonicToSeed(mnemonic, "lixu1234qwer") const root = bip32.fromSeed(seed, myNetwork) for(var i = 0; i < 3; i++) { const path = "m/44'/0'/0'/0/"+i console.log("路徑:", path) const keyPair = root.derivePath(path) const privateKey = keyPair.toWIF() console.log("私鑰:", privateKey) const publicKey = keyPair.publicKey.toString("hex") console.log("公鑰:", publicKey) let address = getAddress(keyPair, myNetwork) console.log("普通地址:", address) let segWitAddress = getSegWitAddress(keyPair, myNetwork) console.log("隔離見證:", segWitAddress, "\n") } function getAddress(keyPair, network) { const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey , network:network}) return address } function getSegWitAddress(keyPair,myNetwork) { const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: myNetwork}), network: myNetwork }) return address }
輸出

驗證

程式碼解析
這裡只解getSegWitAddress方法的實現,其它程式碼解析請檢視上一章“從生成助記詞到擴充套件子地址”的內容。
const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey, network: myNetwork}), network: myNetwork })這是將p2wpkh地址巢狀在p2sh地址中,作為它的redeem欄位。同時需要注意,在兩種地址型別中都需要指定網路型別。上面的程式碼是在比特幣正式網路中執行的,即指定了
const myNetwork = bitcoin.networks.bitcoin
。
版權宣告:部落格中的文章版權歸博主所有,未經授權禁止轉載,轉載請聯絡作者取得同意並註明出處。
未經授權禁止轉載、改編,轉載請註明出處!