Вы здесь, потому что, как и я, взволнованы ростом криптовалют. И хотите знать, как работает блокчейн - фундаментальную технологию, лежащую в его основе.

Но понять блокчейн непросто - по крайней мере, не для меня. Я пробирался через тупые видео, следовал руководствам и разочаровывался из-за слишком малого количества примеров.

Мне нравится учиться на практике. Это заставляет меня заниматься предметом на уровне кода, что разжигает любопытство. Если вы сделаете то же самое, в конце этого руководства у вас будет работающий блокчейн с твердым пониманием того, как он работает.

Прежде, чем начать

Помните, что блокчейн – неизменяемая, последовательная цепочка записей, называемых блоками. Они могут содержать транзакции, файлы или любые данные. Важно, что они соединены друг с другом с помощью хэша.

Если вы не знаете, что такое хэш, вот объяснение.

На кого рассчитано это руководство? Вам должно быть комфортно читать и писать базовый код на Python, а также иметь некоторое представление о том, как работают HTTP-запросы, поскольку мы будем общаться с нашей цепочкой блоков через HTTP.

Что мне нужно? Убедитесь, что установлен Python 3.6 + (вместе с pip). Вам также потребуется установить Flask и замечательную библиотеку requests:

 pip install Flask==0.12.2 requests==2.18.4 

Вам также понадобится HTTP-клиент, например Postman или cURL. Но все подойдет.

Исходный код доступен здесь.

Шаг 1. Создание блокчейна

Откройте свой любимый текстовый редактор или IDE, лично я люблю PyCharm. Создайте новый файл с именем blockchain.py. Мы будем использовать только один файл, но, если вы потеряетесь, всегда можете обратиться к исходному коду.

Представление блокчейна

Мы создадим класс Blockchain, конструктор которого создает начальный пустой список (для хранения нашей цепочки блоков), другой - для хранения транзакций. Вот план нашего класса:

class Blockchain(object):
    def __init__(self):
        self.chain = []
        self.current_transactions = []
        
    def new_block(self):
        # Creates a new Block and adds it to the chain
        pass
    
    def new_transaction(self):
        # Adds a new transaction to the list of transactions
        pass
    
    @staticmethod
    def hash(block):
        # Hashes a Block
        pass

    @property
    def last_block(self):
        # Returns the last Block in the chain
        pass

Наш класс Blockchain отвечает за управление цепочкой. Он будет хранить транзакции и иметь несколько вспомогательных методов для добавления новых блоков в цепочку. Давайте начнем конкретизировать некоторые методы.

Как выглядит блок?

Каждый блок имеет индекс, временную метку (во времени Unix), список транзакций, доказательство (подробнее об этом позже) и хэш предыдущего блока.

Вот пример того, как выглядит отдельный блок:

block = {
    'index': 1,
    'timestamp': 1506057125.900785,
    'transactions': [
        {
            'sender': "8527147fe1f5426f9dd545de4b27ee00",
            'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
            'amount': 5,
        }
    ],
    'proof': 324984774000,
    'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}

На этом этапе идея цепочки должна стать очевидной - каждый новый блок содержит в себе хэш предыдущего блока. Это очень важно, потому что это то, что обеспечивает неизменяемость блокчейна: если злоумышленник повредил более ранний блок в цепочке, то все последующие блоки будут содержать неправильный хэш.

Есть смысл? Если нет, привыкните - это основная идея, лежащая в основе блокчейна.

Добавление транзакций в блок

Нам понадобится способ добавления транзакций в блок. За это отвечает наш метод new_transaction(), и он довольно прост:

class Blockchain(object):
    ...
    
    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block
        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> The index of the Block that will hold this transaction
        """

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

        return self.last_block['index'] + 1

После добавления транзакции в список он возвращает индекс блока, в который будет добавлена ​​транзакция - следующего блока, который будет добыт. Это будет полезно позже, для пользователя, отправляющего транзакцию.

Создание новых блоков

Когда наш экземпляр Blockchain будет создан, нам нужно будет засеять его генезисным блоком - блоком без предшественников. Нам также нужно будет добавить «доказательство» к нашему генезис-блоку, которое является результатом майнинга (или доказательства работы). Подробнее о майнинге поговорим позже.

Помимо создания генезис-блока в нашем конструкторе, мы также конкретизируем методы для new_block(), new_transaction() и hash():

import hashlib
import json
from time import time


class Blockchain(object):
    def __init__(self):
        self.current_transactions = []
        self.chain = []

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

    def new_block(self, proof, previous_hash=None):
        """
        Create a new Block in the Blockchain
        :param proof: <int> The proof given by the Proof of Work algorithm
        :param previous_hash: (Optional) <str> Hash of previous Block
        :return: <dict> New Block
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

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

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block
        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> The index of the Block that will hold this transaction
        """
        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })

        return self.last_block['index'] + 1

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

    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block
        :param block: <dict> Block
        :return: <str>
        """

        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()
  

Вышеупомянутое должно быть понятно - я добавил несколько комментариев и строк документации. Мы почти закончили с представлением нашей цепочки блоков. Но вам должно быть интересно, как создаются или добываются новые блоки.

Понимание доказательства работы

Алгоритм Proof of Work (PoW) - это то, как новые блоки создаются или добываются в цепочке блоков. Цель PoW - найти число, которое решает проблему. Число должно быть трудно найти, но легко проверить - с точки зрения вычислений - кем угодно в сети. Это основная идея Proof of Work.

Мы рассмотрим очень простой пример, который поможет понять это.

Давайте решим, что хэш одного целого числа, x умноженного на другое, y должен заканчиваться на 0. Так, hash(x * y) = ac23dc...0. И для этого упрощенного примера давайте примем x = 5. Реализация этого в Python:

from hashlib import sha256
x = 5
y = 0  # We don't know what y should be yet...
while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
    y += 1
print(f'The solution is y = {y}')

Решение здесь y = 21. Поскольку созданный хэш заканчивается на 0:

hash(5 * 21) = 1253e9373e...5e3600155e860

В Биткойне алгоритм Proof of Work называется Hashcash. И он не слишком отличается от нашего базового примера выше. Это алгоритм, который майнеры пытаются решить, чтобы создать новый блок. Как правило, сложность определяется количеством символов, которые ищутся в строке. Затем майнеры награждаются за свое решение получением монеты - в транзакции.

Сеть способна легко проверить их решение.

Внедрение базового доказательства работы

Давайте реализуем аналогичный алгоритм для нашего блокчейна. Наше правило будет аналогично приведенному выше примеру:

Найдите число p, при хешировании которого с решением предыдущего блока получается хэш с 4 ведущими 0.

import hashlib
import json

from time import time
from uuid import uuid4


class Blockchain(object):
    ...
        
    def proof_of_work(self, last_proof):
        """
        Simple Proof of Work Algorithm:
         - Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
         - p is the previous proof, and p' is the new proof
        :param last_proof: <int>
        :return: <int>
        """

        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        return proof

    @staticmethod
    def valid_proof(last_proof, proof):
        """
        Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
        :param last_proof: <int> Previous Proof
        :param proof: <int> Current Proof
        :return: <bool> True if correct, False if not.
        """

        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == "0000"

Чтобы отрегулировать сложность алгоритма, мы можем изменить количество ведущих нулей. Но 4 достаточно. Вы обнаружите, что добавление одного ведущего нуля значительно увеличивает время, необходимое для поиска решения.

Наш класс почти готов, и мы готовы начать с ним взаимодействовать с помощью HTTP-запросов.

Шаг 2: Блокчейн как API

Мы собираемся использовать Python Flask Framework. Это фреймворк, который упрощает сопоставление конечных точек с функциями Python. Это позволяет нам общаться с нашей цепочкой блоков через Интернет, используя HTTP-запросы.

Мы создадим три метода:

/transactions/new создать новую транзакцию в блоке

/mine чтобы сказать нашему серверу майнить новый блок.

/chain чтобы вернуть полную цепочку блоков.

Настройка Flask

Наш «сервер» сформирует единый узел в нашей сети блокчейнов. Создадим шаблонный код:

import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4

from flask import Flask


class Blockchain(object):
    ...


# Instantiate our Node
app = Flask(__name__)

# Generate a globally unique address for this node
node_identifier = str(uuid4()).replace('-', '')

# Instantiate the Blockchain
blockchain = Blockchain()


@app.route('/mine', methods=['GET'])
def mine():
    return "We'll mine a new Block"
  
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    return "We'll add a new transaction"

@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Краткое объяснение того, что мы добавили выше:

Строка 15: создает экземпляр нашего узла. Узнайте больше о Flask здесь.

Строка 18: создание случайного имени для нашего узла.

Строка 21: создание экземпляра нашего Blockchain класса.

Строка 24–26: создание /mine конечной точки, которая является GET-запросом.

Строка 28–30: создание /transactions/new конечную точку, которая является POST-запросом, поскольку мы будем отправлять ей данные.

Строка 32–38: Создайте /chain конечную точку, которая возвращает полную цепочку блоков.

Строка 40–41: запускает сервер на порту 5000.

Конечная точка транзакций

Так будет выглядеть запрос на транзакцию. Это то, что пользователь отправляет на сервер:

{
 "sender": "my address",
 "recipient": "someone else's address",
 "amount": 5
}

Поскольку у нас уже есть метод класса для добавления транзакций в блок, остальное легко. Напишем функцию добавления транзакций:

import hashlib
import json
from textwrap import dedent
from time import time
from uuid import uuid4

from flask import Flask, jsonify, request

...

@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    values = request.get_json()

    # Check that the required fields are in the POST'ed data
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return 'Missing values', 400

    # Create a new Transaction
    index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])

    response = {'message': f'Transaction will be added to Block {index}'}
    return jsonify(response), 201

Конечная точка майнинга

Наша конечная точка майнинга - это место, где происходит волшебство, и это легко. Она должна делать три вещи:

1.      Рассчитать Proof of Work

2.      Наградить майнера (нас), добавив транзакцию, дающую нам 1 монету.

3.      Создать новый блок, добавив его в цепочку

import hashlib
import json

from time import time
from uuid import uuid4

from flask import Flask, jsonify, request

...

@app.route('/mine', methods=['GET'])
def mine():
    # 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=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 jsonify(response), 200

Обратите внимание, что получателем добытого блока является адрес нашего узла. И большая часть того, что мы здесь сделали, - это просто взаимодействие с методами нашего класса Blockchain. На этом мы закончили и можем начать взаимодействие с нашей цепочкой блоков.

Шаг 3: Взаимодействие с нашей цепочкой блоков

Вы можете использовать старый простой cURL или Postman для взаимодействия с нашим API по сети.

Запустите сервер:

$ python blockchain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Попробуем добыть блок, запросив http://localhost:5000/mine:

Используем Postman отправить GET-запрос
Используем Postman отправить GET-запрос

Давайте создадим новую транзакцию, сделав POST-запрос к http://localhost:5000/transactions/new, содержащему нашу структуру транзакции:

Используем Postman отправить POST-запрос
Используем Postman отправить POST-запрос

Если вы не используете Postman, вы можете сделать аналогичный запрос с помощью cURL:

$ curl -X POST -H "Content-Type: application/json" -d '{
 "sender": "d4ee26eee15148ee92c6cd394edd974e",
 "recipient": "someone-other-address",
 "amount": 5
}' "http://localhost:5000/transactions/new"

Я перезапустил свой сервер и добыл два блока, всего получилось 3. Давайте проверим всю цепочку, запросив http://localhost:5000/chain:

{
  "chain": [
    {
      "index": 1,
      "previous_hash": 1,
      "proof": 100,
      "timestamp": 1506280650.770839,
      "transactions": []
    },
    {
      "index": 2,
      "previous_hash": "c099bc...bfb7",
      "proof": 35293,
      "timestamp": 1506280664.717925,
      "transactions": [
        {
          "amount": 1,
          "recipient": "8bbcb347e0634905b0cac7955bae152b",
          "sender": "0"
        }
      ]
    },
    {
      "index": 3,
      "previous_hash": "eff91a...10f2",
      "proof": 35089,
      "timestamp": 1506280666.1086972,
      "transactions": [
        {
          "amount": 1,
          "recipient": "8bbcb347e0634905b0cac7955bae152b",
          "sender": "0"
        }
      ]
    }
  ],
  "length": 3
}

Шаг 4: консенсус

Это очень круто. У нас есть базовая цепочка блоков, которая принимает транзакции и позволяет нам добывать новые блоки. Но весь смысл блокчейна в том, что они должны быть децентрализованными . И если они децентрализованы, как мы можем гарантировать, что все они отражают одну и ту же цепочку? Это называется проблемой консенсуса, и нам придется реализовать алгоритм консенсуса, если мы хотим, чтобы в нашей сети было более одного узла.

Регистрация новых узлов

Прежде чем мы сможем реализовать алгоритм консенсуса, нам нужен способ сообщить узлу о соседних узлах в сети. Каждый узел в нашей сети должен вести реестр других узлов в сети. Таким образом, нам понадобится еще несколько конечных точек:

/nodes/register принять список новых узлов в виде URL-адресов.

/nodes/resolve для реализации нашего алгоритма консенсуса, который разрешает любые конфликты, чтобы гарантировать, что узел имеет правильную цепочку.

Нам нужно будет изменить конструктор нашей цепочки блоков и предоставить метод для регистрации узлов:

...
from urllib.parse import urlparse
...


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

    def register_node(self, address):
        """
        Add a new node to the list of nodes
        :param address: <str> Address of node. Eg. 'http://192.168.0.5:5000'
        :return: None
        """

        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

Обратите внимание, что мы использовали set() для хранения списка узлов. Это дешевый способ гарантировать, что добавление новых узлов идемпотентно, то есть независимо от того, сколько раз мы добавляем конкретный узел, он появляется только один раз.

Реализация алгоритма консенсуса

Как уже упоминалось, конфликт возникает, когда один узел имеет цепочку, отличную от другой. Чтобы решить эту проблему, мы примем правило, что самая длинная действительная цепочка является авторитетной. Другими словами, де-факто самая длинная цепочка в сети. Используя этот алгоритм, мы достигаем консенсуса между узлами в нашей сети.

...
import requests


class Blockchain(object)
    ...
    
    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:
            response = requests.get(f'http://{node}/chain')

            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']

                # Check if the length is longer and the chain is valid
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain

        # Replace our chain if we discovered a new, valid chain longer than ours
        if new_chain:
            self.chain = new_chain
            return True

        return False

Первый метод valid_chain() отвечает за проверку правильности цепочки путем обхода каждого блока и проверки как хэша, так и доказательства.

resolve_conflicts() - это метод, который просматривает все наши соседние узлы, загружает их цепочки и проверяет их, используя описанный выше метод. Если найдена допустимая цепочка, длина которой больше нашей, мы заменяем нашу.

Давайте зарегистрируем две конечные точки в нашем API, одну для добавления соседних узлов, а другую для разрешения конфликтов:

@app.route('/nodes/register', methods=['POST'])
def register_nodes():
    values = request.get_json()

    nodes = values.get('nodes')
    if nodes is None:
        return "Error: Please supply a valid list of nodes", 400

    for node in nodes:
        blockchain.register_node(node)

    response = {
        'message': 'New nodes have been added',
        'total_nodes': list(blockchain.nodes),
    }
    return jsonify(response), 201


@app.route('/nodes/resolve', methods=['GET'])
def consensus():
    replaced = blockchain.resolve_conflicts()

    if replaced:
        response = {
            'message': 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response = {
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }

    return jsonify(response), 200

На этом этапе вы можете взять другую машину, если хотите, и развернуть разные узлы в своей сети. Или запустите процессы, используя разные порты на одной машине. Я развернул еще один узел на своей машине, на другом порту, и зарегистрировал его на моем текущем узле. Таким образом, у меня есть два узла: http://localhost:5000 и http://localhost:5001.

Регистрация нового узла
Регистрация нового узла

Затем я добыл несколько новых блоков на узле 2, чтобы цепочка была длиннее. После этого я вызвал /nodes/resolve узел 1, где цепочка была заменена алгоритмом консенсуса:

Алгоритм консенсуса
Алгоритм консенсуса

На этом все ... Соберите вместе друзей, чтобы они помогли протестировать ваш блокчейн.

Надеюсь, это вдохновило вас на создание чего-то нового. Я в восторге от криптовалют, потому что считаю, что блокчейн быстро изменят наши представления об экономике, правительстве и ведении учета.

Комментарии (21)


  1. codecity
    15.10.2021 10:50
    -1

    Ну давайте уже Habracoin!


  1. ITMatika
    15.10.2021 10:52
    +6

    Но понять блокчейн непросто - по крайней мере, не для меня.

    Вернее, понять могут не только лишь все. Не мало, кто может это cделать.


  1. MAXH0
    15.10.2021 11:13

    Извините, конечно, но эта статья уже широко известна в узких кругах и многократно переведена.

    Единственно на что стоит надеяться, это на хорошие хабро-комментарии. Но полагаю, что и то мало шансов. Слишком "детская" реализация...


    1. spooky
      15.10.2021 11:55
      +2

      Как будто сама идея блокчейна это нечто настолько сложное, что описать это в десятке абзацев невозможно.
      Это было сложно придумать, в чем огромная уважуха к создателям.


      1. a-tk
        18.10.2021 13:53

        В десятке? Двух хватило был. Плюс одну картинку.


    1. iroln
      15.10.2021 13:00
      +1

      А как должна выглядеть "не детская" реализация для демонстрации принципа работы технологии?


      1. MAXH0
        17.10.2021 19:08

        Это перевод хорошей статьи 2017 года. С 2017 года много что произошло в блокчейне.
        Я бы хотел видеть что-то новое. Смарт-контракты и консенсус подтверждения доли, например. Пусть даже смарт-контракты придется писать на Brainfuck 


  1. house2008
    15.10.2021 14:15

    Скажите, а кто валидирует правильность транзакций? Допустим я разверну ноду, модифицирую софт таким образом, чтобы свои определенные транзакции без проверки помещались в цепочку. Сами транзакции буду создавать тоже своим софтом в котором буду пририсовывать дополнительные монеты или тратить больше чем есть на самом деле. Где тот самый source of truth?


    1. spooky
      15.10.2021 15:34
      +2

      Консенсус будет валидировать. В момент появления нового блока с вашей модифицированной транзакцией будет сформировано 2 блока, один вами, один кем-то еще.
      Они оба будут иметь одинаковый номер. Появится две цепочки. Если в вашей будет двойное расходование, то новые блоки над вашим будут либо не создаваться, либо создаваться медленнее. Образуются две цепочки. Согласно правилам используемого блокчейна спустя некоторое количество блоков (в биткоине например 6) та, что короче будет отброшена, а все транзакции вернутся в мемпул. А ваша, которая уже окажется некорректной, будет просто удалена из него.


      1. house2008
        15.10.2021 15:55

        Спасибо. Именно то, что хотел услышать.


  1. kuzzzov
    15.10.2021 14:22
    +2

    На мой взгляд, в блокчейне самым спорным моментом является майнинг. Огромные вычислительные ресурсы и уйма электроэнергии тратятся на бессмысленные вычисления.

    Почему бы не изменить алгоритм Proof of Work таким образом, чтобы вычисления стали полезными?

    Ведь существует множество проектов добровольных вычислений, участники которых предоставляют ресурсы своего ПК для решения научных задач, например Folding@Home моделирует свертывание белков.

    Почему бы не объединить первое со вторым? Тогда пользователи будут не просто майнить крипту, но и помогать в решении научных задач.


    1. pfffffffffffff
      15.10.2021 14:35
      -1

      А вы адаптируйте каждую полезную задачу чтобы она могла в proof of work. К тому же есть не только PoW алгоритм


    1. spooky
      15.10.2021 15:35
      +2

      Потому что SHA256 это не решение задачи, а перебор.


  1. VPryadchenko
    15.10.2021 15:04

    Получается, каждая нода должна иметь публичный ip?


  1. savostin
    16.10.2021 18:05

    Никогда не понимал, и из этой статьи не понял, зачем нужно доказательство работы?


    1. spooky
      16.10.2021 22:22

      Чтобы реализовать распределенный одноранговый сервер меток времени, мы используем
      схему «доказательства работы», подобную системе Hashcash Адама Бека [6]. Суть
      заключается в поиске такого значения, чей хэш (например, SHA-256) начинался бы с
      некоторого числа нулевых битов. Требуется выполнить объем работы, экспоненциально
      зависящий от числа нулей, но для проверки найденного значения достаточно вычислить
      лишь один хэш
      В нашем сервере меток времени поиск значения с нужным хэшем происходит путем
      перебора значения итерируемого поля-добавки (nonce) в блоке данных. Как только блок,
      удовлетворяющий условию, найден, его содержимое нельзя изменить, не выполнив заново
      всей работы. И если он не является последним в цепочке, эта работа включает в себя и
      перевычисление всех блоков, следующих за ним.

      Из статьи Сатоси Накамото


      1. savostin
        16.10.2021 22:28

        Простите, все равно не понял. Почему нельзя без него?


        1. spooky
          16.10.2021 23:00

          Предположим вы хотите скомпрометировать блокчейн и изменить транзакцию, которая находится в минус 10м блоке от текущего. Для этого вам надо создать сначала -10й блок, проведя работу по поиску подходящего хеша начинающегося с нужного количества 0, затем -9й, т.к. он включает в себя полученный хеш от -10го и т.д. При создании каждого нового блока вам его надо заново смайнить. Невозможно предположить какой будет хеш от новых данных.


          1. savostin
            16.10.2021 23:23

            Почему для гарантии неподдельности цепочки недостаточно хеша предыдущего блока?


            1. spooky
              16.10.2021 23:37
              +1

              Потому что теоретически заново пересчитать 1-2-3 блока можно


  1. bolnikh
    17.10.2021 10:31

    Я правильно понял, что в данной реализации

    1) могут теряться транзакции? например есть 2 узла, на 1м узле сформирован блок с транзакцией 1, на 2м - с транзакцией 2. Длины блокчейна одинаковые и консенсуса не будет. далее 1й узел формирует блок с транзакцией 3. Теперь блокчейн на 1м узле длиннее чем на 2м и перезапишет блокчейн на 2м, что означает потерю транзакции 2.

    2) можно полностью переписать транзакции в блоках не выполняя доказательства работы? Доказательство работы зависит только от одного параметра proof в предыдущем блоке и никак не зависит от транзакций и хеша предыдущего блока, поэтому транзакции можно менять как угодно.