- - j8 q6 y2 E/ F v/ ?4 A8 G
- <div>from hashlib import sha256
- from datetime import datetime
- def generate_block(oldblock, bpm, address):! s K& y( T, f$ }1 j3 y
- """
- :param oldblock:. \8 O+ ?% L6 V& t& s% B7 X
- :param bpm:6 ~( O5 a/ G, m1 {) y8 [* U
- :param address:- X. p$ D- T( [4 _: i; d9 k
- :return:9 |0 e N: G: U# H7 J0 ^0 [- K
- """) Q# e- j& c* u) W
- newblock = {
- "Index": oldblock["Index"] + 1,
- "BPM": bpm,4 ]' X( i& H6 I0 `/ l( L
- "Timestamp": str(datetime.now()),0 e) F* x8 e) _: d: v/ h/ n* X
- "PrevHash": oldblock["Hash"]," O" ]1 x" K! m0 Q* g$ k o
- "Validator": address: h+ J3 j; p1 _, T, P4 t/ K. |/ X
- }7 ]9 \0 B" |% y1 x
- newblock["Hash"] = calculate_hash(newblock)' t, A$ `( v* ]8 Y4 C
- return newblock
- def calculate_hash(block):
- record = "".join([
- str(block["Index"]),3 [. ~3 _6 }! |' `& ?! h" J4 |5 ]# t
- str(block["BPM"]),
- block["Timestamp"],
- block["PrevHash"]
- ])
- return sha256(record.encode()).hexdigest()' {5 Z) y* J; x$ {5 ^: }5 R
- def is_block_valid(newblock, oldblock):
- """
- :param newblock:
- :param oldblock:
- :return:
- """8 }* O( K% R( Q. J" h$ J' |
- if oldblock["Index"] + 1 != newblock["Index"]:
- return False, k' R0 \6 C) q
- if oldblock["Hash"] != newblock["PrevHash"]:* o) ^" [2 Y; Y5 j2 K4 H+ X
- return False, ^) ~! _, y9 W: E' A) i: e
- if calculate_hash(newblock) != newblock["Hash"]:$ Z% E) c* l) e5 P
- return False3 r/ U6 m7 U7 F9 m0 r* y8 |, r) I
- return True</div>
- ; y4 i; k4 j' Z& O, z
- <div>from socketserver import BaseRequestHandler, ThreadingTCPServer
- def run():' L4 T- q& g+ K1 `; U
- # start a tcp server+ T+ g, c& O, S
- serv = ThreadingTCPServer(('', 9090), HandleConn)
- serv.serve_forever()</div>
- <div>import threading
- from queue import Queue, Empty
- # 定义变量
- block_chain = []7 E; Y! {" u' ^9 F3 `: K- j. O; C
- temp_blocks = []
- candidate_blocks = Queue() # 创建队列,用于线程间通信
- announcements = Queue()0 C5 k3 i: U( I9 [. M
- validators = {}! p8 {0 w" \* ?) [: x
- My_Lock = threading.Lock()+ X, _. s, N: H7 W2 h7 C
- class HandleConn(BaseRequestHandler):
- def handle(self):( u8 y* F7 p( q3 f& @2 a! [
- print("Got connection from", self.client_address)
- # validator address
- self.request.send(b"Enter token balance:")& j# U! d! @$ ?" w6 u+ X
- balance = self.request.recv(8192); P0 q* M7 a8 {( r8 m
- try:
- balance = int(balance)
- except Exception as e:
- print(e)
- t = str(datetime.now())
- address = sha256(t.encode()).hexdigest()& ^8 N# X `9 m
- validators[address] = balance
- print(validators)
- while True:8 x: |8 I& Z+ b5 e% V/ M1 J
- announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),% h G# [( b% ?
- daemon=True)
- announce_winner_t.start()
- self.request.send(b"\nEnter a new BPM:")
- bpm = self.request.recv(8192)
- try:9 B T2 @2 T! r- s( E3 I
- bpm = int(bpm)
- except Exception as e:
- print(e)
- del validators[address]9 C& h; f( G! l: z1 w0 J
- break {! [. V" }2 M- J* p; F
- # with My_Lock:
- last_block = block_chain[-1]
- new_block = generate_block(last_block, bpm, address)
- if is_block_valid(new_block, last_block):
- print("new block is valid!")
- candidate_blocks.put(new_block)4 @4 ~& _$ |5 y: c! C- u
- self.request.send(b"\nEnter a new BPM:\n")4 w" R. O6 {+ f& ^' j0 G
- annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True)
- annouce_blockchain_t.start()</div>
- / ^) J4 `( n, x3 o, @
- <div># validator address
- self.request.send(b"Enter token balance:")! L4 V" S6 L1 f; Z, u
- balance = self.request.recv(8192)
- try:
- balance = int(balance)
- except Exception as e:
- print(e)
- t = str(datetime.now())! ?! B1 z6 X7 k* G6 i0 N" M
- address = sha256(t.encode()).hexdigest(): ^2 ]% p9 Y! Q
- validators[address] = balance
- print(validators)</div>
- <div>announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),3 S7 V7 C1 W1 i. g0 \
- daemon=True)
- announce_winner_t.start()
- def annouce_winner(announcements, request):
- """
- :param announcements:
- :param request:# q1 `( M4 A' u0 f0 y! Z
- :return:
- """
- while True:9 @# Q; Q7 I- l: Y# F! X* g
- try:% k/ E/ d1 m' o
- msg = announcements.get(block=False)2 Q5 V6 e) U( o% B% u
- request.send(msg.encode())
- request.send(b'\n')
- except Empty:
- time.sleep(3)7 a2 u8 Y9 D8 G+ O& \
- continue</div>
- <div>self.request.send(b"\nEnter a new BPM:")
- bpm = self.request.recv(8192)! z$ L" B* N, S4 [
- try:
- bpm = int(bpm)
- except Exception as e:5 s6 H, e) k! Q# G# T- @
- print(e), n2 H: Q0 `8 ?9 ]
- del validators[address]
- break/ ]. u( V8 J1 |' w' T) H) B& e- M
- # with My_Lock:
- last_block = block_chain[-1]5 `; v% g6 E3 E% O2 a) g
- new_block = generate_block(last_block, bpm, address)
- if is_block_valid(new_block, last_block):/ j( a% V' z2 i2 i9 J; Z% A
- print("new block is valid!")
- candidate_blocks.put(new_block)</div>
- 4 }# L" E. o1 v: _5 F0 F
- <div>annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True), [2 m: V6 K' f
- annouce_blockchain_t.start()9 U4 q5 B( \5 |$ d: u" E1 M, N
- def annouce_blockchain(request):; U/ Q$ m2 V- s; Q+ X% v1 j
- """5 t$ n* Z( V, w- d2 ]( x+ _) P
- :param request:% l d7 V/ o, W/ u
- :return:3 P% ~, ^) u4 z& x: O
- """! `8 g% q" h; B. g
- while True:4 G6 z0 w$ B( t8 V* Y7 N4 o
- time.sleep(30)- n! Q. f) l) i* z+ J% l: R
- with My_Lock:, ~5 d# s% D( h/ e/ y+ ^! ]. J7 M
- output = json.dumps(block_chain)" B" }$ i' J) O1 L/ }# J
- try: D9 w2 B R2 z; R1 E
- request.send(output.encode())
- request.send(b'\n')+ i4 R% c7 x* W# _0 }$ S' v* W" ^+ s
- except OSError:+ R9 }8 V1 K5 @1 l5 y
- pass</div>
- ) e* N/ W3 ^! C4 n. H: S
- <div>def pick_winner(announcements):
- """
- 选择记账人, {* h5 P& X3 n
- :param announcements:
- :return:% Q# I; @+ _& y2 I$ e5 X5 z
- """
- time.sleep(10)
- while True:/ L) [: v8 h/ i/ x$ D' U
- with My_Lock:
- temp = temp_blocks
- lottery_pool = [] #
- if temp:; y+ j- u2 T1 ~( P5 {+ X
- for block in temp:8 o! {1 a7 v( G
- if block["Validator"] not in lottery_pool:& m, `: Q7 W* k: g
- set_validators = validators
- k = set_validators.get(block["Validator"])* f& Q9 c6 b" l9 K g9 t
- if k:/ ?+ c# C% E0 v* V0 r6 [5 Q# B
- for i in range(k):
- lottery_pool.append(block["Validator"])
- lottery_winner = choice(lottery_pool)- H. ^& |/ Z7 O: t7 Z
- print(lottery_winner)* J' u" ~5 O6 j3 E' @. d& e7 m
- # add block of winner to blockchain and let all the other nodes known# G, F( ] v8 z7 Y
- for block in temp:' E$ B! M2 [7 x# `( B& Y" @' {) f; C
- if block["Validator"] == lottery_winner:" L, l7 [. b2 u( ^/ S' z0 l
- with My_Lock:
- block_chain.append(block)4 _* B, o/ z! I8 L3 e
- # write message in queue.+ [3 K% ^3 d0 K4 m
- msg = "\n{0} 赢得了记账权利\n".format(lottery_winner). U4 O+ T+ X. p7 ]2 l4 P
- announcements.put(msg)
- break! D9 J R k/ Y8 m! \
- with My_Lock:
- temp_blocks.clear()</div>
- ' t+ s0 M1 b. j6 `9 D- \+ U) o: ^4 s
- <div>def run(): l5 h3 W' n6 r0 l5 y$ E
- # create a genesis block
- t = str(datetime.now())
- genesis_block = {9 M0 y; {0 T9 o8 f8 ~! Q" `% w
- "Index": 0,
- "Timestamp": t,
- "BPM": 0,
- "PrevHash": "",
- "Validator": ""
- }( w& Q& z2 w" K% F
- genesis_block["Hash"] = calculate_hash(genesis_block)7 Q; R% R; u0 B1 ?7 b& ?
- print(genesis_block); R: \3 k7 Q3 Z) I+ }$ K
- block_chain.append(genesis_block): \: a8 \$ u. m6 g! r+ l
- thread_canditate = threading.Thread(target=candidate, args=(candidate_blocks,), daemon=True)
- thread_pick = threading.Thread(target=pick_winner, args=(announcements,), daemon=True)# q. B; A+ r" O2 Q
- thread_canditate.start(). M" n0 R( F; g
- thread_pick.start()5 |/ Y: p1 E: y0 R2 q% X- L
- # start a tcp server8 [* }9 Z9 N; R2 { ~ m1 G7 f
- serv = ThreadingTCPServer(('', 9090), HandleConn)
- serv.serve_forever()
- def candidate(candidate_blocks): O7 `' H8 g; ^7 R/ J! s
- """
- :param candidate_blocks:+ f6 ^4 `, { z/ p
- :return:$ R0 v8 e* G1 S: I8 [! H
- """
- while True:
- try:8 B' _1 l. a( ^2 l+ h
- candi = candidate_blocks.get(block=False)
- except Empty:! e$ g/ m" a# D/ q$ V
- time.sleep(5)
- continue
- temp_blocks.append(candi)) }$ ~" R2 s& R- {2 w. |; o- c* m
- if __name__ == '__main__':9 p- L9 r: J8 F& O% G: z
- run()</div>