Skip to content

Commit

Permalink
Merge pull request #9 from awesome-doge/master
Browse files Browse the repository at this point in the history
建立gitbook鏡像網站
  • Loading branch information
awesome-doge authored Aug 26, 2019
2 parents 5c1e992 + ff46d15 commit d1ddd25
Show file tree
Hide file tree
Showing 205 changed files with 39,826 additions and 162 deletions.
32 changes: 0 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,6 @@

本書主要面向開發人員,前兩章對比特幣的介紹也適用於非開發人員。任何對技術有基本瞭解的人都可以閱讀前兩章,以深入瞭解比特幣。

### 目錄

[前言](前言.asciidoc)

[術語](術語.asciidoc)

[第一章 概述](第一章.asciidoc)

[第二章 比特幣如何運作](第二章.asciidoc)

[第三章 Bitcoin Core參考實現](第三章.asciidoc)

[第四章 密鑰和地址](第四章.asciidoc)

[第五章 錢包](第五章.asciidoc)

[第六章 交易](第六章.asciidoc)

[第七章 高級交易和腳本](第七章.asciidoc)

[第八章 比特幣網路](第八章.asciidoc)

[第九章 區塊鏈](第九章.asciidoc)

[第十章 挖礦和共識](第十章.asciidoc)

[第十一章 比特幣安全](第十一章.asciidoc)

[第十二章 區塊鏈應用](第十二章.asciidoc)


[下一章:前言](前言.asciidoc)

## Mastering Bitcoin - Second Edition

Expand Down
16 changes: 16 additions & 0 deletions Summary.asciidoc
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 added _book/book.pdf
Binary file not shown.
47 changes: 47 additions & 0 deletions _book/code/addr.cpp
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;
}
58 changes: 58 additions & 0 deletions _book/code/ec-math.py
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)
18 changes: 18 additions & 0 deletions _book/code/hash_example.py
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)
46 changes: 46 additions & 0 deletions _book/code/key-to-address-ecc-example.py
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))
16 changes: 16 additions & 0 deletions _book/code/max_money.py
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")
59 changes: 59 additions & 0 deletions _book/code/merkle.cpp
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;
}
64 changes: 64 additions & 0 deletions _book/code/proof-of-work-example.py
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)
Loading

0 comments on commit d1ddd25

Please sign in to comment.