用 Python 描述一条简单的区块链

关键词:Consensus AlgorithmProof of Work(PoW)
参考文章:https://hackernoon.com/learn-blockchains-by-building-one-117428612f46
(网上已有中文翻译,本文只是要点概括)

一个想象的场景

前几天我在一条药品链上买了盒感冒药💊,产生了一笔交易记录,上面记录着:是我付的款,人民医院收的钱,还有药品金额,嗯,存下药品信息也不错。

区块链会把这笔交易先记录下来,等待其它计算节点(矿工)帮忙把交易记录写入区块(在等人挖矿啦),等矿工把生成区块所需的物品(算法生成的值)准备好后,就把记录都写入区块,这时候链上就多了一个区块,记录了一些交易信息。当然了,矿工不能白干啊,不然给你闹罢工,系统就奖励矿工一张优惠券,并告诉他,通过我们买💊,买一送一。

我回家吃了好几天药,感冒也没见好,怎么回事呢?上网一查发现,哎呀,吃错药了,医院能不能赔?我拿什么证明呢?这时候到链上一查,给丫区块一特写,药品信息、交易时间、收款人、付款人样样俱全,不赔不行啊。(当然了,药品交易有没有必要使用区块链技术呢?也是个值得思考的问题。)

背后的技术

我在阅读了不少入门介绍后,依然觉得理解不够清晰,本着数据结构和算法一定要手动验证的精神,我也手动验证了一条简单的区块链。如果对区块链还没有建立起基础认识,可以读些有趣的科普文章。

在我们建立一条区块链之前,可先回想复习一下Linked List 链表或者顺序存储数组,我们会用 Python 的 list 数据结构来存储区块 block

区块链给我们带来了"更安全"更透明的一种生活方式,每笔「交易」最终都会被记录进区块,由于链上区块的设计巧妙,可验证,不少人都开始探索它的使用场景,当然了,目前最多还是聚焦在金融领域 ......

区块是如何做到高安全性的呢?

首先每条链都会引入一个创世区块创世区块带有交易的时间和相关信息,此外还包含一个证明 proof字段,这是该链的拥有者定义的,用来证明区块的身份,还包含一个previous hash字段,用来验证上一个区块的身份,由于创世区块之前没有区块了,所以它的previous hash没什么 x 用。但是,之后的区块都可以根据proofprevious hash来验证,由于生成这两个值的算法难以破解,所以安全性比较高。

少啰嗦,直接看代码

class Blockchain(object):
    # 初始化我们的链
    def __init__(self):
        # 所有生成的区块都存着这条链里
        self.chain = []
        # 当前所有交易记录,将被写进新生成的区块里
        self.current_transactions = []

        # 你好,我是创世区块
        self.new_block(previous_hash=1, proof=100)

    def new_block(self, proof, previous_hash=None):
        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.last_block),
        }

        self.current_transactions = []

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

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

    def proof_of_work(self, last_proof):
        proof = 0

        while not self.valid_proof(last_proof, proof):
            proof += 1

        return proof

    def valid_proof(self, last_proof, proof):
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[-1] == "0"

我们提供了初始化一条链的方法,并且提供了产生交易记录的函数,产生区块的函数。hash&proof_of_work都是为区块的身份验证提供服务的,有了它们才能保证每个区块的身份以及它和前一个区块的关联性。当我们能验证每个区块都和前一个区块关系正常时,整条链就正常了。

常说的分布式计算是什么?

你可能听说过区块链是去中心化的,是分布式的,这到底是什么意思?

我们的一个个矿工,其实就是一个个计算节点,他们为区块链提供计算服务,生成新区块所需要的巨大运算都交由他们执行,这叫分布式计算,充分利用了闲散的算力,也充分带动了一波显卡销售 ^ _ ^

但这也带来了一个问题,这么多个计算节点,我们怎么保证最终的结果一致呢?如果我挖到一张优惠券,你挖到两张优惠券,我们这条链岂不是就乱了?这时候就要看共识算法 Consensus Algorithm了,用它来确保所有节点的链都一致,确确实实是一条链,不是 fork 出去的兄弟。我们来拓展上面的代码。

class Blockchain(object):
    def __init__(self):
        .....
        self.nodes = set()
        .....

    .....

    def register_node(self, address):
        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

    def valid_chain(self, chain):
        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")

            if block['previous_hash'] != self.hash(last_block):
                return False

            if not self.valid_proof(last_block['proof'], block['proof']):
                return False

            last_block = block
            current_index += 1

        return True

    def resolve_conflicts(self):
        neighbours = self.nodes
        new_chain = None

        max_length = len(self.chain)
        for node in neighbours:
            response = requests.get(f'http://{node}/chain')

            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain

        if new_chain:
            self.chain = new_chain
            return True

        return False

现在我们提供了增加计算节点的函数,也提供了检验链的函数,更重要的是,我们引入了解决链不一致的方法resolve_conflicts,有了它,我们就可以确保这么多个计算节点拥有的链都一致啦。

具体的思想是这样的:我们在链上记录了所有计算节点的位置,当我们想获得链的最新状态时,就去轮询节点,挨个问:“你的链多长,有几个区块?咱们比比?”,这样一轮下来,如果我们发现有的链比我们的更长,那么这条更长的链就是最新且正确的,我们把它拿过来,更新成我们的链,这样就一致了。

当然了,就算是看到这里你可能还是会有不少疑惑,比如说:

  • 为什么长的就最新且最正确?
  • 如果 A 节点生成了两个区块,B 节点也生成了两个区块,这时候去同步链会怎么样?
  • 什么时候该去同步链?

嗯,写到这里发现自己其实还有很多的疑惑,动手再检验一下吧!

原作者的代码:
https://github.com/dvf/blockchain
我的代码:
https://github.com/helsonxiao/learn-blockchain

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容