Как создать блокчейн: Как сделать свой блокчейн. Часть 1 — Создание, Хранение, Синхронизация, Отображение, Майнинг и Доказательная работа

Содержание

Как сделать свой блокчейн. Часть 1 — Создание, Хранение, Синхронизация, Отображение, Майнинг и Доказательная работа

Доброго всем! Мы тут потихоньку начали исследовать новое совсем для нас направление для обучения — блокчейны и нашли то, что оказалось интересным в рамках нашего курса по Python, в том числе. Чем, собственно, и хотим поделиться с вами.
Я могу узнать, когда у меня появился первый Bitcoin, из истории кошелька в моем аккаунте на Coinbase — входящая транзакция в 2012 году в подарок за регистрацию. Bitcoin в то время стоил около 6.50$. Если бы я сохранил те 0.1 BTC, на момент написания статьи это бы уже стоило более 500$. Если кому-то интересно, я продал их, когда Bitcoin стоил 2000$. Так что я получил только 200$ вместо ныне возможных 550$. Не стоило торопиться.

О существовании Bitcoin я знал, но особо не интересовался. Я видел взлеты и падения курса $/BTC. Я видел, как люди говорят, что за ним будущее, а видел статьи о его полной бессмысленности. Но личного мнения у меня не было — просто наблюдал со стороны.


Точно так же я почти не следил за блокчейнами. Но в последнее время мой отец несколько раз упоминал, что на CNBC и Bloomberg, которые он смотрит по утрам, часто рассказывают о блокчейнах, и он понятия не имеет, что это.

И тогда я внезапно понял, что нужно чуть глубже разобраться в этой теме. И начал с “исследования” — прочитал огромное количество статей в интернете, объясняющую их суть. Некоторые были хорошие, некоторые плохие, некоторые глубокие, а некоторые очень поверхностные.

Чтения оказалось недостаточно, а если существует одна вещь, которую я знаю наверняка, так это то, что чтение не объяснит и сотой доли того, что объяснит программирование. И так я понял, что стоит написать свой собственный локальный блокчейн.

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

Я пишу пост по нескольким причинам: 1) Чтобы люди, прочитавшие его, смогли узнать больше о блокчейнах; 2) Чтобы я смог понять больше, объяснив код, а не просто написав его.
В этом посте я покажу способ хранения данных блокчейна и генерации начального блока, синхронизацию узла с локальными данными блокчейна, отображение блокчейна (что впоследствии будет использоваться для синхронизации с другими узлами), а затем, майнинг и создание валидных новых блоков. В первом посте не будет никаких других узлов. Никаких кошельков, пиров, важных данных. О них поговорим позднее.

В двух словах

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

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

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

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

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

Если хотите изучить код, посмотрите ветку part 1 на Github. Смело присылайте мне любые вопросы, комментарии, правки и похвалы (если вы в настроении сделать что-то особо хорошее), или просто пишите в твиттер.

Шаг 1 — Классы и Файлы

Первый шаг — написание класса, обрабатывающего блоки при запуске узлов. Я назову этот класс Block. Честно говоря, много делать не придется. В функции __init__ мы будем верить, что вся необходимая информация уже представлена в словаре. Для производственного блокчейна — это не самое мудрое решение, но подходит в качестве примера, потому что код пишу только я. Также я напишу метод, запаковывающий важную информацию блока в словарь, а после заведу более удобный способ для отображения информации блока при его печати в терминал.

class Block(object):
  def __init__(self, dictionary):
  '''
    We're looking for index, timestamp, data, prev_hash, nonce
  '''
  for k, v in dictionary.items():
    setattr(self, k, v)
  if not hasattr(self, 'hash'): #in creating the first block, needs to be removed in future
    self.
hash = self.create_self_hash() def __dict__(self): info = {} info['index'] = str(self.index) info['timestamp'] = str(self.timestamp) info['prev_hash'] = str(self.prev_hash) info['hash'] = str(self.hash) info['data'] = str(self.data) return info def __str__(self): return "Block<prev_hash: %s,hash: %s>" % (self.prev_hash, self.hash)

Чтобы создать первый блок, запустим этот простой код:
def create_first_block():
  # index zero and arbitrary previous hash
  block_data = {}
  block_data['index'] = 0
  block_data['timestamp'] = date.datetime.now()
  block_data['data'] = 'First block data'
  block_data['prev_hash'] = None
  block = Block(block_data)
  return block

Отлично. Последний вопрос в этой части — где хранить данные в файловой системе. Это необходимо, если мы не хотим потерять локальные данные блока при отключении узла.
Я назову папку с данными ‘chaindata’, в какой-то степени подражая схеме папок Etherium Mist. Каждому блоку теперь присвоен отдельный файл, названный по его индексу. Нужно убедиться, что имена файлов содержат в начале достаточное количество нулей, чтобы блоки перечислялись по порядку.

С учетом кода выше, нужно написать следующее для создание первого блока:

#check if chaindata folder exists.
chaindata_dir = 'chaindata'
if not os.path.exists(chaindata_dir):
  #make chaindata dir
  os.mkdir(chaindata_dir)
  #check if dir is empty from just creation, or empty before
if os.listdir(chaindata_dir) == []:
  #create first block
  first_block = create_first_block()
  first_block.self_save()

Шаг 2 — Синхронизация блокчейна, локально

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

def sync():
  node_blocks = []
  #We're assuming that the folder and at least initial block exists
  chaindata_dir = 'chaindata'
  if os.path.exists(chaindata_dir):
    for filename in os.listdir(chaindata_dir):
      if filename.endswith('.json'): #.DS_Store sometimes screws things up
        filepath = '%s/%s' % (chaindata_dir, filename)
        with open(filepath, 'r') as block_file:
          block_info = json.load(block_file)
          block_object = Block(block_info) #since we can init a Block object with just a dict
          node_blocks.append(block_object)
return node_blocks

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

Шаг 3 — Отображение блокчейна

Теперь наш блокчейн находится в памяти, и поэтому я хочу отобразить цепь в браузере.

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

Для этого я использую Flask — у него низкий порог вхождения, и я решил, что он подходит для наших целей.

Ниже представлен код для отображения json блокчейна. Я проигнорирую импорты для экономии места.

node = Flask(__name__)

node_blocks = sync.sync() #inital blocks that are synced

@node.route('/blockchain.json', methods=['GET'])
def blockchain():
  '''
  Shoots back the blockchain, which in our case, is a json list of hashes
  with the block information which is:
  index
  timestamp
  data
  hash
  prev_hash
  '''
  node_blocks = sync.sync() #regrab the nodes if they've changed
  # Convert our blocks into dictionaries
  # so we can send them as json objects later
  python_blocks = []
  for block in node_blocks:
    python_blocks.
append(block.__dict__()) json_blocks = json.dumps(python_blocks) return json_blocks if __name__ == '__main__': node.run()

Запустите этот код, зайдите на localhost:3000/blockchain.json и увидите текущий блок.

Шаг 4 — “Майнинг”, также известный как создание блока

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

Сатоши описывает это следующим образом в Bitcoin whitepaper. Учтите, что “timestamp сервер” назван “узлом”.

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

Скриншот изображения, прикрепленного под описанием:

Основная идея раздела — при необходимости соединить блоки, мы создаем хэш информации о новом блоке, включая время создания блока, хэш предыдущего блока и информацию в самом блоке. Я буду называть всю эту информацию “хедером” блока. Таким образом, мы можем проверить корректность блока, посчитав все хэши перед ним, подтвердив последовательность.

В данном случае хедер, который я создаю, объединяет значения строки в одну огромную строку. Я включил следующие данные:

  1. Индекс, показывающий каким по счету является блок;
  2. Хэш предыдущего блока;
  3. Данные — просто случайные строки. Для bitcoin они называются Merkle root и содержат информацию о транзакциях;
  4. Timestamp майнинга этого блока.
def generate_header(index, prev_hash, data, timestamp):
  return str(index) + prev_hash + data + str(timestamp)

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

Хедер Bitcoin значительно сложнее объединения строк. Он использует хэши данных и времени и завязан на то, как данные расположены в памяти. Но в нашем случае объединения строк достаточно.

Теперь у нас есть хедер и можно вычислить валидность хэша. Я буду использовать метод, отличающийся от метода Bitcoin, но все равно запущу хедер блока через функцию sha256.

def calculate_hash(index, prev_hash, data, timestamp, nonce):
  header_string = generate_header(index, prev_hash, data, timestamp, nonce)
  sha = hashlib.sha256()
  sha.update(header_string)
  return sha.hexdigest()

Для майнинга блока мы используем функцию выше, чтобы получить хэш, положить его в новый блок и сохранить этот блок в директории chaindata.
node_blocks = sync. sync()

def mine(last_block):
  index = int(last_block.index) + 1
  timestamp = date.datetime.now()
  data = "I block #%s" % (int(last_block.index) + 1) #random string for now, not transactions
  prev_hash = last_block.hash
  block_hash = calculate_hash(index, prev_hash, data, timestamp)

  block_data = {}
  block_data['index'] = int(last_block.index) + 1
  block_data['timestamp'] = date.datetime.now()
  block_data['data'] = "I block #%s" % last_block.index
  block_data['prev_hash'] = last_block.hash
  block_data['hash'] = block_hash
  return Block(block_data)

def save_block(block):
  chaindata_dir = 'chaindata'
  filename = '%s/%s.json' % (chaindata_dir, block.index)
  with open(filename, 'w') as block_file:
    print new_block.__dict__()
    json.dump(block.__dict__(), block_file)

if __name__ == '__main__':
  last_block = node_blocks[-1]
  new_block = mine(last_block)
  save_block(new_block)

Готово! Но при таком типе создания блока кто угодно с самым быстрым CPU сможет создавать самые длинные цепи, которые другие узлы посчитают корректными. Нужен способ снизить скорость создания блока и подтверждение до перехода к следующему блоку.

Шаг 5 — Доказательство выполнения работы

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

Способ сделать это — установить требования к структуре хэша блока. Как и в случае с bitcoin, необходимо убедиться, что хэш начинается с определенного количества нулей, перед тем, как перейти к следующему. А для этого нужно добавить в хедер дополнительную информацию — случайно перебираемое число (nonce).

def generate_header(index, prev_hash, data, timestamp, nonce):
  return str(index) + prev_hash + data + str(timestamp) + str(nonce)

Теперь функция майнинга настроена для создания хэша, но если хэш блока не содержит достаточного количества нулей, мы увеличиваем значение nonce, создаем новый хедер, вычисляем новый хэш и проверяем хватает ли нулей.
NUM_ZEROS = 4

def mine(last_block):
  index = int(last_block.index) + 1
  timestamp = date.datetime.now()
  data = "I block #%s" % (int(last_block.index) + 1) #random string for now, not transactions
  prev_hash = last_block.hash
  nonce = 0

  block_hash = calculate_hash(index, prev_hash, data, timestamp, nonce)
  while str(block_hash[0:NUM_ZEROS]) != '0' * NUM_ZEROS:
    nonce += 1
    block_hash = calculate_hash(index, prev_hash, data, timestamp, nonce)
  block_data = {}
  block_data['index'] = int(last_block.index) + 1
  block_data['timestamp'] = date.datetime.now()
  block_data['data'] = "I block #%s" % last_block.index
  block_data['prev_hash'] = last_block.hash
  block_data['hash'] = block_hash
  block_data['nonce'] = nonce
  return Block(block_data)

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

Заключение

На этом все! Пока что. Осталось еще много вопросов и фичей в блокчейнах, которые я не объяснил.

Например, как задействовать другие узлы? Как узлы передают данные, когда включаются в блок? Существуют ли иные способы хранения данных кроме огромных строк данных?
Ответы на эти вопросы можно будет найти в следующих частях этой серии постов, как только я сам найду на них ответы. Пожелания по содержанию можно писать мне в твиттер, в комментарии к посту или через форму обратной связи!

Спасибо моей сестре Саре за уточняющие вопросы о блокчейнах и помощь в редактировании поста!

THE END

Комментарии, вопросы, как всегда, приветствуются и тут, и на дне открытых дверей.

Как запустить свой блокчейн: выбираем движок

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

Проектирование и запуск блокчейна имеют свои нюансы. Их можно легко упустить при планировании, если вы неверно оценили объем и сложность задачи.

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

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

Блокчейн с нуля

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

Написание с нуля кода блокчейн-ноды напоминает создание собственной базы данных с механизмом надежной сетевой репликации. Если вы поищете, сколько таких БД было создано за последние десятилетия, то найдете максимум сотню проектов. Огромной долей рынка владеют всего несколько компаний (Oracle, MS SQL Server, MySQL, PostgreSQL), а разработчики ядра таких систем ценятся крайне высоко.

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

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

По опыту нашей компании, бизнес-заказчики редко выбирают этот путь. Создание своего блокчейна — это задача для группы исследователей, энтузиастов, которые могут себе позволить работать свободно, не имея жестких сроков и бизнес-плана. Такая команда должна иметь возможность свободно исследовать любой встретившийся вопрос, не сильно заботясь о сроках сдачи проектов. На текущий момент работа над такими проектами, как биткоин и Ethereum, производится независимыми разработчиками по всему миру, без жестких дедлайнов. Внешнее давление бизнес-факторов может сыграть с вашим проектом злую шутку, заставив быстрее решать проблемы, не продумав последствия.

Готовые блокчейн-движки

Я намеренно назвал раздел «движки», так как этот термин в области ПО часто используется для обозначения комплексов разнопланового ПО, предназначенного для решения конкретной задачи. Например, «поисковый движок» или «графический движок» — это не только код, но и вспомогательное ПО, дополнительные утилиты, описания алгоритмов и многое другое. Учитывая существование нескольких основных ядер блокчейнов, на базе которых построены уже существующие сети, будет удобно называть их движками (например, «построен на движке Ethereum»).

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

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

Ethereum

Этот комплекс ПО построен на базе ядра публичного блокчейна Ethereum. Публичный Ethereum использует консенсус типа Proof-of-Work, а его многочисленные тестовые сети — различные виды Proof-of-Authority и Proof-of-Stake консенсусов. ПО отвечает самым строгим критериям безопасности, проверено в десятках реально работающих сетей и, на мой взгляд, является наиболее развитым для создания блокчейнов с любыми видами консенсусов и полноценными, многофункциональными смарт-контрактами.

Нужно отметить роль проекта POA Network, чьи разработчики проделали огромную работу и запустили уже несколько быстрых и надежных сетей. POA Network существенно быстрее оригинального Ethereum, но при этом обладает той же стойкостью и универсальностью для заключения любых сделок, а роль валидаторов (майнеров) исполняют компьютеры, честная работа которых заверяется юридически. Эту сеть можно считать эталоном для запуска корпоративных блокчейнов на базе Ethereum.

Код блокчейн-ноды и консенсус

Существуют две основных имплементации кода ноды Ethereum: на языке Rust (код, названия: poa-parity (старое) или openethereum(новое)) и на Go (код, название: geth).

На момент написания при построении PoA-сети на geth (Go) вам будет доступен только консенсус Clique — это простейший и небезопасный протокол без финализации, который можно использовать только в тестовых целях.

Консенсус, реализованный в poa-parity (Rust), состоит из двух алгоритмов: schedule валидаторов Aura и finality gadget GRANDPA. Именно этот вариант, проверенный и безопасный, работает в POA-сетях на базе Ethereum. POA Network работают также над имплементацией перспективного BFT-консенсуса HoneyBadger.

Отдельного упоминания заслуживает новая блокчейн-нода Nethermind, написанная на C# для платформы .NET Core. Она полностью поддерживает Ethereum, большое число операционных систем и является отличным выбором для компаний, которые используют .NET Core.

Смарт-контракты и управление сетью

POA Ethereum использует виртуальную машину EVM и смарт-контракты, которые лучше всего писать на языке Solidity. EVM давно стала стандартом для виртуальных машин с большим количеством готового кода и паттернов разработки. Код контрактов под EVM отвечает за большие суммы криптовалюты, и любая найденная уязвимость вызывает мощную реакцию сообщества и СМИ, поэтому безопасность контрактов EVM на текущий момент крайне высока.

Управление списком валидаторов осуществляется посредством смарт-контрактов — это потрясающе удобно. Можно оперировать одним или несколькими токенами или вообще избавиться от них. Можно сделать процедуру добавления валидаторов гибкой или максимально упростить, добавив «всемогущий» аккаунт. Мощь этой схемы в том, что буквально один разработчик контрактов может создать полную экономику сети на одной платформе с высочайшим уровнем безопасности и переносимости, реализовав сразу и управление сетью, и логику сделок, и другие свойства.

Дополнительное ПО

С Ethereum можно использовать JavaScript-библиотеку web3.js, вне зависимости от консенсуса, валидаторов и ее расположения.

Для POA Ethereum существует репозитарий для автоматизации операций по развертыванию готовой сети — deployment-playbooks.

Если вы планируете запускать POA Ethereum, используйте эту инструкцию. Она проведет вас от создания ключей валидаторов к запуску первых нод, развертыванию системных контрактов и запуску интерфейса валидаторов и обозревателя блоков.

Готовая POA-сеть Ethereum присутствует в AWS, но я все же рекомендую контролировать запуск своими руками. Вы должны понимать, какие сервисы вы запускаете и как они работают.

EOS и его форки

Вторым по гарантиям работоспособности и безопасности будет EOS. “OS” в его названии появилась не случайно.

EOS можно запустить в качестве отдельной сети, в PoS- или PoA-варианте. Как и Ethereum, это ПО уже проверено в бою, обладает высокой безопасностью и функционалом, который позволяет запустить собственный блокчейн со смарт-контрактами для автоматизации любых сделок

Если Ethereum имеет простую систему адресов, то в EOS сразу же используется иерархическая система аккаунтов и права на различные действия. Все это делает EOS похожей по дизайну на операционную систему — «программу для запуска других программ».

В качестве межкорпоративной платформы EOS позволяет из коробки получить удобную систему управления аккаунтами и быстрый консенсус, а также легко интегрировать практически любой функционал при помощи плагинов на C++ и смарт-контрактов на C++/WebAssembly (например, можно добавить другую криптографию).

Дизайн консенсуса в EOS и быстрые блоки позволяют достичь очень быстрого времени ответа пользователю, что крайне важно для построения децентрализованных приложений со сложным функционалом (например, проекты Cyberway, Golos.io или соцсеть Commun). Cyberway недавно произвел сложнейшую миграцию всей бизнес-логики из предыдущего блокчейна прозрачно для пользователей, что лишний раз доказывает гибкость и универсальность EOS.

Код блокчейн-ноды и консенсус

Код EOS написан на C++ и развивался на основе опыта, полученного разработчиками при работе над движками Graphene, Bitshares, Steemit. Используется собственный вариант DPoS-консенсуса.

Сейчас почти все проекты, использующие DPoS, строят свои алгоритмы очень похожим на EOS образом: это аккаунты, «голосующие» балансом токена за топ валидаторов. Валидаторы подписывают блоки по одиночке, но каждый в назначенный квант времени, согласно расписанию. Затем они коллективно фиксируют так называемый Last Irreversible Block (LIB), на котором собирается 2/3 + 1 подписей от валидаторов.

Многие форки EOS пытаются улучшить это консенсус. Например, наш вариант Haya использует для фиксации LIB другой finality gadget — RANDPA, чтобы достичь времени финальности в 2-3 секунды.

Переход к корпоративному POA-консенсусу не вызывает затруднений, так как список валидаторов управляется системными смарт-контрактами.

Смарт-контракты и управление сетью

Смарт-контракты в EOS используют модифицированную виртуальную машину WebAssembly, обычно пишутся на языке C++ и могут создаваться и использоваться любым аккаунтом. Писать смарт-контракты не сложно, во многом они перекликаются с Solidity.

В EOS, как и в POA Ethereum, управление сетью, основной токен (или токены) и типы транзакций можно реализовать в системных смарт-контрактаx (вот, например, системный токен). Интересной особенностью контрактов EOS является использование абстракции table для хранения данных контракта. В Ethereum в основном используется mapping (ассоциативный массив).

Еще одна особенность смарт-контрактов в EOS — upgradeability. Владелец контракта может заменить его, обновив логику или исправив ошибку. Это сильно отличается от Ethereum, где неизменность контрактов — важное условие, гарантирующее, что логика контракта никогда уже не будет изменена, если не произойдет хардфорк.

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

В EOS возможно организовать «спонсорские» транзакции, оплачиваемые владельцами контракта, а не самими пользователями. Это мощнейшая возможность для привлечения новых пользователей. Вы ведь помните, что «бесплатных» транзакций без потери безопасности в блокчейнах не бывает?

Дополнительное ПО

BOSCore, Telos, Haya и еще десяток форков EOS доказывают, что это ПО интересно большому количеству проектов. Для EOS существует достаточно инструментов, и вам не придется с нуля реализовывать сопутствующее ПО.

Eosjs — аналог web3.js, позволяет работать с контрактами любой сети на базе EOS из браузера и любых приложений.

EOSTracker — обозреватель блоков с открытым кодом и децентрализованными приложениями для голосований за валидаторов.

У EOS нет одного большого и мощного интегратора, как POA Network для Ethereum, поэтому каждый проект строит собственное решение. Тем не менее, основной код ноды стабилен и работает под серьезными нагрузками без сбоев.

Parity Substrate

Substrate создается командой компании Parity. Разработано огромное количество ПО: кошельки, блокчейн-ноды, системы смарт-контрактов, компиляторы, виртуальные машины.

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

Substrate — это часть крупного проекта Polkadot — системы, состоящей из основной цепочки и множества цепочек-шардов с индивидуальной логикой.

Преимущество «подключения» своего блокчейна к Polkadot заключается в возможности ончейн-обмена данными с другими цепочками и возможностью использовать их контракты, аккаунты, токены без дополнительного ПО.

Код блокчейн-ноды и консенсус

Код Substrate написан на языке Rust. На мой взгляд, в структуре Substrate чувствуется большой опыт команды по созданию блокчейнов, так как все компоненты отлично структурированы, разделены на отдельные модули, а в коде присутствуют подробные комментарии. Доказательством гибкости этого движка является существование клиента для сети биткоина и ZCash на основе кода Substrate.

Что касается консенсуса, то можно выбрать из нескольких готовых вариантов или написать свой собственный. В большинстве случаев это PoA или DPoS, что в случае Substrate означает использование алгоритма Aura и GRANDPA.

Производительность блокчейнов на базе Substrate высока. Основная цепочка Polkadot была протестирована нами в конфигурации с 99 валидаторами, распределенными по трем континентам, и показала отличные результаты.

Преимуществом Substrate я считаю продуманность архитектуры, стек разработки (Rust), и огромное поле для развития. Это крайне гибкая сеть, на базе которой можно построить решения любого уровня сложности.

Смарт-контракты и управление сетью

Substrate, в отличие от Ethereum и EOS, обрабатывает транзакции при помощи кода, который размещается валидаторами, а не пользователями. Это код называется “runtime” и исполняется виртуальной машиной WebAssembly.

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

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

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

В плане гибкости у runtime есть множество преимуществ — разработчик может комбинировать их, создавать сложные роли, объединять управление сетью, внутреннюю логику и экономику. Учитывать следует лишь то, что обновление кода runtime проводится кворумом валидаторов.

Дополнительное ПО

Для Substrate есть ряд полезных решений: polkascan — обозреватель блоков и комплекс программ на JS для работы с Polkadot и сетями на базе Substrate. Возможно, вам пригодятся ansible-сценарии для развертывания готового кластера на базе Substrate, который мы использовали для тестирования Polkadot.

У Substrate нет богатого выбора универсального ПО, кошельков и обозревателей блоков, как у Ethereum или EOS, так как цепочки могут сильно отличаться между собой. Проект активно развивается, и множество команд параллельно создают сопутствующее ПО.

Cosmos SDK

Cosmos — это проект на базе одной основной цепочки и множества дочерних блокчейнов, называемых «zones». Дочерние цепочки строятся на основе Cosmos SDK — набора ПО для построения блокчейнов.

Cosmos — это продолжение проекта Tendermint, из которого ключевыми технологиями является надежный консенсус и концепция Application, сходная с runtime в Substrate.

Как и в случае Polkadot+Substrate, блокчейн, созданный с помощью Cosmos SDK, может жить отдельно или подключиться к экосистеме Cosmos как дочерняя цепочка.

Весь комплекс ПО Cosmos написан на Go и отлично структурирован и активно используется. На его основе уже работают несколько проектов, среди которых Binance Chain.

Если ваши разработчики пишут на Go — Cosmos SDK может вам подойти. Он работает и активно развивается в реальных проектах, чьи блокчейны и транзакции можно увидеть в публичных сетях.

Код блокчейн-ноды и консенсус

Главная концепция Cosmos называется Application. Любой блокчейн представляет собой машину состояний, и в Cosmos она вынесена в отдельную часть кода.

По сути, разработчик просто задает правила, по которым одни данные превращаются в другие при внешнем воздействии, программируя так называемую функцию state transition. Это сложно звучит, но по факту обработка транзакции — это state transition, которая меняет несколько балансов. Именно этим занимается Application — принимает некоторое воздействие извне (транзакцию) и меняет свое состояние (state). Получившиеся изменения фиксируются в блокчейне. При этом разработчик не должен решать проблемы консенсуса и сети — сеть сама договорится между собой и придет к консенсусу относительно результатов.

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

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

Смарт-контракты и управление сетью

Application в Cosmos можно рассматривать как единый смарт-контракт, ответственный за обработку всех видов транзакций. Вот пример структуры Application для сервиса регистрации имен.

Одновременно с созданием кода для блокчейн-нод, Cosmos SDK создает код клиента, который умеет формировать транзакции нужных типов.

Для ограничения транзакций в Cosmos, как в Ethereum, используется газ. Исполняя транзакцию, валидаторы вычисляют ее стоимость в условных единицах «gas». Отправляя транзакцию, пользователь указывает цену, которую он готов платить за единицу газа и лимит, который он готов потратить. Это является основанием для вычисления цены за транзакцию.

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

Дополнительное ПО

Параллельно с созданием кода Application, Cosmos SDK позволяет сразу же получить код, который вызывает нужные функции с клиентских машин. Этот код можно использовать на сайте, работающем с Cosmos, или в кошельке (клиенте) сети.

На JavaScript я нашел несколько полезных библиотек: js-cosmos, cosmosjs и универсальную js-abci, реализующую интерфейс ABCI. Их удобно использовать, если взаимодействие с вашим блокчейном планируется из браузера. ABCI позволяет создавать Application на разных языках, среди которых Java, C++, Python. Проект lotion, например, позволяет создать блокчейн полностью на Javascript.

Cosmos бурно развивается, на этом движке запускается много разных проектов. Рекомендую обратить на него внимание, если у вас есть экспертиза в Go и вы хотите надежное работающее решение.

Подписывайтесь на канал Forklog в YouTube!

Нашли ошибку в тексте? Выделите ее и нажмите CTRL+ENTER

Создаем Blockchain с нуля на Python

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

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

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

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

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

Перед тем, как начать…

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

Если вы не знаете, что такое хеш, то вот вам статьи:

На кого нацелена данная статья?

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

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

pip install Flask==0.12.2 requests==2.18.4

pip install Flask==0.12.2 requests==2.18.4

И да, вам также нужен будет HTTP клиент, такой как Postman или cURL. В целом, что-нибудь подойдет.

Исходный код статьи

Вот здесь вы можете ознакомиться с исходным: https://github.com/dvf/blockchain

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

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

Скелет блокчейна

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

class Blockchain(object): def __init__(self): self.chain = [] self.current_transactions = [] def new_block(self): # Создает новый блок и вносит его в цепь pass def new_transaction(self): # Вносит новую транзакцию в список транзакций pass @staticmethod def hash(block): # Хеширует блок pass @property def last_block(self): # Возвращает последний блок в цепочке pass

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

class Blockchain(object):

    def __init__(self):

        self.chain = []

        self.current_transactions = []

        

    def new_block(self):

        # Создает новый блок и вносит его в цепь

        pass

    

    def new_transaction(self):

        # Вносит новую транзакцию в список транзакций

        pass

    

    @staticmethod

    def hash(block):

        # Хеширует блок

        pass

 

    @property

    def last_block(self):

        # Возвращает последний блок в цепочке

        pass

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

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

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

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

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

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): «»» Направляет новую транзакцию в следующий блок :param sender: <str> Адрес отправителя :param recipient: <str> Адрес получателя :param amount: <int> Сумма :return: <int> Индекс блока, который будет хранить эту транзакцию «»» self.current_transactions.append({ ‘sender’: sender, ‘recipient’: recipient, ‘amount’: amount, }) return self.last_block[‘index’] + 1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

class Blockchain(object):

    …

    

    def new_transaction(self, sender, recipient, amount):

        «»»

        Направляет новую транзакцию в следующий блок

 

        :param sender: <str> Адрес отправителя

        :param recipient: <str> Адрес получателя

        :param amount: <int> Сумма

        :return: <int> Индекс блока, который будет хранить эту транзакцию

        «»»

 

        self.current_transactions.append({

            ‘sender’: sender,

            ‘recipient’: recipient,

            ‘amount’: amount,

        })

 

        return self.last_block[‘index’] + 1

После того, как new_transaction() внесет транзакцию в список, он вернет индекс блока, в которой должна будет быть внесена транзакция — а именно следующая. В будущем, это будет полезно для пользователя, отправляющего транзакцию.

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

После того, как мы получили экземпляр блокчейна, нам нужно посадить в него блок генезиса — первый блок без предшественников. Нам также нужно внести “пруф” в наш блок генезиса, который представляет собой результат майнинга (доказательства проведенной работы). Мы рассмотрим майнинг позже.

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

import hashlib import json from time import time class Blockchain(object): def __init__(self): self.current_transactions = [] self.chain = [] # Создание блока генезиса self.new_block(previous_hash=1, proof=100) def new_block(self, proof, previous_hash=None): «»» Создание нового блока в блокчейне :param proof: <int> Доказательства проведенной работы :param previous_hash: (Опционально) хеш предыдущего блока :return: <dict> Новый блок «»» block = { ‘index’: len(self.chain) + 1, ‘timestamp’: time(), ‘transactions’: self.current_transactions, ‘proof’: proof, ‘previous_hash’: previous_hash or self.hash(self.chain[-1]), } # Перезагрузка текущего списка транзакций self.current_transactions = [] self.chain.append(block) return block def new_transaction(self, sender, recipient, amount): «»» Направляет новую транзакцию в следующий блок :param sender: <str> Адрес отправителя :param recipient: <str> Адрес получателя :param amount: <int> Сумма :return: <int> Индекс блока, который будет хранить эту транзакцию «»» 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): «»» Создает хэш SHA-256 блока :param block: <dict> Блок :return: <str> «»» # Мы должны убедиться в том, что словарь упорядочен, иначе у нас будут непоследовательные хеши block_string = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_string).hexdigest()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

import hashlib

import json

from time import time

 

 

class Blockchain(object):

    def __init__(self):

        self.current_transactions = []

        self.chain = []

 

        # Создание блока генезиса

        self.new_block(previous_hash=1, proof=100)

 

    def new_block(self, proof, previous_hash=None):

        «»»

        Создание нового блока в блокчейне

 

        :param proof: <int> Доказательства проведенной работы

        :param previous_hash: (Опционально) хеш предыдущего блока

        :return: <dict> Новый блок

        «»»

 

        block = {

            ‘index’: len(self.chain) + 1,

            ‘timestamp’: time(),

            ‘transactions’: self.current_transactions,

            ‘proof’: proof,

            ‘previous_hash’: previous_hash or self.hash(self.chain[-1]),

        }

 

        # Перезагрузка текущего списка транзакций

        self.current_transactions = []

 

        self.chain.append(block)

        return block

 

    def new_transaction(self, sender, recipient, amount):

        «»»

        Направляет новую транзакцию в следующий блок

 

        :param sender: <str> Адрес отправителя

        :param recipient: <str> Адрес получателя

        :param amount: <int> Сумма

        :return: <int> Индекс блока, который будет хранить эту транзакцию

        «»»

        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):

        «»»

        Создает хэш SHA-256 блока

 

        :param block: <dict> Блок

        :return: <str>

        «»»

 

        # Мы должны убедиться в том, что словарь упорядочен, иначе у нас будут непоследовательные хеши

        block_string = json.dumps(block, sort_keys=True).encode()

        return hashlib.sha256(block_string).hexdigest()

Код выше должен быть достаточно ясным — я внес несколько комментариев и документацию, чтобы все было понятно. Структура данных будет в json. Мы почти закончили с скелетом нашего блокчейна. Однако на данный момент, вам наверное интересно, как создаются новые блоки?

Понимание подтверждения работы

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

Рассмотрим простой пример, чтобы получить лучшее представление.

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

from hashlib import sha256 x = 5 y = 0 # Мы еще не знаем, чему равен y… while sha256(f'{x*y}’.encode()).hexdigest()[-1] != «0»: y += 1 print(f’The solution is y = {y}’)

from hashlib import sha256

 

x = 5

y = 0  # Мы еще не знаем, чему равен y…

while sha256(f'{x*y}’.encode()).hexdigest()[-1] != «0»:

    y += 1

 

print(f’The solution is y = {y}’)

Решение здесь следующее: y = 21, так как созданный хеш заканчивается нулем:

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

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

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

Реализация базового PoW

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

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

import hashlib import json from time import time from uuid import uuid4 class Blockchain(object): … def proof_of_work(self, last_proof): «»» Простая проверка алгоритма: — Поиска числа p`, так как hash(pp`) содержит 4 заглавных нуля, где p — предыдущий — p является предыдущим доказательством, а p` — новым :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): «»» Подтверждение доказательства: Содержит ли hash(last_proof, proof) 4 заглавных нуля? :param last_proof: <int> Предыдущее доказательство :param proof: <int> Текущее доказательство :return: <bool> True, если правильно, False, если нет. «»» guess = f'{last_proof}{proof}’.encode() guess_hash = hashlib.sha256(guess).hexdigest() return guess_hash[:4] == «0000»

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

import hashlib

import json

 

from time import time

from uuid import uuid4

 

 

class Blockchain(object):

    …

        

    def proof_of_work(self, last_proof):

        «»»

        Простая проверка алгоритма:

         — Поиска числа p`, так как hash(pp`) содержит 4 заглавных нуля, где p — предыдущий

         — p является предыдущим доказательством, а p` — новым

 

        :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):

        «»»

        Подтверждение доказательства: Содержит ли hash(last_proof, proof) 4 заглавных нуля?

 

        :param last_proof: <int> Предыдущее доказательство

        :param proof: <int> Текущее доказательство

        :return: <bool> True, если правильно, False, если нет.

        «»»

 

        guess = f'{last_proof}{proof}’.encode()

        guess_hash = hashlib.sha256(guess).hexdigest()

        return guess_hash[:4] == «0000»

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

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

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

Здесь мы задействуем фреймворк под названием Flask. Это макро-фреймворк, который заметно упрощает сопоставление конечных точек с функциями 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): … # Создаем экземпляр узла app = Flask(__name__) # Генерируем уникальный на глобальном уровне адрес для этого узла node_identifier = str(uuid4()).replace(‘-‘, ») # Создаем экземпляр блокчейна 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)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

import hashlib

import json

from textwrap import dedent

from time import time

from uuid import uuid4

 

from flask import Flask

 

 

class Blockchain(object):

    …

 

 

# Создаем экземпляр узла

app = Flask(__name__)

 

# Генерируем уникальный на глобальном уровне адрес для этого узла

node_identifier = str(uuid4()).replace(‘-‘, »)

 

# Создаем экземпляр блокчейна

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 }

{

    «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() # Убедитесь в том, что необходимые поля находятся среди POST-данных required = [‘sender’, ‘recipient’, ‘amount’] if not all(k in values for k in required): return ‘Missing values’, 400 # Создание новой транзакции 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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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()

 

    # Убедитесь в том, что необходимые поля находятся среди POST-данных

    required = [‘sender’, ‘recipient’, ‘amount’]

    if not all(k in values for k in required):

        return ‘Missing values’, 400

 

    # Создание новой транзакции

    index = blockchain.new_transaction(values[‘sender’], values[‘recipient’], values[‘amount’])

 

    response = {‘message’: f’Transaction will be added to Block {index}’}

    return jsonify(response), 201

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

Конечная точка майнинга — это часть, где происходит магия, и это просто! Для этого нужно сделать три вещи:

  • Подсчитать PoW;
  • Наградить майнера (нас), добавив транзакцию, дающую нам 1 коин;
  • Слепить следующий блок, внеся его в цепь.

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(): # Мы запускаем алгоритм подтверждения работы, чтобы получить следующее подтверждение… last_block = blockchain.last_block last_proof = last_block[‘proof’] proof = blockchain.proof_of_work(last_proof) # Мы должны получить вознаграждение за найденное подтверждение # Отправитель “0” означает, что узел заработал крипто-монету blockchain.new_transaction( sender=»0″, recipient=node_identifier, amount=1, ) # Создаем новый блок, путем внесения его в цепь 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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

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():

    # Мы запускаем алгоритм подтверждения работы, чтобы получить следующее подтверждение…

    last_block = blockchain.last_block

    last_proof = last_block[‘proof’]

    proof = blockchain.proof_of_work(last_proof)

 

    # Мы должны получить вознаграждение за найденное подтверждение

    # Отправитель “0” означает, что узел заработал крипто-монету

    blockchain.new_transaction(

        sender=»0″,

        recipient=node_identifier,

        amount=1,

    )

 

    # Создаем новый блок, путем внесения его в цепь

    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. С этого момента, мы закончили, и можем начать взаимодействовать с нашим blockchain на Python.

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

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

Запускаем сервер:

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

$ python blockchain.py

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Давайте попробуем майнить блок, создав GET-запрос к узлу http://localhost:5000/mine:

curl http://localhost:5000/mine

curl http://localhost:5000/mine

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

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

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

$ 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 }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

{

  «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: Консенсус

Пока всё идет очень здорово. У нас есть базовый blockchain, который принимает транзакции и дает возможность майнить новые блоки. Но вся суть блокчейна в том, что они должны быть децентрализованными. А если они децентрализованы, каким образом мы можем гарантировать, все они отображают одну цепочку?

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

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

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

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

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

… from urllib.parse import urlparse … class Blockchain(object): def __init__(self): … self.nodes = set() … def register_node(self, address): «»» Вносим новый узел в список узлов :param address: <str> адрес узла , другими словами: ‘http://192.168.0.5:5000’ :return: None «»» parsed_url = urlparse(address) self.nodes.add(parsed_url.netloc)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

from urllib.parse import urlparse

 

 

class Blockchain(object):

    def __init__(self):

        …

        self.nodes = set()

        …

 

    def register_node(self, address):

        «»»

        Вносим новый узел в список узлов

 

        :param address: <str> адрес узла , другими словами: ‘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): «»» Проверяем, является ли внесенный в блок хеш корректным :param chain: <list> blockchain :return: <bool> True если она действительна, False, если нет «»» 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): «»» Это наш алгоритм Консенсуса, он разрешает конфликты, заменяя нашу цепь на самую длинную в цепи :return: <bool> True, если бы наша цепь была заменена, False, если нет. «»» 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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

import requests

 

 

class Blockchain(object)

    …

    

    def valid_chain(self, chain):

        «»»

        Проверяем, является ли внесенный в блок хеш корректным

 

        :param chain: <list> blockchain

        :return: <bool> True если она действительна, False, если нет

        «»»

 

        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):

        «»»

        Это наш алгоритм Консенсуса, он разрешает конфликты,

        заменяя нашу цепь на самую длинную в цепи

 

        :return: <bool> True, если бы наша цепь была заменена, False, если нет.

        «»»

 

        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

Первый метод 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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

@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, чтобы убедиться в том, что цепь была длиннее. После этого, я вызвал GET /nodes/resolve в узле 1, где цепь была заменена нашим алгоритмом консенсуса:

И это была обертка… Найдите друзей и вместе попробуйте протестировать ваш блокчейн!

Подведем итоги

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

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: [email protected]

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»

Пишем свой блокчейн

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

Скорее всего вы здесь, также, как и я, потому что были недовольны резким подъемом Криптовалюты. И вы хотите узнать, как же работают Блокчейны – фундаментальная технология, которая стоит за всеми криптовалютами.

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

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

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

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

У вас не должно возникать трудностей с чтением синтаксиса и написанием базовых вещей на Python. Кроме того, у вас должно быть понимание того, как работают HTTP-запросы, поскольку обращаться к нашему Блокчейну мы будем именно через них.

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

pip install Flask==0.12.2 requests==2.18.4

О, вам также понадобится HTTP-клиент, наподобие Postman или cURL. Но все будет дальше.

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

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

Создадим класс Blockchain, конструктор которого будет создавать изначально пустой список (для хранения нашего блокчейна), и еще один для хранения транзакций. Ниже приведен макет нашего класса:

 	
class Blockchain(object):	
    def __init__(self):
        self.chain = []
        self.current_transactions = []
 	
    def new_block(self):
        # Создает новый Блок и добавляет его к цепочке
        pass

 	
    def new_transaction(self):
        # Добавляет новую транзакцию к списку транзакций
        pass
 	
    @staticmethod	
    def hash(block):
        # Хэшируем блоки
        pass
 	

    @property
    def last_block(self):
        # Возвращает последний блок в цепочке
        pass

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

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

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

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):
        """
      Создает новую транзакцию для того чтобы перейти к следующему искомому Блоку

        :параметр sender: <str> Адрес отправителя
        :параметр recipient: <str> Адрес получателя	
        :параметр amount: <int> Количество
        :return: <int> Индекс Блока, в котором будет хранится данная транзакция
        """

        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })
 	
        return self.last_block['index'] + 1

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

После того, как мы создали экземпляр нашего Блокчейна, нам необходимо заполнить его исходным блоком – блок у которого нет предшественников. Также нам необходимо добавить «proof» в наш исходный блок, который является результатом анализа (или алгоритма «доказательство выполнения работы»). По поводу анализа мы поговорим позднее.

Кроме этого, для создания исходного блока в нашем конструкторе, нам также необходимо добавить следующие методы: 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):
        """
        Создаем новый блок в нашем Блокчейне

 	 	
        :параметр proof: <int> proof полученный после использования алгоритма «Доказательство выполнения работы»
        :параметр previous_hash: (Опциональный) <str> Хэш предыдущего Блока
        :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]),
        }

 	
        # Сбрасываем текущий список транзакций
        self.current_transactions = []

 	
        self.chain.append(block)
        return block
 	
    def new_transaction(self, sender, recipient, amount):
        """
        Создает новую транзакцию для перехода к следующему замайненному Блоку

        :param sender: <str> Address of the Sender
        :param recipient: <str> Address of the Recipient
        :param amount: <int> Amount
        :return: <int> Индекс блока который будет хранить в себе эту транзакцию
        """

        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):
        """
        Создает a SHA-256 хэш блока

        :параметр block: <dict> Блок
        :return: <str>
        """

        # Мы должны быть уверены что наш Словарь упорядочен, или мы можем непоследовательные хэши
        block_string = json.dumps(block, sort_keys=True).encode()	
        return hashlib.sha256(block_string).hexdigest()

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

Алгоритм «Доказательство выполнения работы» (PoW) – это то, как новые блоки создаются или майнятся в блокчейне. Целью алгоритма PoW является нахождение такого числа (метки), которое будет решать проблему. Число должно быть таким, чтобы его было сложно найти и легко проверить. Говоря в вычислительном отношении не важно кем в сети это может быть сделано. В этом и заключается основная идея данного алгоритма.

Итак, давайте взглянем на простой пример, которой поможет нам во всем разобраться.

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

from hashlib import sha256


x = 5
y = 0  # Пока мы не знаем каким должен быть y


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

В сфере Биткоинов, алгоритм «Доказательство выполнения работы» называется Hashcash. И он не сильно отличается от нашего базового примера выше. Это алгоритм, который майнеры используют в гонке по решению задачи создания новых блоков. Как правило, сложность определяется количеством символов, которые необходимо обнаружить в строке. После чего майнеры получают награду за свое решение в качестве биткойна при транзакции.

Сеть может легко проверить их решение.

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

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

import hashlib	
import json

 		
from time import time	
from uuid import uuid4

	
class Blockchain(object):	
    ...

    def proof_of_work(self, last_proof):
        """
        Простой алгоритм Proof of Work:
         - Ищем число p' такое, чтобы hash(pp') содержал в себе 4 лидирующих нуля, где p это предыдущий p'
         - p это предыдущий proof, а p' это новый proof

        :параметр 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):
        """
        Проверяем Proof: Содержит ли hash(last_proof, proof) 4 лидирующих нуля?

        :параметр last_proof: <int> предыдущий Proof
        :параметр proof: <int> Тукущий Proof
        :return: <bool> True если все верно, иначе False.
        """
	
        guess = f'{last_proof}{proof}'.encode()	
        guess_hash = hashlib.sha256(guess).hexdigest() 	
        return guess_hash[:4] == "0000"

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

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

Мы будем использовать фреймворк Flask. Данный микро-фреймворк упрощает размещение конечных точек (endpoints) в 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):	
    ...

 	
# Создаем экземпляр нашего узла	
app = Flask(__name__)
 	
# Генерируем уникальный глобальный адрес для этого узла	
node_identifier = str(uuid4()).replace('-', '')

# Создаем экземпляр 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: Создаем endpoint для метода /mine, который является GET-запросом;
  • Строки 28-30: Создаем endpoint для метода /transactions/new, который является POST-запросом, поскольку мы будем отправлять сюда данные;
  • Строки 32-38: Создаем endpoint для метода /chain, который будет возвращать весь Блокчейн;
  • Строки 40-41: Запускаем наш сервер на порт 5000.

Endpoint для транзакций

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

{
 "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()


    # Проверяем, что обязательные поля переданы в POST-запрос
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return 'Missing values', 400

 	
    # Создаем новую транзакцию	
    index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
 	
    response = {'message': f'Transaction will be added to Block {index}'}
    return jsonify(response), 201

Endpoint для майнинга

Наш endpoint майнинга – это то, где происходит магия, и в ней нет ничего сложного. Здесь совершаются три следующих вещи:

  1. Расчет алгоритма PoW;
  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():
    # Мы запускаем алгоритм PoW для того чтобы найти следующий proof...
    last_block = blockchain.last_block	
    last_proof = last_block['proof']
    proof = blockchain.proof_of_work(last_proof)

 	
    # Мы должны получить награду за найденный proof.
    # Если sender = "0", то это означает что данный узел заработал биткойн.	
    blockchain.new_transaction(
        sender="0",	
        recipient=node_identifier,
        amount=1,
    )


    # Формируем новый блок, путем добавления его в цепочку
    block = blockchain.new_block(proof)
 	
    response = {
        'message': "New Block Forged",
        'index': block['index'],
        'transactions': block['transactions'],
        'proof': block['proof'],
        'previous_hash': block['previous_hash'],	
    }	
    return jsonify(response), 200

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

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

Запускаем наш сервер:
$ python blockchain.py* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Давайте попробуем смайнить блок. Для этого воспользуемся GET-запросом на http://localhost:5000/mine:

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

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

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

Я перезагрузил свой сервер, и смайнил два блока, чтобы в итоге получилось три. Давайте проверим всю цепочку, с помощью запроса на 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
}

Пока, все что мы делали, это круто. Мы получили базовый Блокчейн, который может принимать транзакции, тем самым позволяя нам майнить новые Блоки. Однако вся суть Блокчейнов заключается в том, что они должны быть децентрализованы. Но если блокчейны децентрализованы, то как мы можем гарантировать, что все они отражают одну и ту же цепочку? Данная проблема называется проблемой Консенсуса (конфликтов). Мы реализуем алгоритм Консенсуса, если мы конечно хотим, чтобы в нашей сети было больше одного узла.

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

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

Для всего этого нам необходимо модифицировать конструктор нашего Блокчейна, и предоставить метод по регистрации узлов:

 

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

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

    def register_node(self, address):
        """
        Добавляем новый узел в список узлов

        :параметр address: <str> Адрес узла, например: '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):
        """
        Определяем, что данный блокчейн прошел проверку
 
        :параметр chain: <list> Блокчейн
        :return: <bool> True если прошел проверку, иначе False
        """

        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

            # Проверяем, что алгоритм PoW корректен
            if not self.valid_proof(last_block['proof'], block['proof']):
                return False

 	
            last_block = block
 	
            current_index += 1

        return True

    def resolve_conflicts(self):
        """
        Это наш алгоритм Консенсуса, он разрешает конфликт путём
        замены нашей цепочки на самую длинную в нашей сети.

        :return: <bool> True если наша цепочка была заменена, False если это не так
        """

 	
        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

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

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

Давайте зарегистрируем два endpoint-а в нашем 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, для того чтобы цепочка стала длиннее. Потом, я вызвал GET /nodes/resolve на узел 1, где цепочка была заменена по алгоритму Консенсуса:

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

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

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

Простейший блокчейн своими руками
10 полезных ресурсов по технологии blockchain

Ссылка на оригинальную статью
Перевод: Александр Давыдов

Как создать blockchain платформу — систему?

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

Как создать платформу блокчейн?

Создание платформы для ICO-проекта проходит в несколько этапов, разделенных между собой на блоки. Над каждым блоком работает определенная группа специалистов.

Непосредственно созданию сайта под ICO-проект предшествует ряд важных задач:

  • разработка краткосрочного, либо долгосрочного плана по выпуску токенов;
  • разработка бизнес-логики и создание экономической модели ICO-проекта;
  • глубокая работа над внутренней документацией проекта. а также над документацией, предназначенной для инвесторов;
  • бизнес-план, включающий в себя маркетинговые исследования, разработку стратегии ICO и финансовой модели, а также анализ исходных данных.
  • разработка прототипов интерфейса сайта;
  • подготовка тематического контента для последующего наполнения сайта.

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

Кстати, создание сайта также делится на несколько частей: программная, маркетинговая части и оформление сайта.

  1. Программная часть сайта включает в себя такие компоненты, как разработка и запуск Ethereum-кошелька, размещение токена в blockchain, внедрение платежных инструментов, а также согласование финансовой логики, технических требований и проработка факторов безопасности. Разумеется, есть и другие составляющие, но это – самые основные.
  2. Маркетинговая часть подразумевает социальную подоплеку – новостные рассылки, создание тем на специализированных форумах, создание видеообзоров, обязательное ведение блога, пресс-релизы, реклама в криптосообществах и т.п.
  3. Дизайн сайта – это грамотное оформление, привлекающее внимание потенциальных инвесторов.

Как создать blockchain-проект?

Обратившись в нашу компанию, вы плучите в свое пользование команду профессоналов, которые ссоздадут вам масштабный и прибыльный ICO-проект по приемлемым ценам. Также наши специалисты будут курировать ваш проект от начала и до конца.

Создание блокчейн проекта платформы и системы

Главной трудностью любого стартапа, является необходимость привлечения инвестиций для реализации задуманного проекта. Сегодня ICO имеет большой спрос среди грамотных инвесторов, с его помощью можно привлечь больше средств. Создание blockchain-проектов позволит дать бизнесу, основанному на криптовалютах, новый толчок в развитии. Чтобы проект, основанный на технологии блокчейн стал технически безупречным, им должны заниматься профессионалы.

Создание блокчейн проекта

Blockchain-проект обладает рядом преимуществ и решает обширный спектр задач:

  • Отправка различной валюты.
  • Документооборот.
  • Надежное хранение файлов.
  • Децентрализованная торговля.

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

Создание собственного блокчейна

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

  • Разработку смарт-контракта Etherium и токенов.
  • Независимый аудит умного контракта.
  • Разрабатываем бизнес-план.
  • Делаем глубокую проработку документации WhitePaper.
  • Разрабатываем Landing page.
  • Создание электронных кошельков.
  • Организовываем Pre-ICO.
  • Оказываем помощь в проведении ICO.
  • Аудит ICO компании.
  • Создаем виртуальные валюты на платформе Etherium.
  • Совершаем новостную рассылку на специализированных сайтах и в социальных сетях.

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

Создание блокчейн сервисов

Блокчейн сети совершили неимоверный прорыв в общем развитии IT-технологий. Blockchain является уникальной платформой, с помощью которой можно изменить в лучшую сторону финансовые связи с партнерами по бизнесу. Эта система исключает мошенничество, а операции и обмен информацией происходят очень быстро. Создав биржи и другие сервисы по оплате криптовалютой, можно получать небольшой процент за проведение операций пользователями. Учитывая, что их миллионы, суммы будут выходить внушительными.

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

Как создать приложение с использованием блокчейна

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

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

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

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

Создать собственное приложение с использованием блокчейн возможно 3 способами, выбор зависит от того, какие цели вы преследуете:

1. Используем платформу для блокчейн-приложений

Создание приложения с использованием готового блокчейна на одной из специализированных платформ — это самый простой и быстрый способ разработки приложения.

Наиболее популярные платформы:

  • Ethereum — одна из самых известных и функциональных блокчейн-платформ с развитой инфраструктурой для создания смарт-контрактов и разработки децентрализованных приложений. Основной язык программирования — Solidity, внутренняя криптовалюта — Ether (ETH).
  • Hyperledger Fabric — перспективная платформа для разработки решений на базе блокчейна, ориентированных на корпоративный сегмент. Появилась при поддержке IBM и в данный момент не имеет своей криптовалюты. Актуальные языки программирования: Go, Java, JavaScript.
  • Cardano — действующая блокчейн-платформа нового типа; ключевое отличие от других платформ заключается в том, что в Cardano существует разделение вычислительных слоев: первый слой предназначен для работы с внутренней криптовалютой ADA, второй — для создания и обработки смарт-контрактов, написанных на языке программирования Haskell.

Выбор платформы зависит от сложности и цели проекта. При создании своих децентрализованных проектов, мы в Umbrella IT обычно используем платформу Ethereum. Так, одной из первых наших работ на Ethereum, была блокчейн-лотерея. Технология блокчейн помогла обеспечить абсолютную честность розыгрыша, а система смарт-контрактов сделала возможным автоматические выплаты выигрышей сразу на счет участника. В ходе разработки наша команда убедилась, что платформа отвечает всем нашим критериям качества: универсальность, гибкость и скорость разработки.

Для реализации блокчейна на платформе Etherium, необходимо создать новый смарт-контракт на высокоуровневом языке Solidity, чей синтаксис похож на JavaScript, и загрузить его в сеть Etherium, где уже есть свой API и все необходимое для быстрого запуска готового продукта.

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

Плюсы:

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

Минусы:

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

На разработку ядра блокчейн-приложения с использованием готового блокчейна в среднем уходит 2 недели.

2. Разворачиваем собственную сеть на базе open-source блокчейн-платформы

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

Данный вариант прежде всего привлекателен своей автономностью: ваша сеть — ваши правила. За счет использования открытого кода, вы экономите время и ресурсы, необходимое для создания собственной сети.

Плюсы:

  • создание блокчейна на базе open-source платформы освобождает от уплаты комиссии за каждую проведенную транзакцию. Все ваши расходы будут ограничиваться статичной ежемесячной суммой на поддержание ваших серверов и инфраструктуры и не будут увеличиваться с ростом транзакций.   

Минусы:

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

Разработка приложения с созданием собственной блокчейн-сети занимает минимум 1 месяц.

3. Создаем проект с использованием блокчейна с нуля

Разработка блокчейна с нуля подразумевает создание приложения на одном из высокоуровневых языков программирования (С, С+, С#, Java) с использованием огромного количества криптографических алгоритмов. Криптографические алгоритмы — фундаментальная основа блокчейна. Для подписи и верификации любых данных внутри информационного блока проводятся различные процедуры, состоящие из сложных арифметических операций, что, по сути, переносит разработку блокчейна скорее в область математики, чем программирования.

Плюсы:

  • отсутствие комиссии за использование вычислительных ресурсов платформы;
  • создание блокчейна с нуля обосновано при наличии уникальных условий или ограничений (например, если для вас критично, чтобы ваша сеть функционировала в рамках конкретных государств), а также в случаях, когда существующие алгоритмы готовых блокчейнов не соответствует вашим поставленным целям и задачам.

Минусы:

  • долгий срок разработки;
  • так же, как и при создании собственной сети на базе open-source платформы, разработка блокчейна с нуля требует создания полноценной инфраструктуры (включая настройку серверов, администрирование оборудования и подключением майнеров), которую вам придется мониторить и поддерживать самостоятельно.

Разработка собственного блокчейна занимает минимум 6 месяцев.

От теории к практике

Наш опыт показывает, что в большинстве случаев, при необходимости разработки приложения с использованием блокчейна, наиболее оптимальным решением будет либо использование платформы для блокчейн-приложений, либо создание собственной сети на базе open-source платформы.

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

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

Архитектура нашего приложения выглядит так:

Эта архитектура универсальна и подходит для реализации в любой сфере и индустрии.

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

Закажите приложение с использованием блокчейна прямо сейчас!

# 8 шагов по созданию решения для цепочки блоков

Читать 5 мин

Мнения, высказанные предпринимателями. участников являются их собственными.

Вы читаете Entrepreneur India, международную франшизу Entrepreneur Media.

Когда в 2008 году Сатоши Накамото объявил о технологии блокчейн в документе под названием «Биткойн: одноранговая система электронных денег», это было инновационное сочетание криптографии с открытым ключом (изобретено в 1970-х годах) и криптографических хэш-функций (рожденных в 1970-е годы) и доказательство работы (изобретено в 1990-е годы).

За последние несколько лет было создано множество производных проектов и проектов, вдохновленных блокчейном. Большинство из них технически не являются блокчейнами, а скорее системами распределенного реестра.

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

Шаг 1. Определите подходящий вариант использования

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

Есть 3 вещи, которые блокчейны могут делать очень хорошо:

  1. Аутентификация и проверка данных: это включает неизменяемое хранилище, цифровые подписи и шифрование. В блокчейне можно хранить данные практически в любом формате. Блокчейны могут создавать пары открытого и закрытого ключей, а также использоваться для генерации и проверки цифровых подписей.
  2. Интеллектуальное управление активами: включает выпуск, оплату, обмен, условное депонирование и изъятие из обращения.Умный / криптоактив — это токенизированная версия реального актива, например золото, серебро, масло, земля.
  3. Смарт-контракты: Этот термин чаще всего понимают неправильно, но об этом мы поговорим в другой раз.

Шаг 2: Определите наиболее подходящий механизм консенсуса

Исходный блокчейн, на котором работает криптовалюта биткойн, использовал доказательство работы в качестве механизма консенсуса. Но сегодня существует несколько систем распределенного реестра, которые предлагают множество механизмов консенсуса, таких как доказательство доли, византийская отказоустойчивость, консенсус на основе депозита, федеративное византийское соглашение, доказательство истекшего времени, производные PBFT, избыточная византийская отказоустойчивость, упрощенная византийская отказоустойчивость. , Федеративный консенсус, Раунд Робин и Делегированное подтверждение ставки.

В зависимости от вашего варианта использования вам необходимо выбрать наиболее разумный механизм консенсуса.

Шаг 3. Определите наиболее подходящую платформу

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

Вот некоторые из наиболее популярных платформ в алфавитном порядке:

1.BigChainDB

2. Ядро цепочки

3. Corda

4. Кредиты

5. Блокчейн Domus Tower

6. Блокчейн-платформа Elements

7. Eris: db

8. Ethereum

9. HydraChain

10. Hyperledger Fabric

11. Hyperledger Iroha

12. Hyperledger Sawtooth Lake

13. Multichain

14. Openchain

15.Кворум

16. Stellar

17. Сборка Symbiont

Шаг 4: Проектирование узлов

Решения Blockchain могут быть разрешенными (например, государственный земельный кадастр) или без разрешения (например, Биткойн, где любой может стать майнер). Блокчейн-решения могут быть частными (например, система управления контрактами, реализованная в фармацевтической компании), публичными (например, криптовалюта, обеспеченная активами) или гибридными (например, группа банков, использующих общую платформу KYC).

Еще один фактор, который следует учитывать на этом этапе, — будут ли узлы работать в облаке, локально или и там, и там. Затем возникают проблемы с конфигурацией оборудования, такие как процессоры, память и размер диска. Вам также необходимо определиться с базовыми операционными системами (обычно Ubuntu, CentOS, Debian, Fedora, Red Hat или Windows).

Шаг 5: Разработка экземпляра блокчейна

Большинство платформ блокчейнов требуют очень тщательно спланированной конфигурации следующих элементов:

1.Разрешения

2. Выпуск активов

3. Перевыпуск активов

4. Атомарные обмены

5. Управление ключами

6. Множественные подписи

7. Параметры

8. Собственные активы

9. Форматы адресов

10. Форматы ключей

11. Сигнатуры блоков

12. Встряхивание рук

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

Шаг 6. Создание API

Некоторые платформы блокчейнов поставляются с готовыми API, а некоторые — нет. Основные категории API-интерфейсов, которые вам могут понадобиться:

  • Создание пар ключей и адресов
  • Выполнение функций, связанных с аудитом
  • Проверка подлинности данных с помощью цифровых подписей и хэшей
  • Хранение и извлечение данных
  • Управление жизненным циклом интеллектуальных активов — выпуск , оплата, обмен, условное депонирование и вывод на пенсию
  • Смарт-контракты

Шаг 7: Разработка интерфейса администратора и пользователя

На этом этапе вам нужно будет выбрать интерфейс пользователя и языки программирования (например.грамм. HTML5, CSS, PHP, C #, Java, Javascript, Python, Ruby, Golang, Solidity, Angular JS Nodejs). Вам также нужно будет выбрать внешние базы данных (например, MySQL, MongoDB), а также серверы (включая веб-серверы, FTP-серверы, почтовые серверы).

Шаг 8: Добавление Future Tech

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

Изучите блокчейны, построив один

Самый быстрый способ узнать, как работают блокчейны, — это построить один

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

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

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

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

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

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

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

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

  pip install Flask == 0.12.2 requests == 2.18.4  

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

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

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

Откройте свой любимый текстовый редактор или IDE, лично я ❤️ PyCharm. Создайте новый файл с именем

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

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

Мы создадим класс цепочки блоков

   
, конструктор которого создает начальный пустой список (для хранения нашей цепочки блоков), а другой — для хранения транзакций. Вот план для нашего класса:
  class Blockchain (object):
    def __init __ (сам):
        self.chain = []
        self.current_transactions = []
        
    def new_block (сам):
        # Создает новый блок и добавляет его в цепочку
        проходить
    
    def new_transaction (сам):
        # Добавляет новую транзакцию в список транзакций
        проходить
    
    @staticmethod
    def хэш (блок):
        # Хеширует блок
        проходить

    @имущество
    def last_block (сам):
        # Возвращает последний блок в цепочке
        pass  

(Blueprint нашего класса Blockchain)

Наш

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

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

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

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

  block = {
    'index': 1,
    'отметка времени': 1506057125.

5, г. 'транзакции': [ { 'отправитель': "8527147fe1f5426f9dd545de4b27ee00", 'получатель': "a77f5cdfa2934df3954a5c7c7da5df1f", 'amount': 5, } ], «доказательство»: 324984774000, 'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" }

( Пример блока в нашей цепочке блоков)

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

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

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

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

  new_transaction ()  
, и он довольно прост:
  class Blockchain (object):
    ...
    
    def new_transaction (я, отправитель, получатель, сумма):
        "" "
        Создает новую транзакцию для перехода в следующий добытый блок
        : param sender:  Адрес отправителя
        : param recipient:  Адрес Получателя
        : param amount:  Amount
        : return:  Индекс блока, который будет содержать эту транзакцию
        "" "

        self.current_transactions.append ({
            "отправитель": отправитель,
            "получатель": получатель,
            'amount': количество,
        })

        вернуть себя.last_block ['index'] + 1  

После того, как

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

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

Когда будет создан экземпляр нашей цепочки блоков

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

Помимо создания блока genesis в нашем конструкторе, мы также конкретизируем методы для

  new_block ()  
,
  new_transaction ()  
и
  hash ()  
:
  импортировать хэш-библиотеку
импортировать json
от времени импорта времени


класс Blockchain (объект):
    def __init __ (сам):
        себя.current_transactions = []
        self.chain = []

        # Создаем генезисный блок
        self.new_block (previous_hash = 1, proof = 100)

    def new_block (self, proof, previous_hash = None):
        "" "
        Создайте новый блок в цепочке блоков.
        : param proof:  Доказательство алгоритма Proof of Work
        : param previous_hash: (Необязательно)  Хеш предыдущего блока
        : return:  Новый блок
        "" "

        block = {
            'index': len (self.цепочка) + 1,
            'отметка времени': время (),
            'транзакции': self.current_transactions,
            'proof': доказательство,
            'previous_hash': previous_hash или self.hash (self.chain [-1]),
        }

        # Сбросить текущий список транзакций
        self.current_transactions = []

        self.chain.append (блок)
        блок возврата

    def new_transaction (я, отправитель, получатель, сумма):
        "" "
        Создает новую транзакцию для перехода в следующий добытый блок
        : param sender:  Адрес отправителя
        : param recipient:  Адрес Получателя
        : param amount:  Amount
        : return:  Индекс блока, который будет содержать эту транзакцию
        "" "
        себя.current_transactions.append ({
            "отправитель": отправитель,
            "получатель": получатель,
            'amount': количество,
        })

        return self.last_block ['index'] + 1

    @имущество
    def last_block (сам):
        вернуть self.chain [-1]

    @staticmethod
    def хэш (блок):
        "" "
        Создает хэш SHA-256 блока
        : param block:  Блок
        : return: 
        "" "

        # Мы должны убедиться, что словарь упорядочен, иначе у нас будут несогласованные хэши
        block_string = json.дампы (блок, sort_keys = True) .encode ()
        return hashlib.sha256 (block_string) .hexdigest ()  

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

Понимание Proof of Work

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

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

Давайте решим, что хэш некоторого целого числа x, умноженного на другое y, должен заканчиваться на 0. Итак,

  hash (x * y) = ac23dc ... 0  
. В этом упрощенном примере зафиксируем
  x = 5  
.Реализация этого в Python:
  из hashlib import sha256
х = 5
y = 0 # Мы еще не знаем, каким должно быть y ...
а sha256 (f '{x * y}'. encode ()). hexdigest () [- 1]! = "0":
    у + = 1
print (f 'Решение: y = {y}')  

Здесь решение:

  y = 21  
. Поскольку созданный хэш заканчивается на 0:
  hash (5 * 21) = 1253e9373e ... 5e3600155e860  

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

Сеть может легко проверить свое решение.

Реализация базового Proof of Work

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

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

от времени импорта времени
из uuid import uuid4


класс Blockchain (объект):
    ...
        
    def proof_of_work (self, last_proof):
        "" "
        Простой алгоритм доказательства работы:
         - Найдите число p 'такое, что hash (pp') содержит четыре ведущих нуля, где p - предыдущий p '
         - p - предыдущее доказательство, а p '- новое доказательство.
        : param last_proof: 
        : return: 
        "" "

        доказательство = 0
        пока сам.valid_proof (last_proof, proof) ложно:
            доказательство + = 1

        подтверждение возврата

    @staticmethod
    def valid_proof (last_proof, доказательство):
        "" "
        Проверяет доказательство: содержит ли хэш (last_proof, proof) 4 ведущих нуля?
        : param last_proof:  Предыдущее доказательство
        : param proof:  Текущее доказательство
        : return:  Истинно, если верно, если нет.
        "" "

        guess = f '{last_proof} {доказательство}'. encode ()
        guess_hash = hashlib.sha256 (угадать).hexdigest ()
        return guess_hash [: 4] == "0000"  

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

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

Шаг 2. Наш блокчейн как API

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

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

  •   / transaction / new  
    , чтобы создать новую транзакцию в блоке
  •   / mine  
    , чтобы сообщить нашему серверу майнить новый блок.
  •   / chain  
    для возврата всей цепочки блоков

Настройка Flask

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

  import hashlib
импортировать json
from textwrap import dedent
от времени импорта времени
из uuid import uuid4

из фляги импорт фляги


класс Blockchain (объект):
    ...


# Создайте экземпляр нашего узла
app = Flask (__ имя__)

# Сгенерировать глобально уникальный адрес для этого узла
node_identifier = str (uuid4 ()). replace ('-', '')

# Создать блокчейн
blockchain = Блокчейн ()


@ app.route ('/ mine', methods = ['GET'])
def mine ():
    return "Мы будем добывать новый блок"
  
@приложение.маршрут ('/ транзакции / новый', методы = ['POST'])
def new_transaction ():
    return "Мы добавим новую транзакцию"

@ app.route ('/ chain', methods = ['GET'])
def full_chain ():
    response = {
        'цепочка': blockchain.chain,
        'длина': len (blockchain.chain),
    }
    вернуть jsonify (ответ), 200

если __name__ == '__main__':
    app.run (host = '0.0.0.0', port = 5000)  

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

  • Строка 15: Создает экземпляр нашего Node. Узнайте больше о Flask здесь.
  • Строка 18: Создайте случайное имя для нашего узла.
  • Строка 21: Создайте экземпляр класса
      Blockchain  
    .
  • Строка 24–26: Создайте конечную точку
      / mine  
    , которая представляет собой запрос
      GET  
    .
  • Строка 28–30: Создайте конечную точку
      / transaction / new  
    , которая представляет собой запрос POST
     , поскольку мы будем отправлять на нее данные.
  • Строка 32–38: Создайте конечную точку
      / chain  
    , которая возвращает полную цепочку блоков.
  • Строка 40–41: Запускает сервер на порту 5000.

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

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

  {
 "отправитель": "мой адрес",
 "получатель": "чужой адрес",
 «количество»: 5
}  

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

  import hashlib
импортировать json
from textwrap import dedent
от времени импорта времени
из uuid import uuid4

из флакона импорт Flask, jsonify, запрос

...

@ app.route ('/ transaction / new', methods = ['POST'])
def new_transaction ():
    значения = request.get_json ()

    # Убедитесь, что обязательные поля находятся в POST-данных
    required = ['отправитель', 'получатель', 'сумма']
    если не все (требуется k в значениях для k):
        return 'Missing values', 400

    # Создать новую транзакцию
    index = блокчейн.new_transaction (значения ['отправитель'], значения ['получатель'], значения ['количество'])

    response = {'message': f'Транзакция будет добавлена ​​в блок {index} '}
    return jsonify (response), 201  

( Метод создания транзакций)

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

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

  • Рассчитать Proof of Work
  • Наградить майнера (нас), добавив транзакцию, дающую нам 1 монету
  • Создать новый блок, добавив его в цепочку
  •   import hashlib
    импортировать json
    
    от времени импорта времени
    из uuid import uuid4
    
    из флакона импорт Flask, jsonify, запрос
    
    ...
    
    @ app.route ('/ mine', methods = ['GET'])
    def mine ():
        # Мы запускаем алгоритм доказательства работы, чтобы получить следующее доказательство ...
        last_block = blockchain.last_block
        last_proof = last_block ['доказательство']
        proof = blockchain.proof_of_work (last_proof)
    
        # Мы должны получить награду за доказательство.
        # Отправитель "0" означает, что этот узел добыл новую монету.
        blockchain.new_transaction (
            отправитель = "0",
            получатель = идентификатор_узла,
            сумма = 1,
        )
    
        # Создайте новый блок, добавив его в цепочку
        previous_hash = блокчейн.хеш (последний_блок)
        block = blockchain.new_block (доказательство, предыдущий_хэш)
    
        response = {
            'message': "Новый блок подделан",
            'index': блок ['index'],
            'транзакции': блок ['транзакции'],
            'proof': block ['proof'],
            'previous_hash': блок ['previous_hash'],
        }
        return jsonify (response), 200  

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

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

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

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

  $ python blockchain.py
* Запуск на http://127.0.0.1:5000/ (нажмите CTRL + C для выхода)  

Давайте попробуем добыть блок, отправив запрос

  GET  
на
  http: // localhost: 5000 / mine  
:

( Использование Postman для выполнения запроса GET)

Давайте создадим новую транзакцию, сделав запрос POST

  на адрес 
  http: // localhost: 5000 / transaction / new  
с тело, содержащее нашу структуру транзакции:

( Использование Postman для выполнения запроса POST)

Если вы не используете Postman, вы можете сделать эквивалентный запрос, используя cURL:

  $ curl -X POST -H " Content-Type: application / json "-d '{
 "отправитель": "d4ee26eee15148ee92c6cd394edd974e",
 "получатель": "адрес другого человека",
 «количество»: 5
} '"http: // localhost: 5000 / transaction / new"  

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

  http: // localhost: 5000 / chain  

  {
  "цепь": [
    {
      «индекс»: 1,
      "previous_hash": 1,
      «доказательство»: 100,
      "отметка времени": 1506280650.770839,
      "транзакции": []
    },
    {
      «индекс»: 2,
      "previous_hash": "c099bc ... bfb7",
      «пруф»: 35293,
      "отметка времени": 1506280664.717925,
      "транзакции": [
        {
          «количество»: 1,
          "получатель": "8bbcb347e0634905b0cac7955bae152b",
          "отправитель": "0"
        }
      ]
    },
    {
      «индекс»: 3,
      "previous_hash": "eff91a...10f2 ",
      «пруф»: 35089,
      "отметка времени": 1506280666.1086972,
      "транзакции": [
        {
          «количество»: 1,
          "получатель": "8bbcb347e0634905b0cac7955bae152b",
          "отправитель": "0"
        }
      ]
    }
  ],
  «длина»: 3
}  

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

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

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

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

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

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

  ...
из urllib.parse импорт urlparse
...


класс Blockchain (объект):
    def __init __ (сам):
        ...
        self.nodes = set ()
        ...

    def register_node (сам, адрес):
        "" "
        Добавить новый узел в список узлов
        : param address:  Адрес узла. Например. 'http://192.168.0.5:5000'
        : return: Нет
        "" "

        parsed_url = urlparse (адрес)
        себя.node.add (parsed_url.netloc)  

Обратите внимание, что мы использовали набор

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

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

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

  ...
запросы на импорт


класс Blockchain (объект)
    ...
    
    def valid_chain (self, цепочка):
        "" "
        Определите, действителен ли данный блокчейн
        : param chain: <список> Блокчейн
        : return:  Истина, если действительна, ложь, если нет
        "" "

        last_block = цепочка [0]
        current_index = 1

        в то время как current_index  Истина, если наша цепочка была заменена, Ложь, если нет
        "" "

        соседи = я.узлы
        new_chain = Нет

        # Мы ищем только цепи длиннее, чем наша
        max_length = len (self.chain)

        # Возьмите и проверьте цепочки со всех узлов в нашей сети
        для узла в соседях:
            response = requests.get (f'http: // {узел} / цепочка ')

            если response.status_code == 200:
                length = response.json () ['длина']
                цепочка = response.json () ['цепочка']

                # Проверяем, длиннее ли длина и действительна ли цепочка
                если длина> max_length и self.valid_chain (цепочка):
                    max_length = длина
                    new_chain = цепочка

        # Замените нашу цепочку, если мы обнаружили новую действующую цепочку длиннее нашей
        если new_chain:
            self.chain = new_chain
            вернуть True

        return False  

Первый метод

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

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

  @ app.route ('/ nodes / register', methods = ['POST'])
def register_nodes ():
    значения = request.get_json ()

    узлы = значения.get ('узлы')
    если узлов нет:
        return "Ошибка: укажите допустимый список узлов", 400

    для узла в узлах:
        блокчейн.register_node (узел)

    response = {
        'message': 'Добавлены новые узлы',
        'total_nodes': список (blockchain.nodes),
    }
    вернуть jsonify (ответ), 201


@ app.route ('/ nodes / resolve', methods = ['GET'])
def консенсус ():
    заменено = blockchain.resolve_conflicts ()

    при замене:
        response = {
            'message': 'Наша цепочка была заменена',
            'new_chain': blockchain.chain
        }
    еще:
        response = {
            'message': 'Наша сеть авторитетна',
            'цепочка': блокчейн.цепь
        }

    return jsonify (response), 200  

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

  http: // localhost: 5000  
и

  http: // localhost: 5001  
.

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

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

  GET / nodes / resolve  
на узле 1, где цепочка была заменена алгоритмом консенсуса:

( алгоритм консенсуса в работе)

И это конец ... вместе, чтобы помочь протестировать ваш блокчейн.

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

Обновление: Я планирую продолжить часть 2, в которой мы расширим нашу цепочку блоков, добавив в нее механизм проверки транзакций, а также обсудим некоторые способы, которыми вы можете создать свою цепочку блоков.

Если вам понравилось это руководство, или у вас есть предложения или вопросы, дайте мне знать в комментариях. И если вы заметили какие-либо ошибки, не стесняйтесь вносить свой вклад в код здесь !

Согласны или не согласны с некоторыми идеями, представленными в этой статье? Сообщите
нам, что вы думаете о Digg.

Ищете еще статей о блокчейне ? Подпишитесь на нашу рассылку в нижнем колонтитуле!

Истории по теме

Теги
Присоединяйтесь к хакеру полдень