В начале января правительство Китая приказало «армии биткойн-майнеров» страны, которые генерируют 3/4 всей мировой криптовалюты, прекратить работу. Одной из главных причин такого решения стало слишком высокое количество электроэнергии, которое потребляют майнинговые фермы — сейчас на обеспечение безопасности биткойн-блокчейна и добычу монет уходит порядка 0,2% всего мирового энергопотребления.

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


/ изображение Cindy Shebley CC

Для чего нужен майнинг


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

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

В чем состоит работа майнеров


Майнеры занимаются тем, что подбирают значение хеша, которое бы подошло к транзакциям в блоке и позволило получить секретный ключ. Искомый хеш формируется на основании хеша предыдущего блока, случайного числа (nonce) и суммы хешей транзакций за прошедшие 10 минут. При этом он должен удовлетворять условиям системы: соответствовать заявленной сложности майнинга (Difficulty) и быть меньше целевой сложности (Target) — она определяет количество нулевых битов в начале искомого хеша.

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

#include <iostream>
#include <cmath>
 
inline float fast_log(float val)
{
   int * const exp_ptr = reinterpret_cast <int *>(&val);
   int x = *exp_ptr;
   const int log_2 = ((x >> 23) & 255) - 128;
   x &= ~(255 << 23);
   x += 127 << 23;
   *exp_ptr = x;
 
   val = ((-1.0f/3) * val + 2) * val - 2.0f/3;
   return ((val + log_2) * 0.69314718f);
} 
 
float difficulty(unsigned int bits)
{
    static double max_body = fast_log(0x00ffff), scaland = fast_log(256);
    return exp(max_body - fast_log(bits & 0x00ffffff) + scaland * (0x1d - ((bits & 0xff000000) >> 24)));
}
 
int main()
{
    std::cout << difficulty(0x1b0404cb) << std::endl;
    return 0;
}

На момент написания статьи сложность блокчейн-сети составляет: 2874674234415.941, однако этот параметр пересчитывается через каждые 2016 блоков. Он увеличивается или уменьшается, чтобы поддержать среднюю скорость создания блоков (примерно 6 штук в час).

SHA-256

В качестве инструмента для хеширования в биткойн-блокчейне выбран алгоритм SHA-256. Далее, мы рассмотрим один из его раундов.

?/ Раунд SHA-256 для восьми входных слов / Wikimedia / kockmeyer / CC

Предположим, что на вход алгоритму подали восемь слов, обозначим их A, B, C… H. Функция Ma выполняет побитовые операции со словами A, B и C — если большинство полученных значений нули, она также вернет ноль, иначе — единицу.

Блок ?0 трижды сдвигает слово A: на 2, 13 и 22 бита, а сформированные значения побитно складываются операцией xor. Блок ?1 работает аналогично — сдвиги выполняются на 6, 11 и 25 бит.

?Блок Ch — это функция выбора результирующего бита на основании битов в E. Если входное значение единица, то на выход поступит соответствующий бит слова F, иначе — бит слова G.

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

Для иллюстрации процесса вычисления хеша, приведем код на Python, который формирует хеш слов «Bl0Ckchain» и «blockchain»:

import itertools
from hashlib import sha256

# Представляем входные данные в порядке от младшего к старшему
to_long = lambda x: sum(ord(b) << (8*i) for i, b in enumerate(x))

# На практике обычно используется двоичное представление nonce фиксированной длины;
# строки здесь - для большей наглядности. При использовании строк
# разделитель (":") обязателен, иначе PoW можно использовать
# повторно.
combine = lambda nonce, msg: str(nonce) + ":" + msg

def verify_pow(msg, nonce, difficulty):
    h = sha256(combine(nonce, msg)).digest()
    return to_long(h) % (1 << difficulty) == 0

def create_pow(msg, difficulty):
    for nonce in itertools.count(0):
        if verify_pow(msg, nonce, difficulty): return nonce

def print_pow(msg, nonce):
    print combine(nonce, msg), sha256(combine(nonce, msg)).hexdigest()
	
#----------------------------------------------------

msg = "Bl0Ckchain"
nonce = create_pow(msg, 16)
print_pow(msg, nonce)

# 6571:Bl0Ckchain 0000d087d242930aaf6ac5a790ae8d8ece6b502cdb70ba07c1168738b253d279

assert verify_pow(msg, nonce, 16)

msg = "blockchain"
nonce = create_pow(msg, 16)
print_pow(msg, nonce)

# 43952:blockchain 000027b5022f88d2da21bd2802268966050f5a0b031058ce4562939c13727303

assert verify_pow(msg, nonce, 16)
# Количество проделанной работы лишь статически близко к (1 << difficulty),
# для конкретных сообщений возможны отклонения
msg = "Bl0Ckchain"
nonce = create_pow(msg, 16)
print_pow(msg, nonce)
# 6571:Bl0Ckchain 0000d087d242930aaf6ac5a790ae8d8ece6b502cdb70ba07c1168738b253d279
assert verify_pow(msg, nonce, 16)

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

msg = "blockchain"
nonce = 5263268363
print_pow(msg, nonce)
# 5263268363:blockchain 000000007cf39dfc8fccae534b39b5f362c16891abca02d0e7b1dbd5a129ee17
assert verify_pow(msg, nonce, 32)

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

Так как биткойн-протокол использует двойное хеширование, то задачей майнеров становится нахождение второго прообраза хеша x’ (имея первый прообраз x хеша y, где y=H(x)), который бы удовлетворял условию y=H(x'). Однако с целью упрощения задачи, майнеры ищут лишь частичный прообраз — H(x)/2^(n-k)=0. Здесь n — «размер» результата (n=256 бит для SHA256), а k — это фактор, отвечающий за количество нулей в результирующем хеше. Например, k=20 потребует проведения порядка одного миллиона попыток.

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

Майнинг — совместные усилия участников сети


Сложность решения блока чрезвычайно велика. Сейчас майнеры в биткойн-сети выполняют порядка 20 млн терахешей в секунду, и эта цифра растет. Для сравнения, одна видеокарта выдает порядка 30 мегахешей в секунду. Также в своем блоге инженер Кен Ширриф (Ken Shirriff) попробовал решить блок с помощью ручки и бумаги — его достижение было еще скромнее (0,67 хешей в день).


/ Количество терахешей за секунду, по данным blockchain.info

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

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

За организацию взаимодействия пула и майнеров отвечают специальные протоколы. Например, протокол Stratum (еще есть Getwork, Getblocktemplate и другие), который используется большинством пулов. В своем блоге Кен Ширриф приводит код, пересылаемый пулом при выдаче задания, который содержит всю необходимую информацию для начала работы над блоком.

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

По своей сути майнинг биткойнов напоминает своеобразную «гонку вооружений». В самом начале люди майнили криптовалюту с помощью CPU, затем мощности центрального процессора стало недостаточно, и индустрия перешла на GPU и специализированное оборудование ASIC.

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

Но подобная привязка к технике и «реальному миру» имеет свои недостатки. Как уже было отмечено, майнинг — достаточно «затратная» с точки зрения потребления энергии деятельность. На сегодняшний день биткойн-блокчейн расходует 48 ТВт/час в год, причем 30–40% энергии идет на охлаждение чипов.

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

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



Предлагаем вам еще несколько материалов о работе блокчейнов из нашего блога:

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



  1. p00h
    11.02.2018 13:18

    Опять?


  1. Hile
    11.02.2018 13:27

    Горшочек не вари


  1. StjarnornasFred
    11.02.2018 13:30
    +1

    Спасибо за подробную статью. Вероятно, подобных уже было много, но мне она была полезна хотя бы в части описания цели майнинга. Так что критики за «опять?» не будет.

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


    1. DrPass
      11.02.2018 16:19

      Криптовалюты на основе блокчейна существовать как децентрализованные финансовые инструменты никогда и не будут. Какие бы меры для увеличения пропускной способности не предпринимались, против элементарной логики не пойдёшь: размер биткойновского блокчейна с его скоростью 7-14 транзакций/секунду за год вырос на 50 Гб. Несложно прикинуть, что если сеть биткойна как-то научится обрабатывать хотя бы 10% от объема транзакций сети VISA, то блокчейн в год будет расти примерно на полтора терабайта. Никакие пользовательские компьютеры не смогут это поддерживать. Кошельки смогут быть только на мощных централизованных серверах.


      1. vtools
        11.02.2018 20:26

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

        P.S.
        Извините за сохранение вашей стилистики «доказательства»…


        1. DrPass
          11.02.2018 23:52

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

          Шардинг эту проблему кардинально не решит. Зато ещё острее станет проблема и так невысокой производительности сети.


          1. vtools
            12.02.2018 12:55

            Вы забываете добавить слово «имхо». Если вы не знаете такого способа это не значит что его не существует. Я, например, знаю такой алгоритм, который позволит радикально сократить количество сетевого трафика, даже не прибегая к шардингу. Я могу о нем более подробно рассказать, если вам интересно. Вкратце: все ноды изначально упорядочиваются (относительно своего адреса-публичного ключа), затем обмен идет только уникальной информацией. Число обменов примерно равно логарифму размера сети. Размер общей переданной информации примерно равно одному блоку. По сравнению с текущими протоколами это дает ускорение в 1000 раз (алгоритм уже проверен в тестовой сети).


      1. selivanov_pavel
        11.02.2018 21:38

        Уже сделали алгоритмы и протоколы, позволяющие оперировать кошельком не храня весь блокчейн. Майнить не получится, а тратить и принимать койны — пожалуйста. http://docs.electrum.org/en/latest/spv.html#simple-payment-verification


  1. San_tit
    11.02.2018 18:28

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


  1. ToshiruWang
    12.02.2018 12:09

    Во всём этом интересует ответ на вопрос — я, как частник, не участвующий ни в одном пуле, купил себе мощный CPU, GPU, много GPU, ASIC, несколько ASICов, но всё это составляет очень смешную долю от мировых мощностей (и, возможно, совсем не смешные расходы на электроэнергию для меня).
    И, как следствие, вариант нахождения следующего блока именно мной составляет тот же жалкий процент и если я не нахожу блок, то я не получаю с него процент за комиссии (потому как каждый находящий блок включает их в качестве транзакций себе) и не получаю биткойны за новый блок. По прикидкам ситуация нахождения мной блока через час-день-неделю после нахождения его же (прямого наследника того блока, наследника которого я нахожу) не лучше — просто спалил больше ресурсов. Я, конечно, кидаю его в чейн, но поезд ушёл и по длине ветки я проигрываю. Остаётся только чистая случайность — когда повезёт мне, а не одному из 100500 китайцев (приклеить 4хлистный клевер, побрызгать святой водой на электрические соединения).
    Из этого следует вывод что варианта «просто куплю оборудование — начну богатеть» не работает. Или я где-то не прав?


    1. vtools
      12.02.2018 12:45

      Из этого следует вывод что варианта «просто куплю оборудование — начну богатеть» не работает. Или я где-то не прав?

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


  1. Daniyar94
    13.02.2018 02:24

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


    А зачем пулу результат с 10 нулями? Он же не приблизит к решению с 15 нулями? Или я что-то не понял?


    1. vtools
      13.02.2018 11:11

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

      Тут нужно понять одну важную вещь: поиск «красивого хеша» это случайный процесс. Может так получится, что вы на самом простом компьютере начали вычислять хеши и вам сразу попался нужный хеш. Вот только вероятность такого события очень маленькая. Но если таких майнеров у пула будет миллион, то и вероятность увеличивается в миллион раз. А выигрыш распределяется на миллион майнеров, т.к. особой заслуги конкретного майнера не было — это был случайный процесс. Следующий раз найдет другой майнер, а монета опять распределится на всех (пропорционально мощности).


  1. Daniyar94
    13.02.2018 02:27

    Так и не написали, как биткойны «генерируются»? Как я понял в Etherium’е коины генерятся при создании. А тут как?