- S; j4 @+ E# Z, J1 @- } q8 w/ P
- <div>from hashlib import sha256
- from datetime import datetime$ q. h8 r4 P3 n! i6 x( h
- def generate_block(oldblock, bpm, address):8 R# n1 \6 q: a
- """
- :param oldblock:1 p" }5 N5 T! }8 U- S' `1 d+ d- O
- :param bpm:$ r; _6 p& j8 o n" }5 v+ c
- :param address:3 W( A- t% S8 d3 i
- :return:0 c& U) n% c" R% m) a( k# W4 g5 R
- """
- newblock = {
- "Index": oldblock["Index"] + 1,* H' s' [1 h/ @4 S4 A
- "BPM": bpm, m" q; m# ?% X
- "Timestamp": str(datetime.now()),
- "PrevHash": oldblock["Hash"], j8 k9 d1 A; S* Q$ N
- "Validator": address5 P# ~! t! e/ Q# f9 @/ o
- }) b* W/ ~& j0 e" o6 U. y6 o
- newblock["Hash"] = calculate_hash(newblock)" d" a; x7 O o+ G& |+ [, a
- return newblock. _5 d7 U" O9 f9 j8 }
- def calculate_hash(block):. g" B9 V6 n1 w0 n7 H; \5 _ e; {
- record = "".join([
- str(block["Index"]),
- str(block["BPM"]),, e% x0 j8 \6 M
- block["Timestamp"],
- block["PrevHash"]
- ])& S% x; L* p4 c! o1 r
- return sha256(record.encode()).hexdigest()0 x! I# E. v' y8 P+ L
- def is_block_valid(newblock, oldblock):
- """$ ~" l1 j- g7 T' l) e6 g! W
- :param newblock:% Y( s7 K( i" R/ A+ a
- :param oldblock:7 k& f' M4 H; m3 r+ B! v/ Z" D& Z5 d
- :return:
- """
- if oldblock["Index"] + 1 != newblock["Index"]:
- return False5 c L- @' w* V8 ]6 [& [8 Z& S
- if oldblock["Hash"] != newblock["PrevHash"]:
- return False
- if calculate_hash(newblock) != newblock["Hash"]:8 A( l0 m. E2 c+ Q) N8 ?) B- _
- return False2 l4 v: a3 c/ ~/ {+ s& n: W, z3 _
- return True</div>
- A$ y0 ^! w' ~# [
- <div>from socketserver import BaseRequestHandler, ThreadingTCPServer
- def run():
- # start a tcp server1 K9 R7 H) b% P6 l4 [ Y9 K' ]
- serv = ThreadingTCPServer(('', 9090), HandleConn): |4 Q" W9 ]7 l! a$ p
- serv.serve_forever()</div>
- ! h7 _( C) c( M7 w
- <div>import threading
- from queue import Queue, Empty
- # 定义变量, A8 U) e! X9 f2 W1 P
- block_chain = []$ s* B4 p7 l+ b1 a
- temp_blocks = []
- candidate_blocks = Queue() # 创建队列,用于线程间通信# L3 n1 t) T# `
- announcements = Queue(). M' s% F7 k; {( T) s
- validators = {}% a& Z- E- F4 e$ M& ?" g
- My_Lock = threading.Lock(). }( E- U, g! T* L9 l" t7 v( A" r/ s
- class HandleConn(BaseRequestHandler):. Z$ O& h* [4 ?/ [
- def handle(self):
- print("Got connection from", self.client_address)
- # validator address
- self.request.send(b"Enter token balance:"): _2 {; |5 L- q. a; L! @
- balance = self.request.recv(8192)3 r: Q( x0 u" X
- try:9 r3 \6 o" F7 |! K2 v' P9 u& Z* v6 d
- balance = int(balance)
- except Exception as e:
- print(e)
- t = str(datetime.now())
- address = sha256(t.encode()).hexdigest()
- validators[address] = balance
- print(validators)0 o- G9 R- Y3 x+ J$ v
- while True:
- announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),! N' [" g: d+ q7 o+ w. g
- daemon=True)
- announce_winner_t.start()
- self.request.send(b"\nEnter a new BPM:")6 W* k0 `8 s; l: Z- h+ u
- bpm = self.request.recv(8192)* K/ @( t. D# S% L& s" ]
- try:7 G4 O; {! _& U8 q8 j# C4 T4 j
- bpm = int(bpm)
- except Exception as e:% O# ^/ } K& e+ U' ?
- print(e)
- del validators[address]( o, ]0 j2 f q5 {
- break# d* [* ~* L* {
- # with My_Lock:$ L# \9 o0 q4 h6 N: a: S. [; \
- last_block = block_chain[-1]7 E8 Z$ I; o, \! l' p2 ?8 e
- new_block = generate_block(last_block, bpm, address)
- if is_block_valid(new_block, last_block):" ?0 d: a2 a, I4 z
- print("new block is valid!")
- candidate_blocks.put(new_block)
- self.request.send(b"\nEnter a new BPM:\n")3 @: v: X2 U) A9 ~9 C8 g
- annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True)1 o# x9 M }$ \
- annouce_blockchain_t.start()</div>
- <div># validator address. f7 q- n. d/ ` _4 R) O
- self.request.send(b"Enter token balance:")
- balance = self.request.recv(8192)/ N0 f$ E( B! S2 ^
- try:9 y% \$ [+ {4 T
- balance = int(balance)
- except Exception as e:+ ?8 `" ^4 E5 u5 u, v+ ~- P- _
- print(e)$ K i( {2 e+ E
- t = str(datetime.now())
- address = sha256(t.encode()).hexdigest()
- validators[address] = balance4 D0 `. l5 Q% o: u' {
- print(validators)</div>
- <div>announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),
- daemon=True)/ W) J0 x) n! }
- announce_winner_t.start()
- def annouce_winner(announcements, request):
- """
- :param announcements:
- :param request:+ ^4 o2 S- y/ ?3 w& r2 H7 c
- :return:
- """8 ?1 J, Y0 G& l0 u2 O, b
- while True:( n7 e7 K4 v9 ?4 u7 V7 w0 E4 ]
- try:
- msg = announcements.get(block=False)
- request.send(msg.encode())
- request.send(b'\n')
- except Empty:6 @8 a0 g- [5 n2 m1 ^ Q0 K
- time.sleep(3)
- continue</div>
- & b$ ]) w% R! G1 `0 R
- <div>self.request.send(b"\nEnter a new BPM:"), b: Z! c$ y$ \9 b7 E3 [
- bpm = self.request.recv(8192)% o# ~5 _- J% c8 i2 V" O
- try:7 ^: Z- k9 B H. x& S7 ~
- bpm = int(bpm)
- except Exception as e:5 c2 v, G! `) {( K3 \
- print(e)$ ^ B, ^; Y/ L# |0 z3 L$ I1 u; e+ J
- del validators[address]5 c' z3 W- M" U4 o6 I
- break
- # with My_Lock:5 h, J& W; A5 y! Q
- last_block = block_chain[-1]
- new_block = generate_block(last_block, bpm, address)! ~& @6 }* f' n1 C
- if is_block_valid(new_block, last_block):
- print("new block is valid!")
- candidate_blocks.put(new_block)</div>
- + L7 x/ R" N! b& H
- <div>annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True)
- annouce_blockchain_t.start()% G* z8 b6 I+ l1 b
- def annouce_blockchain(request):
- """
- :param request:& k5 K3 z. X% M2 v
- :return:
- """4 _5 } `. X& e9 Z1 n
- while True:
- time.sleep(30), R/ [! Q$ r% k/ B5 o' j. ]
- with My_Lock:
- output = json.dumps(block_chain)
- try:/ O- n d# d8 @- h9 h: R8 y0 g
- request.send(output.encode())
- request.send(b'\n')
- except OSError:; @) K0 f, ~6 D& q
- pass</div>
- <div>def pick_winner(announcements):
- """+ c( c9 v" `+ E T$ S
- 选择记账人, U t2 Y0 {, l2 P2 ~% Q% v
- :param announcements:
- :return:% F! t* R, S. ^6 w7 K
- """
- time.sleep(10)
- while True:5 d- s$ i9 H7 m* h
- with My_Lock:
- temp = temp_blocks) z" U- {: | C! z) s4 U2 Y
- lottery_pool = [] #+ x: B: n7 g9 x& a/ z9 X
- if temp:
- for block in temp:
- if block["Validator"] not in lottery_pool:
- set_validators = validators+ Q& B/ A1 T2 W( O
- k = set_validators.get(block["Validator"])
- if k:
- for i in range(k):9 [0 a$ _+ i4 s: _5 D- P
- lottery_pool.append(block["Validator"])
- lottery_winner = choice(lottery_pool)
- print(lottery_winner)
- # add block of winner to blockchain and let all the other nodes known! A- Z# K+ A8 F
- for block in temp:0 x3 a; H$ v8 f. l! l& Q# K/ p7 h
- if block["Validator"] == lottery_winner:8 F {# g0 M( k
- with My_Lock:
- block_chain.append(block)
- # write message in queue.
- msg = "\n{0} 赢得了记账权利\n".format(lottery_winner)
- announcements.put(msg)
- break# {$ E& T' ~! t s* K) l4 ^: I
- with My_Lock:5 @6 ~" \& a3 |/ E+ K J, g
- temp_blocks.clear()</div>
- <div>def run():
- # create a genesis block. f' T+ }- n! l5 @) C
- t = str(datetime.now())4 m3 V: W; V* |: Q6 A
- genesis_block = {, ]. c' {1 D: y2 F
- "Index": 0,1 d" \. e* r' F7 ~% \
- "Timestamp": t,4 N" o% ^: Z" G2 |& D9 ?- C
- "BPM": 0,& ?: |" L/ O6 c
- "PrevHash": "",( V% ^! l9 x1 {! X9 ^6 n
- "Validator": ""
- }
- genesis_block["Hash"] = calculate_hash(genesis_block)4 A+ X' n& {9 }5 `
- print(genesis_block)' \6 W; c" G7 z( ~
- block_chain.append(genesis_block), c5 F1 n3 a" l
- thread_canditate = threading.Thread(target=candidate, args=(candidate_blocks,), daemon=True)- A [" @: y4 e* o8 w7 H3 U
- thread_pick = threading.Thread(target=pick_winner, args=(announcements,), daemon=True)7 i' a$ v% v( @8 j% h A- S
- thread_canditate.start()% j" D4 B% A, t; Z$ j9 `- @
- thread_pick.start()6 `, p; M: @- H7 X7 q- x
- # start a tcp server
- serv = ThreadingTCPServer(('', 9090), HandleConn)
- serv.serve_forever()# K9 T4 X; O8 ^1 w z
- def candidate(candidate_blocks):
- """
- :param candidate_blocks:; m: y" _6 r, w- _% \( U
- :return:
- """+ v" a0 `; {# K; I; L% Z# ]! `# e3 J1 o: _
- while True:% O# ^. E! K0 C6 f8 m) D/ O3 A, R( q1 u: F
- try:
- candi = candidate_blocks.get(block=False)1 N. O4 i$ @; T$ B5 H
- except Empty:+ z- V P H! |0 ~8 w) O0 q
- time.sleep(5)( `7 j, z* }" X9 H* v. \, f$ J
- continue; J; q- c. {3 h7 \& z$ Q1 h
- temp_blocks.append(candi): [ A; H: X) ~5 k; C
- if __name__ == '__main__':7 _' y9 m4 A+ E; R: L
- run()</div>