区块链入门


【序号、时间戳、hash值】+【交易记录】

非对称加密

对称加密也叫做单密钥加密,指的是用同一个密钥对信息进行加密和解密。简单讲就是上锁和开锁都是一把钥匙。一个问题是密钥配送困难问题。

非对称加密有一对密钥,分别是私钥和公钥,公钥和私钥一一对应,私钥需要保密,而公钥则是可以公开的。加密和解密不是用同一个密钥。

回到之前的例子,你朋友去配了一对钥匙(钥匙A和钥匙B),钥匙A上锁柜子之后,必须要钥匙B才能开锁柜子。你朋友把钥匙A邮寄给你,你用这把钥匙把信件锁到柜子中,然后将柜子邮寄给你朋友,你朋友用钥匙B打开柜子取出信件。细心的小伙伴又想到了,朋友把钥匙A寄给自己的时候,可能会被快递人员偷配钥匙,但是快递人员即使持有钥匙A,他也不能打开柜子,因为钥匙A上锁柜子之后,只有钥匙B才能开锁,整个过程,钥匙B一直在朋友手上,只要朋友不把钥匙B弄丢,这个柜子就只能由朋友打开。

比特币公钥就是通过私钥推导而来,公钥继续转换变成账户地址,而且是不能反向推导出私钥的**,私钥和公钥是一对,用户需要妥善保管好自己的私钥,而公钥和账户地址都是可以公开的。

还有一种情况是私钥加密,公钥解密。典型的应用场景就是数字签名,A采用自己的私钥加密文件信息后发送给B,并将公钥也发送给B,B利用这个公钥对信息解密,如果C和D也有这个公钥,那C和D也可以解密这个文件信息,但是只有持有私钥的A才能加密这个信息,因此可以确保这个文件信息确确实实是由A发出的,这就比较适用于一些公司老总做电子签名,以确保签名是老总签的。在区块链中,你的收款地址就相当于公钥,人人可以看到,但是如果你要转移你的资产给朋友,你需要输入密码(私钥)进行数字签名,来表示这个资产确确实实是由你发出的。

搭建一个区块链框架

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, jsonify, request


class Blockchain:
def __init__(self):
self.current_transactions = []
self.chain = []
# 很多个节点
self.nodes = set()

# 创建创世块
self.new_block(previous_hash='1', proof=100)

def register_node(self, address: str) -> None:
"""
Add a new node to the list of nodes
:param address: Address of node. Eg. 'http://192.168.0.5:5000'
"""
parsed_url = urlparse(address)
self.nodes.add(parsed_url.netloc) # 不要存http 协议这部分

# 判断链条是否有效
def valid_chain(self, chain: List[Dict[str, Any]]) -> bool:
"""
Determine if a given blockchain is valid

:param chain: A blockchain
:return: True if valid, False if not
"""

last_block = chain[0]
current_index = 1

while current_index < len(chain):
block = chain[current_index]
print(f'{last_block}')
print(f'{block}')
print("\n-----------\n")
# Check that the hash of the block is correct
if block['previous_hash'] != self.hash(last_block):
return False

# Check that the Proof of Work is correct
if not self.valid_proof(last_block['proof'], block['proof']):
return False

last_block = block
current_index += 1

return True

def resolve_conflicts(self) -> bool:
"""
共识算法解决冲突
使用网络中最长的链.

:return: 如果链被取代返回 True, 否则为False
"""

neighbours = self.nodes
new_chain = None

# We're only looking for chains longer than ours
max_length = len(self.chain)

# Grab and verify the chains from all the nodes in our network
for node in neighbours:
response = requests.get(f'http://{node}/chain')

if response.status_code == 200:
length = response.json()['length']
chain = response.json()['chain']

# Check if the length is longer and the chain is valid
if length > max_length and self.valid_chain(chain):
max_length = length
new_chain = chain

# Replace our chain if we discovered a new, valid chain longer than ours
if new_chain:
self.chain = new_chain
return True

return False

# -> 是返回值
def new_block(self, proof: int, previous_hash: Optional[str]) -> Dict[str, Any]:
"""
生成新块

:param proof: The proof given by the Proof of Work algorithm
:param previous_hash: Hash of previous Block
:return: New Block
"""

block = {
'index': len(self.chain) + 1, # chain是一个数组
'timestamp': time(),
'transactions': self.current_transactions, # 一个数组
'proof': proof, # 工作量证明
'previous_hash': previous_hash or self.hash(self.chain[-1]),#上一个区块hash值
}

# Reset the current list of transactions
self.current_transactions = []

self.chain.append(block)
return block

def new_transaction(self, sender: str, recipient: str, amount: int) -> int:
"""
生成新交易信息,信息将加入到下一个待挖的区块中

:param sender: Address of the Sender
:param recipient: Address of the Recipient
:param amount: Amount
:return: The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})

return self.last_block['index'] + 1

@property
def last_block(self) -> Dict[str, Any]:
return self.chain[-1]

@staticmethod
def hash(block: Dict[str, Any]) -> str:
"""
生成块的 SHA-256 hash值

:param block: Block
"""

# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode() # json转字符串,转字节数组
return hashlib.sha256(block_string).hexdigest() # hash后的摘要信息

def proof_of_work(self, last_proof: int) -> int:
"""
简单的工作量证明:
- 查找一个 p' 使得 hash(pp') 以4个0开头
- p 是上一个块的证明, p' 是当前的证明
"""

proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1

return proof

@staticmethod
def valid_proof(last_proof: int, proof: int) -> bool:
"""
验证证明: 是否hash(last_proof, proof)以4个0开头

:param last_proof: Previous Proof
:param proof: Current Proof
:return: True if correct, False if not.
"""

guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"


# Instantiate the Node
app = Flask(__name__)

# Generate a globally unique address for this node
node_identifier = str(uuid4()).replace('-', '')

# Instantiate the Blockchain
blockchain = Blockchain()

# 这些是Flask的路由
# 挖矿
@app.route('/mine', methods=['GET'])
def mine():
# We run the proof of work algorithm to get the next proof...
last_block = blockchain.last_block
last_proof = last_block['proof'] # 上一个块的工作量证明
proof = blockchain.proof_of_work(last_proof)

# 给工作量证明的节点提供奖励.
# 发送者为 "0" 表明是新挖出的币
blockchain.new_transaction(
sender="0",
recipient=node_identifier,
amount=1,
)

# Forge the new Block by adding it to the chain
block = blockchain.new_block(proof, None)

response = {
'message': "New Block Forged",
'index': block['index'],
'transactions': block['transactions'],
'proof': block['proof'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200


@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()

# 检查POST数据,, 取出三个字段
required = ['sender', 'recipient', 'amount']
if not all(k in values for k in required):
return 'Missing values', 400

# Create a new Transaction
index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])

response = {'message': f'Transaction will be added to Block {index}'}
return jsonify(response), 201


@app.route('/chain', methods=['GET'])
def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}
return jsonify(response), 200 # json转字符串


@app.route('/nodes/register', methods=['POST'])
def register_nodes():
values = request.get_json()
nodes = values.get('nodes')
if nodes is None:
return "Error: Please supply a valid list of nodes", 400

for node in nodes:
blockchain.register_node(node)

response = {
'message': 'New nodes have been added',
'total_nodes': list(blockchain.nodes),
}
return jsonify(response), 201


@app.route('/nodes/resolve', methods=['GET'])
def consensus():
replaced = blockchain.resolve_conflicts()

if replaced:
response = {
'message': 'Our chain was replaced',
'new_chain': blockchain.chain
}
else:
response = {
'message': 'Our chain is authoritative',
'chain': blockchain.chain
}

return jsonify(response), 200


if __name__ == '__main__':
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port

app.run(host='127.0.0.1', port=port)