forked from inoutcode/bitcoin_book_2nd
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from awesome-doge/master
建立gitbook鏡像網站
- Loading branch information
Showing
205 changed files
with
39,826 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
= 精通比特幣 | ||
|
||
. link:前言.asciidoc[前言] | ||
. link:術語.asciidoc[術語] | ||
. link:第一章.asciidoc[第一章 概述] | ||
. link:第二章.asciidoc[第二章 比特幣如何運作] | ||
. link:第三章.asciidoc[第三章 Bitcoin Core參考實現] | ||
. link:第四章.asciidoc[第四章 密鑰和地址] | ||
. link:第五章.asciidoc[第五章 錢包] | ||
. link:第六章.asciidoc[第六章 交易] | ||
. link:第七章.asciidoc[第七章 高級交易和腳本] | ||
. link:第八章.asciidoc[第八章 比特幣網路] | ||
. link:第九章.asciidoc[第九章 區塊鏈] | ||
. link:第十章.asciidoc[第十章 挖礦和共識] | ||
. link:第十一章.asciidoc[第十一章 比特幣安全] | ||
. link:第十二章.asciidoc[第十二章 區塊鏈應用] |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include <bitcoin/bitcoin.hpp> | ||
|
||
int main() | ||
{ | ||
// base16格式的私钥 | ||
bc::ec_secret decoded; | ||
bc::decode_base16(decoded, | ||
"038109007313a5807b2eccc082c8c3fbb988a973cacf1a7df9ce725c31b14776"); | ||
|
||
bc::wallet::ec_private secret( | ||
decoded, bc::wallet::ec_private::mainnet_p2kh); | ||
|
||
// 生成公钥 | ||
bc::wallet::ec_public public_key(secret); | ||
std::cout << "Public key: " << public_key.encoded() << std::endl; | ||
|
||
// 生成比特币地址 | ||
// 一般可以使用: | ||
// bc::wallet::payment_address payaddr = | ||
// public_key.to_payment_address( | ||
// bc::wallet::ec_public::mainnet_p2kh); | ||
// const std::string address = payaddr.encoded(); | ||
|
||
// 计算用于P2PKH地址的公钥雜湊值 . | ||
bc::data_chunk public_key_data; | ||
public_key.to_data(public_key_data); | ||
const auto hash = bc::bitcoin_short_hash(public_key_data); | ||
|
||
bc::data_chunk unencoded_address; | ||
// 预留25字节空间 | ||
// [ version:1 ] | ||
// [ hash:20 ] | ||
// [ checksum:4 ] | ||
unencoded_address.reserve(25); | ||
// 版本号字节, 0 代表普通的 BTC 地址 (P2PKH). | ||
unencoded_address.push_back(0); | ||
// 雜湊值 | ||
bc::extend_data(unencoded_address, hash); | ||
// 计算雜湊值的校验和并放入前4个字节 | ||
bc::append_checksum(unencoded_address); | ||
// 最后使用base58编码 | ||
assert(unencoded_address.size() == 25); | ||
const std::string address = bc::encode_base58(unencoded_address); | ||
|
||
std::cout << "Address: " << address << std::endl; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import ecdsa | ||
import os | ||
|
||
# secp256k1, http://www.oid-info.com/get/1.3.132.0.10 | ||
_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F | ||
_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 | ||
_b = 0x0000000000000000000000000000000000000000000000000000000000000007 | ||
_a = 0x0000000000000000000000000000000000000000000000000000000000000000 | ||
_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 | ||
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 | ||
curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p, _a, _b) | ||
generator_secp256k1 = ecdsa.ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r) | ||
oid_secp256k1 = (1, 3, 132, 0, 10) | ||
SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, | ||
generator_secp256k1, oid_secp256k1) | ||
ec_order = _r | ||
|
||
curve = curve_secp256k1 | ||
generator = generator_secp256k1 | ||
|
||
|
||
def random_secret(): | ||
convert_to_int = lambda array: int("".join(array).encode("hex"), 16) | ||
|
||
# 从OS的密码学安全的随机数发生器中收集256位随机数据 | ||
byte_array = os.urandom(32) | ||
|
||
return convert_to_int(byte_array) | ||
|
||
|
||
def get_point_pubkey(point): | ||
if (point.y() % 2) == 1: | ||
key = '03' + '%064x' % point.x() | ||
else: | ||
key = '02' + '%064x' % point.x() | ||
return key.decode('hex') | ||
|
||
|
||
def get_point_pubkey_uncompressed(point): | ||
key = ('04' + | ||
'%064x' % point.x() + | ||
'%064x' % point.y()) | ||
return key.decode('hex') | ||
|
||
|
||
# 生成私钥 | ||
secret = random_secret() | ||
print("Secret: ", secret) | ||
|
||
# 生成公钥 | ||
point = secret * generator | ||
print("EC point:", point) | ||
|
||
print("BTC public key:", get_point_pubkey(point).encode("hex")) | ||
|
||
# 给定点(x,y),我们可以使用以下方法创建对象 | ||
point1 = ecdsa.ellipticcurve.Point(curve, point.x(), point.y(), ec_order) | ||
assert(point1 == point) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# 在雜湊演算法的输入中迭代nonce的例子。 | ||
|
||
from __future__ import print_function | ||
import hashlib | ||
|
||
text = "I am Satoshi Nakamoto" | ||
|
||
# 从0到19迭代nonce | ||
for nonce in range(20): | ||
|
||
# 将nonce添加到文本的末尾 | ||
input_data = text + str(nonce) | ||
|
||
# 计算输入的SHA-256雜湊(文本+nonce) | ||
hash_data = hashlib.sha256(input_data).hexdigest() | ||
|
||
# 显示输入和雜湊结果 | ||
print(input_data, '=>', hash_data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from __future__ import print_function | ||
import bitcoin | ||
|
||
# 随机生成一个私钥 | ||
valid_private_key = False | ||
while not valid_private_key: | ||
private_key = bitcoin.random_key() | ||
decoded_private_key = bitcoin.decode_privkey(private_key, 'hex') | ||
valid_private_key = 0 < decoded_private_key < bitcoin.N | ||
|
||
print("Private Key (hex) is: ", private_key) | ||
print("Private Key (decimal) is: ", decoded_private_key) | ||
|
||
# 将私钥转换为WIF格式 | ||
wif_encoded_private_key = bitcoin.encode_privkey(decoded_private_key, 'wif') | ||
print("Private Key (WIF) is: ", wif_encoded_private_key) | ||
|
||
# 添加"01"后缀,表示压缩的私钥 | ||
compressed_private_key = private_key + '01' | ||
print("Private Key Compressed (hex) is: ", compressed_private_key) | ||
|
||
# 生成 WIF-compressed | ||
wif_compressed_private_key = bitcoin.encode_privkey( | ||
bitcoin.decode_privkey(compressed_private_key, 'hex'), 'wif_compressed') | ||
print("Private Key (WIF-Compressed) is: ", wif_compressed_private_key) | ||
|
||
# 乘以EC生成点G,生成公钥 | ||
public_key = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) | ||
print("Public Key (x,y) coordinates is:", public_key) | ||
|
||
# 编码成十六进制,以04开头 | ||
hex_encoded_public_key = bitcoin.encode_pubkey(public_key, 'hex') | ||
print("Public Key (hex) is:", hex_encoded_public_key) | ||
|
||
# 压缩公钥,根据y是偶数还是奇数来调整前缀 | ||
(public_key_x, public_key_y) = public_key | ||
compressed_prefix = '02' if (public_key_y % 2) == 0 else '03' | ||
hex_compressed_public_key = compressed_prefix + (bitcoin.encode(public_key_x, 16).zfill(64)) | ||
print("Compressed Public Key (hex) is:", hex_compressed_public_key) | ||
|
||
# 从公钥生成比特币地址 | ||
print("Bitcoin Address (b58check) is:", bitcoin.pubkey_to_address(public_key)) | ||
|
||
# 从压缩的公钥生成压缩的比特币地址 | ||
print("Compressed Bitcoin Address (b58check) is:", | ||
bitcoin.pubkey_to_address(hex_compressed_public_key)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# 最初的区块挖掘奖励是50比特币 | ||
start_block_reward = 50 | ||
# 平均每10分钟挖掘一块,每4年挖掘 210000 块 | ||
reward_interval = 210000 | ||
|
||
|
||
def max_money(): | ||
# 50 BTC = 50 0000 0000 Satoshis | ||
current_reward = 50 * 10**8 | ||
total = 0 | ||
while current_reward > 0: | ||
total += reward_interval * current_reward | ||
current_reward /= 2 | ||
return total | ||
|
||
print("Total BTC to ever be created:", max_money(), "Satoshis") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
#include <bitcoin/bitcoin.hpp> | ||
|
||
bc::hash_digest create_merkle(bc::hash_list& merkle) | ||
{ | ||
if (merkle.empty()) | ||
return bc::null_hash; | ||
else if (merkle.size() == 1) | ||
return merkle[0]; | ||
|
||
// 只要有多于1个雜湊,循环继续 | ||
while (merkle.size() > 1) | ||
{ | ||
// 如果雜湊值数量为奇数,复制列表中最后一个雜湊值 | ||
if (merkle.size() % 2 != 0) | ||
merkle.push_back(merkle.back()); | ||
// 列表大小为偶数 | ||
assert(merkle.size() % 2 == 0); | ||
|
||
// 新的雜湊值列表 | ||
bc::hash_list new_merkle; | ||
// 每次计算两个 | ||
for (auto it = merkle.begin(); it != merkle.end(); it += 2) | ||
{ | ||
// 连接两个雜湊值 | ||
bc::data_chunk concat_data(bc::hash_size * 2); | ||
auto concat = bc::serializer< | ||
decltype(concat_data.begin())>(concat_data.begin()); | ||
concat.write_hash(*it); | ||
concat.write_hash(*(it + 1)); | ||
// 雜湊 | ||
bc::hash_digest new_root = bc::bitcoin_hash(concat_data); | ||
// 将雜湊值添加到列表 | ||
new_merkle.push_back(new_root); | ||
} | ||
// 替换为新的列表 | ||
merkle = new_merkle; | ||
|
||
// 调试 输出 ------------------------------------- | ||
std::cout << "Current merkle hash list:" << std::endl; | ||
for (const auto& hash: merkle) | ||
std::cout << " " << bc::encode_base16(hash) << std::endl; | ||
std::cout << std::endl; | ||
// -------------------------------------------------- | ||
} | ||
// 最终以一个雜湊值结束,即 merkle root | ||
return merkle[0]; | ||
} | ||
|
||
int main() | ||
{ | ||
bc::hash_list tx_hashes{{ | ||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000000"), | ||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000011"), | ||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000022"), | ||
}}; | ||
const bc::hash_digest merkle_root = create_merkle(tx_hashes); | ||
std::cout << "Result: " << bc::encode_base16(merkle_root) << std::endl; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#!/usr/bin/env python | ||
# Proof-of-Work 演算法示例 | ||
|
||
import hashlib | ||
import time | ||
|
||
try: | ||
long # Python 2 | ||
xrange | ||
except NameError: | ||
long = int # Python 3 | ||
xrange = range | ||
|
||
max_nonce = 2 ** 32 # 40亿 | ||
|
||
|
||
def proof_of_work(header, difficulty_bits): | ||
# 计算难度目标 | ||
target = 2 ** (256 - difficulty_bits) | ||
|
||
for nonce in xrange(max_nonce): | ||
hash_result = hashlib.sha256(str(header) + str(nonce)).hexdigest() | ||
|
||
# 检查是否是目标值以下的有效结果 | ||
if long(hash_result, 16) < target: | ||
print("Success with nonce %d" % nonce) | ||
print("Hash is %s" % hash_result) | ||
return (hash_result, nonce) | ||
|
||
print("Failed after %d (max_nonce) tries" % nonce) | ||
return nonce | ||
|
||
|
||
if __name__ == '__main__': | ||
nonce = 0 | ||
hash_result = '' | ||
|
||
# 难度从0到31位 | ||
for difficulty_bits in xrange(32): | ||
difficulty = 2 ** difficulty_bits | ||
print("Difficulty: %ld (%d bits)" % (difficulty, difficulty_bits)) | ||
print("Starting search...") | ||
|
||
# 当前时间 | ||
start_time = time.time() | ||
|
||
# 创建一个包含前一个块的雜湊的新块 | ||
# 我们伪造一个交易块 —— 只是一个字串。 | ||
new_block = 'test block with transactions' + hash_result | ||
|
||
# 为新块找到一个有效的nonce | ||
(hash_result, nonce) = proof_of_work(new_block, difficulty_bits) | ||
|
||
# 记录需要多长时间才能找到结果 | ||
end_time = time.time() | ||
|
||
elapsed_time = end_time - start_time | ||
print("Elapsed Time: %.4f seconds" % elapsed_time) | ||
|
||
if elapsed_time > 0: | ||
|
||
# 估计每秒的雜湊计算次数 | ||
hash_power = float(long(nonce) / elapsed_time) | ||
print("Hashing Power: %ld hashes per second" % hash_power) |
Oops, something went wrong.