楼主: Studio-R
1604 2

[区块链] 边构建区块链边学习(Jupyter notebook) [推广有奖]

  • 9关注
  • 12粉丝

教授

1%

还不是VIP/贵宾

-

威望
0
论坛币
38231 个
通用积分
890.7861
学术水平
30 点
热心指数
29 点
信用等级
18 点
经验
25291 点
帖子
636
精华
1
在线时间
1130 小时
注册时间
2016-11-3
最后登录
2024-4-24

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
边构建区块链边学习(Jupyter notebook)
  • 构建区块链的同时进行学习|编程|使用在POSTD中发布的解释和代码逐步进行测试。

  • 直接由Jupyter实施,因为觉得在Flask中的实现很多余。

  • 阅读文本是假定您对于块链本身的机制已经有所理解。






代码的实现1.创建一个区块链类


In [1]:
  1. from time import time
  2. import hashlib
  3. import json

  4. class Blockchain(object):
  5.     def __init__(self):
  6.         self.current_transactions = []
  7.         self.chain = []

  8.         # Create the genesis block
  9.         self.new_block(previous_hash=1, proof=100)

  10.     def new_block(self, proof, previous_hash=None):
  11.         """
  12.         Create a new Block in the Blockchain
  13.         :param proof: <int> The proof given by the Proof of Work algorithm
  14.         :param previous_hash: (Optional) <str> Hash of previous Block
  15.         :return: <dict> New Block
  16.         """
  17.         block = {
  18.             'index': len(self.chain) + 1,
  19.             'timestamp': time(),
  20.             'transactions': self.current_transactions,
  21.             'proof': proof,
  22.             'previous_hash': previous_hash or self.hash(self.chain[-1]),
  23.         }

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

  26.         self.chain.append(block)
  27.         return block

  28.     def new_transaction(self, sender, recipient, amount):
  29.         """
  30.         Creates a new transaction to go into the next mined Block
  31.         :param sender: <str> Address of the Sender
  32.         :param recipient: <str> Address of the Recipient
  33.         :param amount: <int> Amount
  34.         :return: <int> The index of the Block that will hold this transaction
  35.         """
  36.         self.current_transactions.append({
  37.             'sender': sender,
  38.             'recipient': recipient,
  39.             'amount': amount,
  40.         })
  41.         return self.last_block['index'] + 1

  42.     @staticmethod
  43.     def hash(block):
  44.         """
  45.         Creates a SHA-256 hash of a Block
  46.         :param block: <dict> Block
  47.         :return: <str>
  48.         """
  49.         # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
  50.         block_string = json.dumps(block, sort_keys=True).encode()
  51.         return hashlib.sha256(block_string).hexdigest()

  52.     @property
  53.     def last_block(self):
  54.         return self.chain[-1]

  55.     def proof_of_work(self, last_proof):
  56.         """
  57.         Simple Proof of Work Algorithm:
  58.          - Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
  59.          - p is the previous proof, and p' is the new proof
  60.         :param last_proof: <int>
  61.         :return: <int>
  62.         """
  63.         proof = 0
  64.         while self.valid_proof(last_proof, proof) is False:
  65.             proof += 1
  66.         return proof

  67.     @staticmethod
  68.     def valid_proof(last_proof, proof):
  69.         """
  70.         Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
  71.         :param last_proof: <int> Previous Proof
  72.         :param proof: <int> Current Proof
  73.         :return: <bool> True if correct, False if not.
  74.         """
  75.         guess = ('%d%d' % (last_proof, proof)).encode()
  76.         guess_hash = hashlib.sha256(guess).hexdigest()
  77.         return guess_hash[:4] == "0000"
复制代码

2.挖矿代码


In [2]:
  1. from uuid import uuid4

  2. node_identifier = str(uuid4()).replace('-', '')

  3. def mine(blockchain):
  4.     global node_identifier
  5.    
  6.     # We run the proof of work algorithm to get the next proof...
  7.     last_block = blockchain.last_block
  8.     last_proof = last_block['proof']
  9.     proof = blockchain.proof_of_work(last_proof)

  10.     # We must receive a reward for finding the proof.
  11.     # The sender is "0" to signify that this node has mined a new coin.
  12.     blockchain.new_transaction(
  13.         sender="0",
  14.         recipient=node_identifier,
  15.         amount=1,
  16.     )

  17.     # Forge the new Block by adding it to the chain
  18.     previous_hash = blockchain.hash(last_block)
  19.     block = blockchain.new_block(proof, previous_hash)

  20.     response = {
  21.         'message': "New Block Forged",
  22.         'index': block['index'],
  23.         'transactions': block['transactions'],
  24.         'proof': block['proof'],
  25.         'previous_hash': block['previous_hash'],
  26.     }
  27.     return response
复制代码





3.添加示例并返回整个链


In [3]:
  1. def full_chain(blockchain):
  2.     response = {
  3.         'chain': blockchain.chain,
  4.         'length': len(blockchain.chain),
  5.     }
  6.     return response
复制代码




尝试移动块链

使用pprint使显示更容易看到。




In [4]:
  1. import pprint
  2. pp = pprint.PrettyPrinter(indent=2)
复制代码

自身节点的标识符如下。




In [5]:
  1. import pprint
  2. pp = pprint.PrettyPrinter(indent=2)
复制代码
Out[5]:
'7d10057a10364156aa9ac7b92ce3c34e'





一旦实例化,将创建第一个区块

  • index:索引为1
  • previous_hash:初始的hash值1
  • length:链条的长度显然是1



In [6]:
  1. b = Blockchain()
  2. pp.pprint(full_chain(b))
复制代码

开始创建第一个街区

  1. { 'chain': [ { 'index': 1,
  2.                'previous_hash': 1,
  3.                'proof': 100,
  4.                'timestamp': 1516245610.8226993,
  5.                'transactions': []}],
  6.   'length': 1}
复制代码

In [7]:
  1. newblock = mine(b)
  2. pp.pprint(newblock)
复制代码
  1. { 'index': 2,
  2.   'message': 'New Block Forged',
  3.   'previous_hash': 'b0879b53a4230c49e23d3c4715034e732bc07ab54f3ba16dbd0fa73860d8faee',
  4.   'proof': 35293,
  5.   'transactions': [ { 'amount': 1,
  6.                       'recipient': '7d10057a10364156aa9ac7b92ce3c34e',
  7.                       'sender': '0'}]}
复制代码

在交易环节中,只描述了采矿挖掘交易

  • sender:发件人为0
  • recipient:收件人标识符
  • amount:金额是1

记录为交易。 现在我们来看看整个区块链的内容




In [8]:
  1. pp.pprint(full_chain(b))
复制代码
  1. { 'chain': [ { 'index': 1,
  2.                'previous_hash': 1,
  3.                'proof': 100,
  4.                'timestamp': 1516245610.8226993,
  5.                'transactions': []},
  6.              { 'index': 2,
  7.                'previous_hash': 'b0879b53a4230c49e23d3c4715034e732bc07ab54f3ba16dbd0fa73860d8faee',
  8.                'proof': 35293,
  9.                'timestamp': 1516245625.9124067,
  10.                'transactions': [ { 'amount': 1,
  11.                                    'recipient': '7d10057a10364156aa9ac7b92ce3c34e',
  12.                                    'sender': '0'}]}],
  13.   'length': 2}
复制代码





作为一个新的交易(交易),有的区块只包含挖掘结果。

我们在这里添加一个新的事务。

  • 添加发件人到'foo'
  • 将收件人设置为'bar'
  • amount 设置为10

并达成交易。




In [9]:
  1. index = b.new_transaction('foo', 'bar', 10)
复制代码


此时index(块的索引)是3。 上述交易存储在这个块中。




In [10]:
  1. print(index)
复制代码
3

此时,从整个链条来看,上面添加的交易还没有在链上注册。




In [11]:
  1. pp.pprint(full_chain(b))
复制代码
  1. { 'chain': [ { 'index': 1,
  2.                'previous_hash': 1,
  3.                'proof': 100,
  4.                'timestamp': 1516245610.8226993,
  5.                'transactions': []},
  6.              { 'index': 2,
  7.                'previous_hash': 'b0879b53a4230c49e23d3c4715034e732bc07ab54f3ba16dbd0fa73860d8faee',
  8.                'proof': 35293,
  9.                'timestamp': 1516245625.9124067,
  10.                'transactions': [ { 'amount': 1,
  11.                                    'recipient': '7d10057a10364156aa9ac7b92ce3c34e',
  12.                                    'sender': '0'}]}],
  13.   'length': 2}
复制代码





挖矿并添加一个新的块。


In [12]:
  1. newblock = mine(b)
复制代码

创建第3个区块,保存之前创建的事务信息和挖掘信息。




In [13]:

pp.pprint(newblock)
{ 'index': 3,  'message': 'New Block Forged',  'previous_hash': '635b05a6a3d32c78f3d23fa9ab44222616ba073cac93f064fedeafb6684ad645',  'proof': 35089,  'transactions': [ {'amount': 10, 'recipient': 'bar', 'sender': 'foo'},                    { 'amount': 1,                      'recipient': '7d10057a10364156aa9ac7b92ce3c34e',                      'sender': '0'}]}


此时整个链条的状态如下。




In [14]:
pp.pprint(full_chain(b)){ 'chain': [ { 'index': 1,               'previous_hash': 1,               'proof': 100,               'timestamp': 1516245610.8226993,               'transactions': []},             { 'index': 2,               'previous_hash': 'b0879b53a4230c49e23d3c4715034e732bc07ab54f3ba16dbd0fa73860d8faee',               'proof': 35293,               'timestamp': 1516245625.9124067,               'transactions': [ { 'amount': 1,                                   'recipient': '7d10057a10364156aa9ac7b92ce3c34e',                                   'sender': '0'}]},             { 'index': 3,               'previous_hash': '635b05a6a3d32c78f3d23fa9ab44222616ba073cac93f064fedeafb6684ad645',               'proof': 35089,               'timestamp': 1516245688.0261838,               'transactions': [ { 'amount': 10,                                   'recipient': 'bar',                                   'sender': 'foo'},                                 { 'amount': 1,                                   'recipient': '7d10057a10364156aa9ac7b92ce3c34e',                                   'sender': '0'}]}],  'length': 3}



智能合约(分布式)class Blockchain2()类的实现

实现Blcokchain 2类包含共识算法。

另外,节点标识符被保存为一个类成员,并且在挖掘它时被修改为使用它。 (为了能够处理多个节点的块链)

(实际上,定义Node类并将Blockchain 2类作为has-a作为成员似乎更好,但是因为在Blockchain类的原始版本中引入了register_node()或resolve_conflicts()




In [15]:import copyBlockchainNeighbours = {}class Blockchain2(Blockchain):    def __init__(self, node_identifier):        super().__init__()        self.nodes = set()        self.node_identifier = node_identifier            def register_node(self, node_identifier):        """        Add a new node to the list of nodes        :node_identifier: <str> Node identifier of the neighbour node.        :return: None        """        self.nodes.add(node_identifier)    def valid_chain(self, chain):        """        Determine if a given blockchain is valid        :param chain: <list> A blockchain        :return: <bool> 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):        """        This is our Consensus Algorithm, it resolves conflicts        by replacing our chain with the longest one in the network.        :return: <bool> True if our chain was replaced, False if not        """        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:            blockchain = BlockchainNeighbours[node]            print('node id: %s, len: %d' % (blockchain.node_identifier, len(blockchain.chain)))            # Check if the length is longer and the chain is valid            if len(blockchain.chain) > max_length and self.valid_chain(blockchain.chain):                max_length = len(blockchain.chain)                new_chain = blockchain        # Replace our chain if we discovered a new, valid chain longer than ours        if new_chain:            print("Replacing `%s' <- `%s'" % (self.node_identifier, new_chain.node_identifier))            self.chain = copy.copy(new_chain.chain)            return True        return False


In [16]:def mine2(blockchain):    # 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)    # We must receive a reward for finding the proof.    # The sender is "0" to signify that this node has mined a new coin.    blockchain.new_transaction(        sender="0",        recipient=blockchain.node_identifier,        amount=1,    )    # Forge the new Block by adding it to the chain    previous_hash = blockchain.hash(last_block)    block = blockchain.new_block(proof, previous_hash)    response = {        'message': "New Block Forged",        'index': block['index'],        'transactions': block['transactions'],        'proof': block['proof'],        'previous_hash': block['previous_hash'],    }    return response


创建多个节点的块链



为三个节点创建一个块链,并注册为一个相邻节点。




In [35]:# 为节点标识符为“foo”,“bar”,“buz”的三个节点创建一个块链。foo = Blockchain2('foo')bar = Blockchain2('bar')buz = Blockchain2('buz')# 注册在相邻节点的列表中BlockchainNeighbours['foo'] = fooBlockchainNeighbours['bar'] = barBlockchainNeighbours['buz'] = buz# 'bar','buz'注册为'foo'节点邻居foo.register_node('bar')foo.register_node('buz')# 为“bar”,“buz”节点注册邻居bar.register_node('foo')bar.register_node('buz')buz.register_node('foo')buz.register_node('bar')



在初始状态下,所有节点的链路长度为1。




In [18]:
print('foo: %d, bar: %d, buz: %d' %(len(foo.chain), len(bar.chain), len(buz.chain)))

foo: 1, bar: 1, buz: 1





即使你试图在初始状态下解决冲突,也没有链节点长于foo节点,所以foo节点链不会改变。




In [19]:
foo.resolve_conflicts()



node id: buz, len: 1node id: bar, len: 1

Out[19]:
False





在一些节点上伸展块

接下来,在bar节点上挖掘并添加一个块。




In [20]:
pp.pprint(mine2(bar))
{ 'index': 2,  'message': 'New Block Forged',  'previous_hash': 'c97740db684709fd7455f413f0ad84f435236e1534caaea7cf744921b59fab3b',  'proof': 35293,  'transactions': [{'amount': 1, 'recipient': 'bar', 'sender': '0'}]}




节点的长度只有2




In [21]:
print('foo: %d, bar: %d, buz: %d' %(len(foo.chain), len(bar.chain), len(buz.chain)))



foo: 1, bar: 2, buz: 1




In [22]:
pp.pprint(foo.chain)



[ { 'index': 1,    'previous_hash': 1,    'proof': 100,    'timestamp': 1516245713.7215648,    'transactions': []}]



In [23]:
pp.pprint(bar.chain)[ { 'index': 1,    'previous_hash': 1,    'proof': 100,    'timestamp': 1516245713.7215648,    'transactions': []},  { 'index': 2,    'previous_hash': 'c97740db684709fd7455f413f0ad84f435236e1534caaea7cf744921b59fab3b',    'proof': 35293,    'timestamp': 1516245772.022711,    'transactions': [{'amount': 1, 'recipient': 'bar', 'sender': '0'}]}]



In [24]:
pp.pprint(buz.chain)
[ { 'index': 1,    'previous_hash': 1,    'proof': 100,    'timestamp': 1516245713.7215648,    'transactions': []}]



消除节点之间的冲突

在这种状态下,当试图解决foo节点处的冲突时,foo节点链被(更长的)节点链覆盖。




In [25]:
foo.resolve_conflicts()node id: buz, len: 1node id: bar, len: 2Replacing `foo' <- `bar'
Out[25]:
True





当冲突的解决完成时,foo节点的链长变为2。




In [26]:

print('foo: %d, bar: %d, buz: %d' %(len(foo.chain), len(bar.chain), len(buz.chain)))foo: 2, bar: 2, buz: 1





如果每个节点链的内容不同



接下来,考虑每个节点链的内容不同的情况。

这里我们看到foo节点和buz节点的内容不同的情况。




In [27]:
# buzノードの内容を揃えるbuz.resolve_conflicts()print('foo: %d, bar: %d, buz: %d' %(len(foo.chain), len(bar.chain), len(buz.chain)))
node id: foo, len: 2node id: bar, len: 2Replacing `buz' <- `foo'foo: 2, bar: 2, buz: 2



在这里,在foo节点添加两个块,一个块在buz节点,并且添加具有不同事务的块。




In [28]:
foo.new_transaction('AAA', 'BBB', 123)mine2(foo)foo.new_transaction('CCC', 'DDD', 456)mine2(foo)buz.new_transaction('EEE', 'FFF', 789)mine2(buz)print('foo: %d, bar: %d, buz: %d' %(len(foo.chain), len(bar.chain), len(buz.chain)))foo: 4, bar: 2, buz: 3




此时foo节点和buz节点链的内容如下。 你可以看到内容与中间不同。




In [29]:
pp.pprint(foo.chain)
[ { 'index': 1,    'previous_hash': 1,    'proof': 100,    'timestamp': 1516245713.7215648,    'transactions': []},  { 'index': 2,    'previous_hash': 'c97740db684709fd7455f413f0ad84f435236e1534caaea7cf744921b59fab3b',    'proof': 35293,    'timestamp': 1516245772.022711,    'transactions': [{'amount': 1, 'recipient': 'bar', 'sender': '0'}]},  { 'index': 3,    'previous_hash': '8791fb38c957761c7af4331d65e834691cd7aa46019faaab3d655deae86d3dbb',    'proof': 35089,    'timestamp': 1516245803.1813366,    'transactions': [ {'amount': 123, 'recipient': 'BBB', 'sender': 'AAA'},                      {'amount': 1, 'recipient': 'foo', 'sender': '0'}]},  { 'index': 4,    'previous_hash': '99e21d9dd699d831803a0ea41d08cf9b2cfa642b94d4ee5ba4a38d1773c1c5c3',    'proof': 119678,    'timestamp': 1516245803.3608067,    'transactions': [ {'amount': 456, 'recipient': 'DDD', 'sender': 'CCC'},                      {'amount': 1, 'recipient': 'foo', 'sender': '0'}]}]
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Notebook EBook note eboo Book

[url=https://edu.cda.cn/page/110][/url]
沙发
pudino 发表于 2018-1-31 14:33:23 |只看作者 |坛友微信交流群
不太能理解。

使用道具

藤椅
Studio-R 在职认证  发表于 2018-2-2 18:45:26 |只看作者 |坛友微信交流群
pudino 发表于 2018-1-31 14:33
不太能理解。
有什么问题吗?

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jr
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-25 16:08