Блокчейн используется не только в криптовалютах, а также в тех областях где нужно сопровождать доказанную последовательность определенных событий или состояний. Об этом буквально и говорит само слово blockchain: цепочка блоков. Таким образом, с системной точки зрения мы имеем блоки и связи между ними. Наша задача — препарировать блок таким образом, чтобы установить наличие данной связи (проверка блокчейна). Или создать новую связь — это уже майнинг, слово приводящее в трепет публику которая вращается в мире криптовалют.
Поработаем с блоками и связями такой популярной криптовалюты, как BitCoin.
Блоки и связи / Block & Chains
Типичный блок выглядит следующим образом:
{
"hash":"0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103",
"ver":1,
"prev_block":"00000000000007d0f98d9edca880a6c124e25095712df8952e0439ac7409738a",
"mrkl_root":"935aa0ed2e29a4b81e0c995c39e06995ecce7ddbebb26ed32d550a72e8200bf5",
"time":1322131230,
"bits":437129626,
"nonce":2964215930,
"n_tx":22,
"size":9195,
"block_index":818044,
"main_chain":true,
"height":154595,
"received_time":1322131301,
"relayed_by":"108.60.208.156",
"tx":[--Array of Transactions--]
{
Блоки хорошо представлять в виде вагончиков, которые сцепляются друг с другом. Эта аналогия обладает еще одним ценным соответствием: самый первый вагончик, то есть паровозик, не сцеплен спереди ни с кем. Это самый верхний блок в системе, и он будет самым верхним до тех пор, пока кто-нибудь не намайнит следующий блок. Тогда новый блок становится паровозиком во главе состава и к нему подцепляется остальная цепочка.
Все! В блокчейне больше ничего нет, кроме сцепленных вагончиков — блоков. Теперь нужно понять, что выполняет роль этой сцепки. Вот тут в этом месте наше сравнение с вагончиками не сработает, потому что в пассажирском или грузовом составе каждый вагон может быть сцеплен с любым другим вагоном или локомотивом, а в случае блокчейна для того чтобы вагончики сцепились, их сцепной механизм должен иметь одинаковый код.
В блоках роль этого кода выполняют значения ключей hash и prev_block. В блокчейне значение prev_block каждого блока в точности совпадает со значением hash предыдущего блока, и аналогично hash каждого блока совпадает со значением prev_block последующего блока. При этом при вычислении значения hash используется хэш предыдущего блока, что делает цепочку хешей зависимой друг от друга.
Поскольку hash — это фактически хэш блока, то такой механизм обеспечивает не только однозначность последовательности блоков, но и защиту содержимого блока. Попытка изменить последовательность блоков, удалить блоки или вставить новые, а также поменять содержимое самих блоков ни к чему не приведет: нарушится соответствие последовательности хэшей. Поэтому с блокчейном ничего сделать нелья: можно только добавить новый блок спереди. Это уже майнинг!
Block Parsing
Распарсим один из блоков блокчейна. Я взял для примера блок #528340, хэш которого имеет значение
0000000000000000002740c2167e7dcea59e11362587ea9ed348022701f5a73d.
Вы наверное обратили внимание на то, что хэши имеют вначале большое количество нулей, что вообще-то говоря очень странно для хэш-функции, которая должна выглядеть как стопроцентно случайная последовательность. В этом и есть соль майнинга: блок получает право возглавить блокчейн только в том случае, если его хеш будет иметь в начале определенное количество нулей. В этом и заключается вычислительная трудность, на которую тратят время майнеры.
Заканчиваем с лирическими отступлениями и приступаем к парсингу. Блок будем брать прямо с сайта по его хэшу:
# block #528340 hash block_hash = '0000000000000000002740c2167e7dcea59e11362587ea9ed348022701f5a73d' url = 'https://blockchain.info/rawblock/%s' r = requests.get(url % block_hash) print(r.status_code) data = json.loads(r.text)
Если код статуса равен 200, значит на запрос получен ответ с нужными данными в формате JSON, которые преобразуются в словарь с парами ключ — значение (переменная data).
Поскольку изобретатели алгоритма решили работать с данными справа налево, в режиме реверса последовательности байтов в строке, я написал вспомогательную функцию которая это делает:
def sformat(data, arg):
s = data[arg]
l = list(s)
i=0
for ch in reversed(s):
if i%2 != 0:
l[i-1]=ch
l[i]=ch0
else:
ch0=ch
i+=1
ret = ''.join(l)
print('%s: %s' % (arg,ret))
return(ret)
Переформатируем все переменные, которые будут принимать участие в вычислении хэша:
bl=sformat(data, 'hash')
pb=sformat(data, 'prev_block')
mr=sformat(data, 'mrkl_root')
# new dict to unify call function sformat()
data2 = {'ver':'','time':'','bits':'','nonce':''}
data2['ver']='%x' % data['ver']
ve=sformat(data2, 'ver')
data2['time']='%x' % data['time']
ti=sformat(data2, 'time')
data2['bits']='%x' % data['bits']
bi=sformat(data2, 'bits')
data2['nonce']='%x' % data['nonce']
no=sformat(data2, 'nonce')
Теперь все это нужно смешать в одну кучу
header=ve+pb+mr+ti+bi+no
и найти значение хэша нашего блока:
header_bin = header.decode('hex')
pass1=sha256(header_bin).digest()
new_block=sha256(pass1).digest()[::-1].encode('hex')
Не забываем, что в этой операции участвовал хэш предыдущего блока prev_block. В результате получаем заветную строчку со многими нулями вначале — это и есть хэш нашего блока, все соответствует.
Полезная нагрузка: транзакции
За повествованием мы забыли про полезное наполнение блока, ради чего все собственно затевалось: про транзацкции, кто кому сколько перечислил. Транзакций в блоке великое множество, они проходят под ключом tx. Gосмотрим только одну из, например самую верхнюю n=0:
print(json.dumps(data['tx'][n], ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ': ')))
Информацию дает строчка json.dumps(data[‘tx’][n]), остальное — красивости для удобочитаемого вывода. В результате увидим:
{
"hash": "eaa674093137d79c025f2a86660c25af3c9ba492542c0f92daa5b58c1e5a15b9",
"inputs": [
{
"script": "03d40f08046d1b2a5b2f4254504f4f4c2ffabe6d6d4a6c034e5c60e2b4ff7ae75f8a2160ece386d768b82cf03f745694e8b2a911d9010000000000000002019a460996010000000000",
"sequence": 4294967295,
"witness": "01200000000000000000000000000000000000000000000000000000000000000000"
}
],
"lock_time": 0,
"out": [
{
"addr": "1MsEbXvTs8mHy5vS9hgyMPq5Xx4umiuYrX",
"n": 0,
"script": "76a914e4e2a9a247f46c81fa2cc33523ccfac977a370c588ac",
"spent": false,
"tx_index": 355525333,
"type": 0,
"value": 1430000492
},
{
"n": 1,
"script": "6a24aa21a9edb744306372d97b47e5f81708eb8a2e3ef1790c0a128345008e2eb299400e68b1",
"spent": false,
"tx_index": 355525333,
"type": 0,
"value": 0
}
],
"relayed_by": "0.0.0.0",
"size": 241,
"time": 1529486188,
"tx_index": 355525333,
"ver": 1,
"vin_sz": 1,
"vout_sz": 2,
"weight": 856
}
Видно, что некто перечислил 14.3 BTC кому-то. Именно так: кошельки отправителя и получателя представлены в виде хэшей, и кто это такие — мы не знаем. Собственно это и есть краеугольный камень БитКойна.
Блокчейн хранит абсолютно все транзакции, которые были в системе. По этой причине совершенно четко видно, как появляются монеты и к кому они переходят, и какое общее количество их находится в системе.
На этом завершим наш небольшой анализ, ведь главное мы уже сделали: показали как вагончики сцепляются друг с другом и уникальность этой сцепки.
Добавить комментарий