終於寫完10天了,今天把昨天誘因的手續費部份補上,第10天放鬆一下。
光有挖礦的獎勵只能說給了節點產生新區塊的誘因,節點還必須有把交易放入區塊的誘因才行,所以該區塊的產生者也能跟每筆交易收到手續費啦。我這兩天看了看比特幣目前的手續費實作方式挺複雜的,最後決定給報明牌達成一個共識,每筆交易都收一塊錢。這邊要注意到當前的區塊計算POW(proof of work)的難度只跟過去的區塊有關,一般實務上驗證交易合法的計算量與挖礦相比大概是舉手之勞,既然有手續費對節點來說那就是能塞交易盡量塞啦。
修改區塊運作,每筆交易都拿一塊錢當手續費,塞進挖礦獎勵的區塊:
# 為了在收手續費的同時保持交易紀錄正確
# 交易的data欄位改成in,out
# 在這裡的實作中 共識下交易方的in應比out小1
# 這個1當手續費塞進挖礦獎勵
# 確定發起交易者也同意共識
# 而不是節點自己來改
transaction = {
'owner_vk': now_vk,
'preowner_vk': pre_tran['owner_vk'],
'vin': vin,
'vout': vout,
'signature': ecdsa.SigningKey.from_pem(pre_sk).sign(str(pre_tran)+now_vk)
}
# 目前先一收到交易就計算區塊
def recv_tran( self , peerconn, msgdata):
block = self.create_block()
fee_tran = json.loads(msgdata)
if fee_tran['vout'] >= 0 and fee_tran['vin'] == fee_tran['vout']+1:
block['Txs'][0]['vin'] += 1
block['Txs'].append(json.loads(msgdata))
else:
print("請附手續費!")
return
print('挖礦賺錢囉!')
self.proof_of_work(block)
檢查一下有沒有給手續費:
def create_block(self):
...
check_legel = True
# 第j的區塊的第k個transaction
for j in range(len(self.blockchain)):
for k in range(len(self.blockchain[j]['Txs'])):
for l in range(len(new_block['Txs'])):
# 第一筆交易是挖礦獎勵 可以沒有支付者
if l == 0:
# 確認獎勵跟手續費合不合
if new_block['Txs'][0]['vin'] != 99+len(new_block['Txs']):
check_legel = False
continue
if self.blockchain[j]['Txs'][k]['preowner_vk'].decode('utf-8') == new_block['Txs'][l]['preowner_vk'].decode('utf-8'):
check_legel = False
...
要在多很多check步驟才算安全,概念驗證概念驗證。
實際運行:
node = BTPeer(0, 4445)
node.addpeer(1, 'xxx.xxx.xxx.xxx', 4444)
node.addpeer(2, 'xxx.xxx.xxx.xxx', 4445)
node.addpeer(3, 'xxx.xxx.xxx.xxx', 4446)
block = node.create_block()
block_pow = node.proof_of_work(block)
node.recv_block(None, json.dumps(block_pow, encoding='latin1'))
'''
# 先挖一次沒交易的礦
請把您的私鑰收好,挖到礦就有錢了: -----BEGIN EC PRIVATE KEY-----
.....
-----END EC PRIVATE KEY-----
xxx.xxx.xxx.xxx:4445 計算合法區塊成功
node xxx.xxx.xxx.xxx:4445:紀錄了新block中的所有交易
'''
sk = ''
while True:
temp = raw_input("input sk: ")
sk += temp
if temp == '-----END EC PRIVATE KEY-----':
break
else:
sk += '\n'
ecdsa.SigningKey.from_pem(sk)
node.trade_broadcast(node.blockchain[-1]['Txs'][0], 100, 99, sk, 'ggg')
'''
# 然後發起交易
input sk: -----BEGIN EC PRIVATE KEY-----
input sk: ...
input sk: ...
input sk: ...
input sk: -----END EC PRIVATE KEY-----
'''
node = BTPeer(0, 4444)
node.addpeer(1, 'xxx.xxx.xxx.xxx', 4444)
node.addpeer(2, 'xxx.xxx.xxx.xxx', 4445)
node.addpeer(3, 'xxx.xxx.xxx.xxx', 4446)
node.mainloop()
'''
# 收到4445 port的區塊
node xxx.xxx.xxx.xxx:4444:紀錄了新block中的所有交易
請把您的私鑰收好,挖到礦就有錢了: -----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----
# 幫4445 port處理交易
挖礦賺錢囉!
xxx.xxx.xxx.xxx:4444 計算合法區塊成功
node xxx.xxx.xxx.xxx:4444:紀錄了新block中的所有交易
'''
在github放有完整的範例程式提供,可以直接執行參考,可以把debug設成1以方便理解流程。
實際的比特幣運作是根據上一次的全網算力調整下一個區塊的難度,以此來控制區塊產生的時間,一個區塊能塞的數據大小也有一個限制,所以目前在比特幣中交易量大時等候的時間可能會遠遠大過前面所提的大約一小時,這在其他很多應用裡面已經有所改善,之後有機會會提到,但比特幣因為目前來說價值過於龐大,要進行改動都會牽涉到多方利益,一些技術改善的進展反而很慢。
《Bitcoin: A Peer-to-Peer Electronic Cash System》
https://bitcoin.org/bitcoin.pdf