比特幣入門二基礎概念

一、比特幣協議與實現

從技術角度看,比特幣是一種數字加密貨幣協議,它僅僅約定了在比特幣網絡中 節點旳行爲規範,因此任何人都可以遵照此規範實現自己的比特幣節點軟件並接入 比特幣網絡。如果你希望深入瞭解比特幣協議,可以查看 這裏

容易理解,在現有的諸多實現中,最著名的就是最早由中本聰本人發起的 BitcoinCore項目:

BitcoinCore被稱爲比特幣協議的參考實現,這意味着它給出了比特幣協議的每 一部分應當如何實現的權威參考或者說範本,因此在本課程中將基於該軟件學習比特幣的使用 和應用開發。課程環境中預置了BitcoinCore軟件,如果你需要在自己的機器上 練習,可以從官方網站下載。

在BitcoinCore項目中,包含了兩個完整的比特幣協議實現:圖形版的bitcoin-qt和 命令行版的bitcoind,我們稱之爲節點軟件。這兩個軟件的作用是一致的, 在本課程在線環境中將使用bitcoind來部署比特幣節點:

部署在不同計算機上的節點軟件可以彼此聯通成一個複雜的P2P網絡,進而實現 比特幣交易的中繼、廣播與確認,因此是整個比特幣網絡的核心。

節點軟件通常也提供基於JSON RPC的API接口,以便其他應用集成對比特幣區塊鏈 的訪問能力。在BitcoinCore項目中的bitcoin-cli軟件就是一個基於節點RPC API的 命令行工具,我們將使用這個工具來學習比特幣的一些常用操作。

二、節點軟件與客戶端

節點軟件是比特幣網絡的核心,因此在繼續下面的課程之前,我們先在1# 終端啓動節點軟件bitcoind:~$ bitcoind

在1#終端按Ctrl+C就可以結束bitcoind的運行,或者在2#終端,使用 pkill命令結束:~$ pkill bitcoind

如果希望將區塊鏈清零,可以在停止bitoind的運行後,刪除整個數據目錄, 然後重新啓動

~$ pkill bitcoind

~$ rm -rf ~/.bitcoin/regtest

~$ bitcoind

配置節點軟件

bitcoind的運行依賴於其配置文件,在ubuntu中,該文件的路徑爲~/.bitcoin/bitcoin.conf

對於一個新部署的bitcoind節點,首先需要修改的是RPC API的訪問控制, 下面的設定將允許客戶端以用戶user和密碼123456來訪問RPC API接口:

rpcuser=user

rpcpassword=123456

bitcoind有三種運行模式,可以分別連接到主鏈、測試鏈或構建一個單節點 的私有鏈用於開發。在本課程中,我們將其運行模式設置爲私有鏈模式:

regtest=1

使用客戶端工具

節點軟件bitcoind實現了完整的比特幣規範,但是它沒有提供人機操作接口, 因此我們需要藉助於bitcoin-cli這個命令行工具來訪問節點軟件提供的功能。

例如,可以使用getbalance子命令來獲取節點錢包餘額:

注意:如果沒有執行過其他的操作,你看到的餘額應該是0.00000000

bitcoin-cli的子命令對應於節點旳JSON RPC開發接口,可以完成地址創建、 交易發送、餘額查詢、區塊瀏覽等諸多任務。

三、身份:密鑰與地址

比特幣的身份識別體系是建立在非對稱加密技術之上的去中心化系統, 每一個身份對應着一對密鑰。

非對稱加密採用一對密鑰(私鑰、公鑰)進行數據的加密或解密: 用私鑰加密,則需要用公鑰解密;用公鑰加密,則需要用私鑰解密。 這一非對稱特性使得其非常適合用於身份表示與驗證 —— 公鑰用於 身份的表示,而私鑰則用於身份的驗證:

在上圖中,當tommy需要向jerry發送原始數據時,他首先使用自己的私鑰對 原始數據進行簽名,得到的簽名數據附加在原始數據後面,一同發送給jerry。 jerry收到數據後,使用tommy的公鑰就可以驗證簽名是否是由tommy的私鑰簽發的, 從而確認該數據確實來自於tommy。

雖然公鑰可以唯一的標識一個身份,但在比特幣中更多的使用地址來 標識身份,可以認爲地址是一個或一組公鑰的精簡表示,因此同樣可以 使用私鑰進行驗證:

使用getnewaddress調用可以生成並返回一個新的地址,例如:

~$ bitcoin-cli getnewaddress
2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S

使用validateaddress調用可以查看這個地址的相關信息,例如公鑰:

~$ bitcoin-cli validateaddress 2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S    
{
  "isvalid": true, 
  "address": "2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S", 
  ...
  "pubkey": "02c865c914ee88ac798e66e0623012286c1549c709a4f8efa994a1504f180574f5", 
    ...
}

使用dumpprivkey調用可以導出這個地址的私鑰:

~$ bitcoin-cli dumpprivkey 2NC6QeGFjxyBb1qqYq5wz3UyufQ4cMMVz7S    
cNvFMEshrc7oNaoPwFgygmpwzM7xt1DAtvD5xh5uogQZuoMk7S4v

dumpprivkey命令導出的私鑰是經過base58編碼的WIF格式(Wallet Import Format), 該格式主要用於私鑰的拷貝黏貼,並且很容易轉換回原始格式。

這樣看起來,是不是意味着 從地址可以推導出私鑰和公鑰?

希望上面的操作不要誤導了你,bitcoind只是在節點錢包裏保存了地址和 密鑰的對應關係而已,任何情況下你都無法從地址反向推導出公鑰,或者從 公鑰反向推導出私鑰。

#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo  "address => $addr"

pub=`bitcoin-cli validateaddress $addr | jq '.pubkey' | sed s/\"//g`
echo "public key => $pub"

prv=`bitcoin-cli dumpprivkey $addr`
echo "private key => $prv"

四、節點錢包

節點軟件bitcoind除了完整實現比特幣的核心協議,還包含了一個可選但是重要 的功能模塊 —— 錢包:

可以把錢包視爲保存着你所有密鑰與地址的保險箱,同時也封裝了比特幣很多 偏技術性的概念與細節,使其可以被極客之外的人羣所理解和接受。因此在默認 配置下,bitcoind會啓用節點錢包。如果你希望禁止錢包功能,例如你準備自己 管理密鑰與地址,那麼可以在配置文件中設置disablewallet選項:

disablewallet=1

錢包模塊會跟蹤其管理的所有地址相關的交易,因此可以及時地更新錢包的餘額信息。 這一功能非常重要,因爲比特幣中沒有賬戶的概念,比特幣是散落在一個個交易 中的電子現金,如果沒有錢包幫助跟蹤與我們地址相關的交易,那麼想算清楚自己 總共持有多少個比特幣都很困難。

節點提供的很多RPC調用都是由錢包模塊來實現的。例如,當我們調用getnewaddress 命令時,就是由錢包模塊來生成密鑰和地址並自動加入到錢包中, 因此其相關的交易也會自動地影響錢包的餘額。同樣,當我們調用getbalance時, 也是由錢包模塊來彙總所有地址上的比特幣並返回總金額。

五、挖礦:交易確認與激勵

我們知道,比特幣是通過挖礦這種機制來保證分佈式環境下的節點一致性, 只有通過挖礦,交易才能在衆多節點之間達成共識並最終打包到區塊中上鍊。

在另一方面,挖礦也是比特幣系統的造幣機制,所有的比特幣都是通過各個 節點的挖礦出塊產生的,並且支付給礦工作爲其付出的獎勵 —— 這一獎勵最初 是50個比特幣,並且每出21萬個區塊之後減半,直至最終減少到0。目前階段的挖礦 獎勵是每區塊12.5個比特幣。

節點挖礦獲得的獎勵並不會立刻生效,而必須等待更多的區塊生成之後纔可用。 這是因爲當比特幣網絡中出現分叉時,某些區塊會變成孤兒,而這些區塊包含的交易 將被重新打包入其他區塊,同時這些孤兒區塊的挖礦獎勵將被回收:

因此按照約定,挖塊獎勵得到的比特幣必須要等101個確認(Confirms)之後才能生效。

執行挖礦操作

在公鏈上我們沒什麼機會挖礦,不過在私鏈上,必須由自己挖礦,否則交易 沒有辦法確認。

使用generate調用來執行挖礦操作,例如下面的命令連續挖出101個區塊:

~$ bitcoin-cli generate 101

generate命令也是由錢包模塊實現的,它會創建一個新的錢包地址,然後將挖礦獎勵轉入 這個新地址。顯然在第N+100個塊挖出後,第N個塊的確認達到了101個,因此第N塊 的獎勵就生效了。現在看一下我們的錢包餘額:

~$ bitcoin-cli getbalance

你應該看到餘額有了變換。

六、比特幣轉賬交易

錢包有了餘額,我們就可以嘗試給其他地址轉比特幣了:

由於bitcoind內置了錢包模塊,轉賬交易變得非常簡單:只要調用sendtoaddress接口就可以向指定的地址發送比特幣了。

我們先使用getnewaddress調用來生成一個新地址以便測試:

~$ bitcoin-cli getnewaddress
2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5

然後使用sendtoaddress`命令就可以向這個新地址轉賬了。 例如,下面的代碼向我們新生成的地址轉入2.45個比特幣並返回交易id:

~$ bitcoin-cli sendtoaddress 2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5 2.45

現在我們挖礦確認這個交易,給它6次確認:

~$ bitcoin-cli generate 6

需要指出的是,由於getnewaddress生成的地址是自動添加到錢包中的, 因此該地址收到的比特幣依然計入到錢包的餘額中。

使用getreceivedbyaddress調用查看地址接收到的比特幣數量:

~$ bitcoin-cli getreivedbyaddress 2MzJkG1a4ZfWt3v3d3Rmkv57Z7UyLDHpep5 6
2.45000000
#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo "address => $addr"

txid=`bitcoin-cli sendtoaddress $addr 2.45`
echo "txid => $txid"

blks=`bitcoin-cli generate 6`
echo "mined 6 block"

received=`bitcoin-cli getreceivedbyaddress $addr 6`
echo "received  => $received"

七、理解交易的結構

交易(Transaction)是比特幣的核心,它不僅是比特幣流轉的記錄,而且 比特幣本身也隱含在交易當中。下圖表示了兩個交易之間比特幣的流轉過程:

通常一個交易總是包含輸入(vin)和輸出(vout)兩個部分,其中的輸入 用來引用其他交易的輸出。但用來記錄挖礦獎勵的幣基交易/coinbase transaction 是個例外:它只有輸出部分。例如,上圖中的交易1111是一個幣基交易,其 輸出部分記錄了挖礦獎勵的50個幣轉入了地址x。

交易2222則記錄了地址x的持有者向地址y轉40個幣的事實。在這個交易 的輸入部分,可以看到它引用了交易1111的第0個輸出,就是說,將把交易 1111的第0個輸出所表示的比特幣轉給地址y。

交易輸出在沒有被其他交易使用之前,被稱爲未消費交易輸出/Unspent Transaction Output, 簡稱爲UTXO。UTXO的一個重要特點是不可以拆分消費:要麼不使用它,要麼完全使用它。 這有點像現鈔:你不能把一張50元的鈔票撕成40元和10元。 因此,雖然只需要給地址y轉40個比特幣,但是交易1111中的這個面值50個幣的UTXO 會完全消耗掉,不再可用。

交易的輸入總額與輸出總額的差值,就是支付給礦工的交易費/Transaction Fee。 因此對於上面的交易我們還需要構造第二個交易輸出來處理多出來的10個比特幣,只把 其中一小部分支付交易費,剩下的使用x持有人控制的另一個地址z來回收 —— 就 像找零錢一樣,因此這個地址z通常被稱爲找零地址/change address。當然,也 可以將這部分比特幣轉給另一個外部地址。

當交易2222被確認後,交易1111的第0個輸出就被消耗掉了,不再可用;產生 的兩個新的UTXO,則分別屬於地址y和地址z,而這一事實,被記錄在 交易2222中寫入區塊鏈。

我們可以使用如下的命令來創建、確認一個轉賬交易:

~$ addr=`bitcoin-cli getnewaddress`
~$ txid=`bitcoin-cli sendtoaddress $addr 3.33`
~$ blks=`bitcoin-cli generate 6`

然後使用getrawtransaction調用來查看交易的詳情:

~$ bitcoin-cli getrawtransaction $txid true

當指定參數true時,返回的結果是解碼後的JSON格式的交易詳情,其 vin字段中包含本次交易使用的所有前序UTXO,這些UTXO在交易確認後就 不再是UTXO了:

在vout字段中則包含本次交易生成的新的UTXO:

#!/bin/bash

addr=`bitcoin-cli getnewaddress`
echo "address => $addr"

txid=`bitcoin-cli sendtoaddress $addr 3.33`
echo "txid => $txid"

blks=`bitcoin-cli generate 6`
echo "mined 6 blocks"

bitcoin-cli getrawtransaction $txid true

今天新書的CIP號也下來了,把書demo的代碼也剛發給了編輯,希望本週能下廠,坐等新書了,感興趣的小夥伴到時候可以支持一下。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章