Технический документ, по- видимому, закодирован как 54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713 , что представляет собой m из n multisig Tx с 947 выходами (чуть меньше предела scriptsig в 20 КБ!).
Используя Blocktrail Python SDK , я получаю список выходных данных в виде шестнадцатеричного кода, используя следующий код Python (2.7) (примечание: параметры APIKEY , APISECRET доступны, если требуется, на сайте www.blocktrail.com ):
from blocktrail import APIClient
bt_client = APIClient(APIKEY, APISECRET, network='BTC')
txnObj = bt_client.transaction('54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713')
hashes = [(t['script_hex']) for t in (txnObj)['outputs']]
Полученный список доступен здесь в полном объеме и, по сути, состоит из всех Txns pay-to-pubkey-script. Выдержка:
[u'5141e4cf0200067daf13255044462d312e340a25c3a4c3bcc3b6c39f0a322030206f626a0a3c3c2f4c656e6774682033203020522f46696c7465722f466c617465446541636f64653e3e0a73747265616d0a789cad5c4b8b24b911becfafa8b3a1da292925654253d0d55373f06d61c007e39bbd061f0cde8bffbe25c55b5266f61ab3905d419ba54728e28bb76a963777fbcfb77fdf96db7d291f93f3e599f7fafcedefb73fffe1f6aff665fdefb77f7c7bfefce6c2fa166e695bdfd6dbcfbfddfef8c3dd5cf953ae',
.....
u'514130206e200a30303030313832353430203030303030206e200a747261696c65720a3c3c2f53697a652036382f526f6f74203636203020520a2f496e666f20363720413020520a2f4944205b203c43413142304134344244353432343533424546393138464643443436444330343e0a3c4341314230413434424435343234353342454641393138464643443436444330343e205d0a2f446f63436865636b73756d202f36463732454137353134444641443233464142434337413535303032314146370a3e53ae',
u'51213e0a7374617274787265660a3138323732370a2525454f460a000000000000000051ae',
u'76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac',
u'76a914031c79236ff3017496cf8d9a883f494458f245f288ac']
ВОПРОС: Как этот массив шестнадцатеричных данных преобразуется в биткойн.pdf ? Конкретные ответы в формате Python будут оценены!
По сути, это забавная маленькая головоломка на блокчейне. Во-первых, вам нужно немного узнать о pdf-файлах и их структуре, которые вы можете найти здесь .
Во-вторых, вы заметите в разделе 3.4.1, что все pdf-файлы начинаются с этой строки:
%PDF-
В шестнадцатеричном формате, то есть 255044462d
. И действительно, это в самом первом выводе самого первого голого мультиподписного ключа:
<e4cf0200><067daf13>**255044462d**312e340a25c3a4c3bcc3b6c39f0a322030206f626a0a3c3c2f4c656e6774682033203020522f46696c7465722f466c6174654465
Я не понял, для чего предназначены первые 8 байтов (♦ edit : e4cf0200067daf13 = 2x 4byte little Endian "checksums", see @WizardOfOzzie comment below
), но остальные голые мультиподписные ключи (все между 1 и 3 OP_CHECKMULTISIG в каждом выводе - обратите внимание, что последний - 1 из 1, так что это 1 OP_CHECKMULTISIG) это фрагменты данных для pdf и они в порядке. Если вы можете поместить все шестнадцатеричные цифры голых мультиподписных ключей в один файл (без пробелов) с именем «fromblockchain.hex», вы можете запустить эту очень простую программу для извлечения pdf:
contents = open('fromblockchain.hex').read()
bytes = contents[16:].decode('hex')
f = open("bitcoin.pdf")
f.write(bytes)
f.close()
Это должно создать биткойн.pdf, который является настоящим техническим документом по сатоши. Я проверил это, и это действительно технический документ. Приятно знать, что это буквально в блокчейне.
В качестве альтернативы, если на вашем компьютере запущен биткойн, вы можете запустить этот скрипт python, чтобы получить технический документ биткойнов:
import subprocess
# raw = full hex of raw Tx using Bitcoin-cli
raw = subprocess.check_output(["bitcoin-cli", "getrawtransaction", "54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713"])
outputs = raw.split("0100000000000000")
pdf = ""
for output in outputs[1:-2]:
# there are 3 65-byte parts in this that we need
cur = 6
pdf += output[cur:cur+130].decode('hex')
cur += 132
pdf += output[cur:cur+130].decode('hex')
cur += 132
pdf += output[cur:cur+130].decode('hex')
pdf += outputs[-2][6:-4].decode("hex")
f = open("bitcoin.pdf", "wb")
f.write(pdf[8:-8])
f.close()
Наконец проверка контрольной суммы
sha256sum bitcoin.pdf
b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553 bitcoin.pdf
0x5141
и между 0x41
s. Что случилось со стандартными двумя последними выходами 76a914____88ac
?pdf += outputs[-2][6:-4].decode('hex')
. Также необходимо использовать openopen("bitcoin.pdf", 'wb')
(двоичный режим). Мне нужно будет изучить мультиподпись больше b/c. Я до сих пор не понимаю, почему остальные мультиподписи подталкивают байты 0x41, а последние подталкивают только байты 0x21.bitcoin.pdf
=> rawhextx
) с помощью Python? Форумы / сабреддиты, посвященные Python, с трудом понимают аспект Биткойн. РЕДАКТИРОВАТЬ: да, я знаю, что это нестандартный Tx; это только для интеллектуального любопытства0xe4cf0200067daf13
( "Я так и не понял, для чего нужны первые 8 байт" ). На самом деле это 2x 4-байтовые «контрольные суммы». В частности, маленькие шестнадцатеричные представления Endian: <total pdf size>
<crc32 for pdf>
ie 184292
330267910
;)bitcoincore.org
и она, похоже, отличается. Я предполагаю, что это какая-то нерелевантная вещь метаданных.getrawtransaction
теперь принимает необязательный blockhash
аргумент. Так что это устраняет необходимость -txindex
здесь.Это команда bash, которая также может дать вам файл:
bitcoin-cli getrawtransaction 54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713 0 00000000000000ecbbff6bafb7efa2f7df05b227d5c73dca8f2635af32a2e949 | sed 's/0100000000000000/\n/g' | tail -n +2 | cut -c7-136,139-268,271-400 | tr -d '\n' | cut -c17-368600 | xxd -p -r > bitcoin.pdf
Ему не нужен -txindex
, но нужен полный узел, а не обрезанный. Я полагаю, что можно сделать вариант, gettxout
который работает с обрезанными узлами, но это остается в качестве упражнения для читателя.
seq 0 947 | (while read -r n; do bitcoin-cli gettxout 54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713 $n | jq -r '.scriptPubKey.asm' | awk '{ print $2 $3 $4 }'; done) | tr -d '\n' | cut -c 17-368600 | xxd -r -p > bitcoin.pdf
Источник: bitcoinhackers.org/@jb55/105595146491662406В PDF-файле используются скрипты загрузки/загрузки Python, присутствующие в самой цепочке биткойнов.
Эти скрипты присутствуют по адресу:
Это мои разветвления Gists Кена Ширриффа, которые, предположительно, нашли их во время поиска: http://www.righto.com/2014/02/ascii-bernanke-wikileaks-photographs.html
Оба скрипта имеют заголовок с копирайтом:
#
# File downloader
# Requires git://github.com/jgarzik/python-bitcoinrpc.git
#
# (c) 2013 Satoshi Nakamoto All Rights Reserved
#
# UNAUTHORIZED DUPLICATION AND/OR USAGE OF THIS PROGRAM IS PROHIBITED BY US AND INTERNATIONAL COPYRIGHT LAW
что, вероятно, является шуткой и, на мой взгляд, написано не Сатоши.
И загрузчик, и загрузчик загружаются с кодировкой загрузчика, что создает небольшую проблему начальной загрузки курицы и яйца для загрузки загрузчика. Но кодировка настолько проста, что вы можете просто загрузить необработанные данные загрузчика и исправить их вручную.
После загрузки загрузчика вручную мне удалось запустить его, чтобы извлечь побайтовое соответствие PDF-файлу, представленному на https://web.archive.org/web/20210418161957/https://bitcoin.org/bitcoin.pdf . (sha256 == b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553).
Во-первых, вам нужно локально запустить основной сервер Биткойн. Предположим, что ваш .bitcon/bitoin.conf
содержит:
rpcuser=asdf
rpcpassword=qwer
server=1
txindex=1
Затем я запускаю:
git clone git://github.com/jgarzik/python-bitcoinrpc.git
git -C python-bitcoinrpc checkout cdf43b41f982b4f811cd4ebfbc787ab2abf5c94a
wget https://gist.githubusercontent.com/shirriff/64f48fa09a61b56ffcf9/raw/ad1d2e041edc0fb7ef23402e64eeb92c045b5ef7/bitcoin-file-downloader.py
pip install python-bitcoinrpc==1.0
BTCRPCURL=http://asdf:qwer@127.0.0.1:8332 \
PYTHONPATH="$(pwd)/python-bitcoinrpc:$PYTHONPATH" \
python3 bitcoin-file-downloader.py \
54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713
где tx 54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713 (блок 230009) — транзакция, в которой закодирован технический документ.
Кодировка, используемая скриптом загрузчика
Загрузчик не очень строг к тонкостям загрузчика. Мы можем сразу понять его формат из источника:
data = b''
for txout in tx['vout'][0:-2]:
for op in txout['scriptPubKey']['asm'].split(' '):
if not op.startswith('OP_') and len(op) >= 40:
data += unhexlify(op.encode('utf8'))
length = struct.unpack('<L', data[0:4])[0]
checksum = struct.unpack('<L', data[4:8])[0]
data = data[8:8+length]
if checksum != crc32(data):
print('Checksum mismatch; expected %d but calculated %d' % (checksum, crc32(data)),
file=sys.stderr)
sys.exit()
так что мы видим, что это:
Тогда из приведенных выше данных:
Кодировка, используемая сценарием загрузчика
Загрузчик немного более конкретен. Пожалуй, проще всего это понять, посмотрев на разборку небольшой загрузки, например самого загрузчика: https://www.blockchain.com/btc/tx/6c53cd987119ef797d5adccd76241247988a0a5ef783572a9972e7371c5fb0cc
Сначала у нас есть куча выходов типа:
OP_1 data OP_3 OP_CHECKMULTISIG
и стоит крошечные 0,00000001 BTC, которые содержат большую часть данных. Предположительно, они не могут быть потрачены из-за OP_CHECKMULTISIG
, но это также не может быть доказано.
Затем в конце у нас есть две разные транзакции, которые, как мы видели выше, загрузчик игнорирует:
стандартный P2PKH OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
с минимальным значением 0,00000001 BTC и неизрасходованным. ТОДО почему? Это соответствует части кода:
# dest output
out_value = Decimal(sys.argv[3])
change -= out_value
txouts.append((out_value, OP_DUP + OP_HASH160 + pushdata(addr2bytes(sys.argv[2])) + OP_EQUALVERIFY + OP_CHECKSIG))
который показывает, что вы просто передаете произвольное целевое значение и адрес из своего скрипта.
стандартная проводная транзакция изменения P2PKH со значительным значением, чтобы восстановить остатки от ввода. Он отправляется на новый адрес, принадлежащий вам, который создается «на лету» с помощью вызова RPC:
change_addr = proxy.getnewaddress()
txouts.append([change, OP_DUP + OP_HASH160 + pushdata(addr2bytes(change_addr)) + OP_EQUALVERIFY + OP_CHECKSIG])
Чтение источника в основном подтверждает то, что мы видим на разборке. Далее следуют некоторые другие указатели.
В:
data = open(sys.argv[1],'rb').read()
data = struct.pack('<L', len(data)) + struct.pack('<L', crc32(data)) + data
fd = io.BytesIO(data)
мы видим:
struct.pack('<L', len(data))
добавляется в начало файла.
В:
def checkmultisig_scriptPubKey_dump(fd):
data = fd.read(65*3)
if not data:
return None
r = pushint(1)
n = 0
while data:
chunk = data[0:65]
data = data[65:]
if len(chunk) < 33:
chunk += b'\x00'*(33-len(chunk))
elif len(chunk) < 65:
chunk += b'\x00'*(65-len(chunk))
r += pushdata(chunk)
n += 1
r += pushint(n) + OP_CHECKMULTISIG
return r
мы видим основной цикл кодирования данных. Это выясняется из разборки:
OP_1 data OP_3 OP_CHECKMULTISIG
фиксируется OP_1
наpushint(1)
OP_3
может быть меньше 3, он кодирует, сколько фрагментов по 65 байт было закодировано, при этом на каждом выходе присутствует максимум 3 фрагмента из- заfd.read(65*3)
OP_1
Таким образом , последняя транзакция полезной нагрузки может иметь OP_2
или OP_3
в зависимости от степени детализации.
Для чего еще использовался скрипт загрузчика и был ли он популярен?
В:
Я проиндексировал каждую транзакцию в блокчейне, которая следует указанному выше формату, в частности, имеющую соответствующий CRC32 в первых 8 байтах.
Мне также удалось загрузить и интерпретировать каждую из транзакций, как кратко описано по адресу: https://cirosantilli.com/cool-data-embedded-in-the-bitcoin-blockchain/illegal-content-of-block-229k .
По сути, очень скоро после того, как загрузчик/загрузчик были загружены на 229991, помимо технического документа, было сделано несколько загрузок, преднамеренно содержащих то, что некоторые страны могут считать незаконными данными, хотя ни одна из них не бросалась в глаза по моим сумасшедшим стандартам, и, как мы видели, до сих пор блокчейн Биткойн пережил их на данный момент по состоянию на 2021 год.
Поскольку незаконный контент был загружен вскоре после того, как загрузчик, я считаю весьма вероятным, что он был загружен тем же человеком, который создал загрузчик.
И после непродолжительного всплеска активности загрузка прекратилась, и намного позже была сделана только одна загрузка по адресу tx 89248ecadd51ada613cf8bdf46c174c57842e51de4f99f4bbd8b8b34d3cb7792, которая привлекла мое внимание, потому что она содержит изображение Будды в формате ASCII между двумя символами Инь-Ян, как описано по адресу: https:// cirosantilli.com/cool-data-embedded-in-the-bitcoin-blockchain/ascii-art
69696969 69696969
6969 696969 696969 6969
969 69 6969696 6969 6969 696
969 696969696 696969696969 696
969 69696969696 6969696969696 696
696 9696969696969 969696969696 969
696 696969696969 969696969 969
696 696 96969 _=_ 9696969 69 696
9696 969696 q(-_-)p 696969 6969
96969696 '_) (_` 69696969
96 /__/ \ 69
69 _(<_ / )_ 96
6969 (__\_\_|_/__) 9696
Поэтому мой вывод таков, что скрипты загрузчика и загрузчика просто никогда не пользовались значительной популярностью.
Они слишком перегружены и неуклюжи, чем нужно. Зачем вам нужен CRC32, когда сам блокчейн уже хеширован побайтно до краев? Возможно, он был задуман просто как маркер «интересной информации». Но гораздо более естественным и доминирующим позже было использование строк ASCII или просто магических байтов определенных форматов файлов в качестве маркеров, см., например, мои комментарии к более прямо закодированным изображениям по адресу:
Волшебник Оззи
Ник Оделл
scriptsig limit of 20kB!
Я знал об ограничении в 10 КБ, введенном вEvalScript
, но о каком ограничении в 20 КБ вы говорите?Волшебник Оззи