0%

Learn Blockchain by Building One_book study

来自Learn Blockchain by Building One的笔记

书本笔记

image-20210801195944516

chapter 1

主要就是讲工具安装(环境搭建)和一个小例子。

工具

安装python、poetry

poetry

poetry:管理python项目依赖关系

1
2
3
poetry new my-project	#用Poetry创建一个Python项目
poetry add requests #用Poetry添加python的依赖
poetry shell #Python解释器是不是在Poetry的virtualenv中

example

获得比特币价格

1
2
3
import requests
response = requests.get("https://api.coinbase.com/v2/prices/spot?currency=USD")
print(response.text)

image-20210731164527928

chapter 2

主要讲hash,题目是“A Way to Identify
Everything”,也就是用hash可以验证发送的数据是否被修改

hash

Example

1 Hashing in Python

文字的hash

1
2
3
4
5
6
import hashlib
# Hash functions expect bytes as input: the encode() method turns strings to bytes
input_bytes = b"backpack"
output = hashlib.sha256(input_bytes)
# We use hexdigest() to convert bytes to hex because it's easier to read
print(output.hexdigest())

image-20210731164818639

2 Hashing images

图片的hash

1
2
3
4
5
from hashlib import sha256
file = open("my_image.jpg", "rb")
hash = sha256(file.read()).hexdigest()
file.close()
print(f"The hash of my file is: {hash}")

image-20210731165008111

3 Sending untamperable emails

加了一部分密文,hash

1
2
3
4
5
6
7
from hashlib import sha256
secret_phrase = "bolognese"
def get_hash_with_secret_phrase(input_data, secret_phrase):
combined = input_data + secret_phrase
return sha256(combined.encode()).hexdigest()
email_body = "Hey Bob,I think you should learn about Blockchains! I've been investing in Bitcoin and currently have exactly 12.03 BTC in my account."
print(get_hash_with_secret_phrase(email_body, secret_phrase))

image-20210731165316295

chapter 3

实现区块链的链(修改后的,所以proof_of_work是chapter 4的

  • __init__:一开始创建初始块
  • new_block:创建块
  • hash:对块进行hash
  • last_block:取最后一个块
  • valid_block:判断是否是有效块(前4个是0
  • proof_of_work:一直生成块,知道有效块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#blockchain.py

import json
import random

from datetime import datetime
from hashlib import sha256


class Blockchain(object):
def __init__(self):
self.chain=[]
self.pending_transactions=[]

#Create the genesis block
print("Creating genesis block")
self.chain.append(self.new_block())

def new_block(self):
block={
'index':len(self.chain),
'timestamp':datetime.utcnow().isoformat(),
'transactions':self.pending_transactions,
'previous_hash':self.last_block["hash"] if self.last_block else None,
'nonce':format(random.getrandbits(64),"x"),
}


block_hash = self.hash(block)
block["hash"] = block_hash


self.pending_transactions=[]

return block

@staticmethod
def hash(block):

block_string = json.dumps(block,sort_keys=True).encode()
return sha256(block_string).hexdigest()

@property
def last_block(self):

return self.chain[-1] if self.chain else None

@staticmethod
def valid_block(block):

return block['hash'].startswith("0000")

def proof_of_work(self):
while True:
new_block = self.new_block()
if self.valid_block(new_block):
break

self.chain.append(new_block)
print("Found a new block: ",new_block)

image-20210731165711500

chapter 4

题目是工作量证明,

工具

ipython

  • 与Python解释器交互的一个很棒的工具

  • 使用制表符补全和语法高亮显示

工作量证明

挖矿:矿工通过找到一个哈希值小于给定值

example

1 easy
1
2
3
4
5
6
7
8
9
from hashlib import sha256

x = 5
y = 0

while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
y += 1

print(f'The solution is y = {y}')(funcoin-fVGYERd1-py3.8)

image-20210731170111573

2 应用到blockchain

代码同chapter3

image-20210731170314488

chapter 5

讲的网络,首先讲了异步,然后做了一个简单的聊天,类似于区块链中的通信情况。

异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import asyncio
import time


async def greet(name,delay):
await asyncio.sleep(delay)
print(f'{name}:I waited {delay} seconds before saying "hello"')


async def main():
task_1 = asyncio.create_task(greet("t1",3))
task_2 = asyncio.create_task(greet("t2",2))
task_3 = asyncio.create_task(greet("t3",2))

start_time = time.time()
print("0.00s: Program Start")

await task_1
await task_2
await task_3

print(f"{time.time() - start_time:.2f}s: Program End")

asyncio.run(main())

image-20210731171321116

简易聊天系统

构造一个通信,类似于区块链的通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import asyncio
from textwrap import dedent


class ConnectionPool:
def __init__(self):
self.connection_pool = set()

def send_welcome_message(self,writer):
message = dedent(f"""
===
Welcome {writer.nickname}!

There are {len(self.connection_pool) - 1} user(s) here beside you

Help:
- Type anything to chat
- /list will list all the connected users
- /quit will disconnect you
===
""")

writer.write(f"{message}/n".encode())

def broadcast(self,writer,message):
for user in self.connection_pool:
if user != writer:
# We don't need to also broadcast to the user sending the message
user.write(f"{message}/n".encode())

def broadcast_user_join(self,writer):
self.broadcast(writer,f"{writer.nickname} just joined")

def broadcast_user_quit(self,writer):
self.broadcast(writer,f"{writer.nickname} just quit")

def broadcast_new_message(self,writer,message):
self.broadcast(writer,f"[{writer.nickname}] {message}")

def list_users(self,writer):
message = "===/n"
message += "Currently connected users:"
for user in self.connection_pool:
if user == writer:
message += f"/n - {user.nickname} (you)"
else:
message += f"/n - {user.nickname}"

message += "/n==="
writer.write(f"{message}/n".encode())

def add_new_user_to_pool(self, writer):
self.connection_pool.add(writer)

def remove_user_from_pool(self,writer):
self.connection_pool.remove(writer)


async def handle_connection(reader,writer):
# Get a nickname for the new client
writer.write("> Choose your nickname: ".encode())

response = await reader.readuntil(b"/n")
writer.nickname = response.decode().strip()

connection_pool.add_new_user_to_pool(writer)
connection_pool.send_welcome_message(writer)

# Announce the arrival of this new user
connection_pool.broadcast_user_join(writer)

while True:
try:
data = await reader.readuntil(b"/n")
except asyncio.exceptions.IncompleteReadError:
connection_pool.broadcast_user_quit(writer)
break

message = data.decode().strip()
if message == "/quit":
connection_pool.broadcast_user_quit(writer)
break
elif message == "/list":
connection_pool.list_users(writer)
else:
connection_pool.broadcast_new_message(writer,message)

await writer.drain()

if writer.is_closing():
break

# We're new outside the message loop, and the user has quit.Let's clean up...
writer.close()
await writer.wait_closed()
connection_pool.remove_user_from_pool(writer)

async def main():
server = await asyncio.start_server(handle_connection,"0.0.0.0",8888)

async with server:
await server.serve_forever()


connection_pool = ConnectionPool()
asyncio.run(main())

image-20210731171000653

image-20210731171014807

image-20210731171025014

image-20210731171036384

chapter 6

加密

example

1 验证数据完整

发送的时候,把原文和sha256加密的东西一起发送过去

验证的时候,对数据sha256,对比值是否相等

alice发生数据给bob

1
2
3
4
from hashlib import sha256
message = "Hello Bob, Let's meet at the Kruger National Park on 2020-12-12 at 1pm."
hash_message = sha256(("p@55w0rd" + message).encode()).hexdigest()
print(hash_message)

bob验证数据未被修改

1
2
3
4
5
6
from hashlib import sha256
alices_message = "Hello Bob, Let's meet at the Kruger National Park on 2020-12-12 at 1pm."
alices_hash = "39aae6ffdb3c0ac1c1cc0f50bf08871a729052cf1133c4c9b44a5bab8fb66211"
hash_message = sha256(("p@55w0rd" + alices_message).encode()).hexdigest()
if hash_message == alices_hash:
print("Message has not been tampered with")

image-20210731171637680

2 加密传送数据

发送数据:

  • 公钥发送
  • 私钥对数据签名

接收

verify验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import nacl.encoding
import nacl.signing

#Generate a new key-pair for Bob
bobs_private_key = nacl.signing.SigningKey.generate()
bobs_public_key = bobs_private_key.verify_key
print(bobs_public_key)

#Since it's bytes,we'll need to serialize the key to a readable format before publishing it:
bobs_public_key_hex = bobs_public_key.encode(encoder=nacl.encoding.HexEncoder)
print("/n/n")
print(bobs_public_key_hex)
#Now,Let's sign a message with it
signed = bobs_private_key.sign(b"Send $37 to Alice")
print("/n/n")
print(signed)

image-20210731171918053

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import nacl.encoding
import nacl.signing


# From the above example...
bobs_public_key = 'acc5cc1750b841f0b383e5f620282946476c37d602c42b9dbaccb9db758b728e'

# We generate the verify_key
verify_key = nacl.signing.VerifyKey(bobs_public_key,encoder=nacl.encoding.HexEncoder)

signed_message = b"/x8b/x08/x93/xb0/xda!r)/x19i/x18d/xe0/xbbi/x8a@c/xf8-/x8e/xbdr/xb7/xe8%/x0eez/x99/xd2/x0c/xc8/x14_/x8d/x02zWV/x8e/x81/xfb[9/x9b/x9d/x1b/xbb/xda/xe7/x05/x945/xc2/xef~/x17/x90/xfd3'/xc3/x00Send $37 to Alice"

# Now we attempt to verify the message
# Any invalidation will result in an Exception being thrown
verify_key.verify(signed_message)

image-20210731172022526

如果修改bobs_public_key/signed_message为错误的,则

image-20210731172057501

chapter 7

整合

image-20210731172254999

实践

0 完整代码

链接:https://github.com/dvf/blockchain

image-20210807173529463

1 工具安装

安装python(版本3.8)和poetry

1
2
3
4
5
6
7
8
9
10
11
12
$ sudo apt-get update
$ sudo apt-get install python3.8
#ln -s 把python3和python3.8链接

$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

#安装依赖
poetry add pynacl structlog colorama marshmallow marshmallow-oneofschema aiohttp

pip install pipenv
pipenv install
pip install Flask==0.12.2 requests==2.18.4

1启动节点

代码下载后放到服务器上,启动节点

1
2
3
$ pipenv run python blockchain.py			#默认启动端口5000,启动5000端口的节点
$ pipenv run python blockchain.py -p 5001
$ pipenv run python blockchain.py --port 5002

image-20210807171341824

2 使用

访问

访问区块链

1
2
#ip:port/chain 可以访问区块链
http://156.233.254.97:5002/chain

image-20210807171442690

挖矿

1
2
#ip:port/mine
http://156.233.254.97:5002/mine

image-20210807171527803

image-20210807171542372

创建交易

1
2
3
4
5
6
7
8
9
10
11
curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 1234
}' "http://156.233.254.97:5004/transactions/new"

curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 7979
}' "http://156.233.254.97:5002/transactions/new"

image-20210807171921098

image-20210807172056677

共识机制

5002端口里面有三个块

5003端口开一个,只有一个初始块

image-20210807172258623

将2注册到3上,让5003知道有5002这个节点

1
2
3
4
5
6
7
curl -X POST -H "Content-Type: application/json" -d '{
"nodes":["156.233.254.97:5002"]
}' "http://156.233.254.97:5003/nodes/register"

curl -X POST -H "Content-Type: application/json" -d '{
"nodes":["156.233.254.97:5004"]
}' "http://156.233.254.97:5005/nodes/register"

image-20210807172505247

通过共识,5003更新节点跟5002一样

image-20210807172558767

image-20210807172613733

Q:如果阅读本文需要付费,你是否愿意为此支付1元?