Blockchain-Public Chain

foreword

       This is the knowledge point notes about blockchain -public chain that I took time to sort out during my postgraduate studies at South China Agricultural University . It is only a simple technical science, and does not involve zero-knowledge proofs (NIZK, zk-SNARKs). I want to really understand Zero-knowledge proof, recommended for postgraduate study.

UTXO

       What is UTXO? That is, Unspent Transaction Output. In order to achieve data traceability , the blockchain will record each transaction (TX) in detail in the chain. It looks like the following, which records in detail how many resources flow from where to where .

       For example, in the wine supply chain , Alice supplies Bob with 2 bottles of wine. After that, in order to supply Christal with a bottle of wine, Bob first needs to find the TX_1 in the chain, and prove the validity of this TX_1, and then generate a TX_2 record that Bob supplies Christal with a bottle of wine, and a TX_3 record that Bob supplies to himself 1 bottle of wine, and finally destroy TX_1 in the ledger chain.

Merkle tree

       How to ensure that all TX records have not been tampered with? Use Merkle tree to verify; how to prove the validity of a certain TX? Check with Merkle tree . As an example, in the following figure, in order to prove the validity of L2 , we send the nodes circled in green in the figure to the verifier.

       So how does the Merkle tree dynamically add nodes? The principle is as follows. In order to insert orange points , we record the purple points from left to right , and then update the parent node on the path of the purple point , so that the original tree structure will not be destroyed.

       I posted a copy of my own python code here, a node is a database record, the idea is borrowed from https://github.com/jvsteiner/merkletree .

#!/usr/bin/python3
#coding=utf-8
#author: Qingwen Guo, South China Agricultural University

from hashlib import *
from math import log


# 全局定义Hash函数的形式
def hash_function(string):
    string = string.encode('utf-8')
    return sha256(string).hexdigest()


# 默克尔树中的节点
class Node:
    __slots__ = ['lchild', 'rchild', 'parent', 'sibling', 'side', 'value']

    def __init__(self, string):
        self.value = hash_function(string)
        self.lchild = None
        self.rchild = None
        self.parent = None
        self.sibling = None
        self.side = None

    def __repr__(self):
        return self.value


class MerkleTree:
    __slots__ = ['leaves', 'root']

    def __init__(self, strings=[]):
        self.leaves = [Node(string) for string in strings]
        self.root = None

    def build(self):
        if (not self.leaves) or (len(self.leaves) == 0):
            return False
        layer = self.leaves[::]
        while len(layer) != 1:
            layer = self._build(layer)
        self.root = layer[0]
        return True

    def _build(self, layer):
        res, temp = [], None
        if len(layer) % 2 != 0:
            temp = layer.pop(-1)
        for i in range(0, len(layer), 2):
            string = str(layer[i].value) + str(layer[i+1].value)
            node = Node(string)
            node.lchild, node.rchild = layer[i], layer[i+1]
            layer[i].parent, layer[i+1].parent = (node, ) * 2
            layer[i].sibling, layer[i].side, layer[i+1].sibling, layer[i+1].side = layer[i+1], 'L', layer[i], 'R'
            res.append(node)
        if temp:
            res.append(temp)
        return res

    def _get_add_path(self):
        res = []
        node = self.root
        rest_leaves = len(self.leaves)
        if rest_leaves != 0:
            while True:
                rest_leaves = rest_leaves - 2 ** int(log(rest_leaves, 2))
                if rest_leaves == 0:
                    break
                res.append(node.lchild)
                node = node.rchild
        # 若是空树,则不添加任何节点进路径
        if node:
            res.append(node)
        return res

    def add(self, string):
        node = Node(string)
        path = self._get_add_path()
        # 若列表path不存在节点,则直接以node为根节点
        if len(path) == 0:
            self.root = node
        # 若列表path仅有根节点
        elif len(path) == 1:
            p = path.pop(-1)
            string = str(p.value) + str(node.value)
            self.root = Node(string)
            self.root.lchild, self.root.rchild = p, node
            p.parent, node.parent = (self.root, ) * 2
            p.sibling, p.side, node.sibling, node.side = node, 'L', p, 'R'
        else:
            if path[-1].sibling == path[-2]:
                p = path.pop(-1)
                string = str(p.value) + str(node.value)
                new_node = Node(string)
                new_node.lchild, new_node.rchild = p, node
                p.parent, node.parent = (new_node, ) * 2
                p.sibling, p.side, node.sibling, node.side = node, 'L', p, 'R'
                node = new_node
            while len(path) != 0:
                p = path.pop(-1)
                string = str(p.value) + str(node.value)
                p.parent.value = hash_function(string)
                p.parent.rchild = node
                node.parent = p.parent
                p.sibling, p.side, node.sibling, node.side = node, 'L', p, 'R'
                node = node.parent
        self.leaves.append(node)

    def get_chain(self, i):
        res = []
        if 0 <= i and i <= len(self.leaves):
            node = self.leaves[i]
            while node != self.root:
                res.append((node.sibling.value, node.sibling.side))
                node = node.parent
        return res

    def check_chain(self, chain, string):
        res = hash_function(string)
        for v in chain:
            if v[1] == 'L':
                res = hash_function(v[0] + res)
            elif v[1] == 'R':
                res = hash_function(res + v[0])
            else:
                return False
        return res == self.root.value

    def clear(self):
        self.root = None
        for leaf in self.leaves:
            leaf.parent, leaf.sibling, leaf.side, leaf.value = (None, ) * 4


letters = "abcdefghijklmnopqrstuvwxyz"


for i in range(1, len(letters)+1):
    tree = MerkleTree([c for c in letters[:i]])
    tree.build()
    test1 = tree.root.value
    
    tree = MerkleTree()
    for c in letters[:i]:
        tree.add(c)
    test2 = tree.root.value

    if test1 != test2:
        print("Build Error!")


for i in range(1, len(letters)+1):
    tree1 = MerkleTree([c for c in letters[:i]])
    tree1.build()

    tree2 = MerkleTree([c for c in letters[:i]])
    tree2.build()

    for j in range(0, i):
        chain = tree1.get_chain(j)

        if not tree2.check_chain(chain, letters[j]):
            print("Chain Error!")

Double spend transaction

       How to prevent a TX from being used multiple times requires each accounting node to maintain a UTXO transaction pool to record which TXs are still valid.

Proof of Work PoW

       Why do you need a mining algorithm ? This article gives a good example, in this article I recreate a business scenario to better illustrate its role. In the wine supply chain , if the wine provided by Bob to Christal is mixed with water, when the regulatory authorities hold Bob accountable, Bob may re-forge a long enough chain and falsely claim that the wine did not come from him, denying other The human ledger chain has been tampered with by hackers . Fortunately, the mining algorithm can effectively deal with this rogue behavior, because even if Bob recreates a new chain, his computing power will never catch up with the longest chain , and everyone only recognizes the validity of the longest chain.

Private chain and alliance chain

       Although the mining algorithm of the public chain is very useful, it is very cumbersome when it comes to the private chain and the alliance chain, because the actual operation is very slow and wastes resources. To solve this problem, we need to find a better way . any solution? Think about it, what is the algorithm corresponding to the Hash algorithm ? Yes, it is a digital signature (Digital Signature) .

       Each billing node in the network announces its own ( Pk , Sk ) in the form of a self-signed certificate , and the node signs with its own Sk when billing, and uses the corresponding Pk for validity verification when resources flow . Since Bob does not have the Sk of the next bookkeeping node , he is stuck and cannot create a longer ledger chain. Of course, this is just a small skill in engineering. If you want to understand the zero-knowledge proof (NIZK, zk-SNARKs) technology of Ethereum (Ethereum Blockchain), it is recommended to go to graduate school.

postscript

       In the end, I ended with a sentence from the old school song of Tsinghua University, "wareness comes first, literature and art follow ;

Reference

A Python implementation of the Merkle/Hash Tree Algorithm

What exactly are POW and POS mechanisms?

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324440870&siteId=291194637