Что-то я не встречал пошаговой инструкции на русском языке о том, как создать Биткоин транзакцию без программирования.
То есть понятно, что для создания стандартной транзакции отправки монет, можно пользоваться GUI кошельком или командой консоли типа sendtoaddress, но что если хочется создать стандартную транзакцию с нестандартным запирающим скриптом..? Попробую тут описать весь процесс.
Пост получаяется длинным, поэтому буду дополнять постепенно.Используемые источники
1.
https://medium.com/coinmonks/how-to-create-a-raw-bitcoin-transaction-step-by-step-239b888e87f22.
https://en.bitcoin.it/wiki/Protocol_documentation#tx3.
https://bitcoin.org/en/developer-reference#raw-transaction-formatПредисловиеСам я кодер, поэтому и тему разместил в разделе "Кодеры", но надеюсь, что инструкция будет доступна для понимания именно "не кодерам". То есть попробую описать инструкцию для обычного человека у которого кроме блокнота и клиента bitcoin-qt ничего специального на компьютере не установлено.
Итак начнем.Как я уже выше упомянул, из инструментов нам понадобятся следующие приложения:
1. Блокнот
2. bitcoin-qt
Это все.
Продолжаем.Если вы не сын/дочь миллионера, то наверняка не захотите экспериментировать с настоящими биткоинами которые стоят денег. Поэтому запустите bitcoin-qt в тестовом режиме. Для этого
ИЛИ Сделайте ярлык на рабочий стол и в свойствах ярлыка (вкладка общие) после bitcoin-qt.exe допишите через пробел параметр
-testnet
ИЛИ Вместо свойства ярлыка можете создать файл bitcoin.conf в директории %APPDATA%/Bitcoin
В этом файле напишите текст
testnet=1
Если все сделаете правильно, то кошелек bitcoin core будет запускаться в тестовой сети.
В тестовой сети другие адреса и другие, бесплатные биткоины. Чтобы начать экспериментировать, вам нужно дождаться синхронизации тестового блокчейна и пополнить кошелек тестовыми биткоинами с кранов. Краны можете погуглить сами, они все время то появляются, то протухают...
Когда кошелек пополненНу вот с этого момента и начинается самое интересное. Зайдите в меню Помощь - Окно отладки - Консоль. Введите туда самую главную команду:
help
В консоли отобразятся все доступные команды вашего кошелька bitcoin-qt. Если хотите получить хелп по конкретной команде (с примерами использования), то введите в консоль например
help sendtoaddress
Напомню, что наша цель создать транзакцию вручную. Чтобы посмотреть, что примерно у нас должно получиться в итоге, можете посмотреть какую-нибудь транзакцию из своего кошелька. Введите в консоли
listunspent
Увидите список непотраченных транзакций в вашем кошельке. Возьмите из списка txid любой транзакции и введите в консоль например
getrawtransaction 2e4308716eaaf6d27d2b91bfe2a78fc7819176966b619b6d8dc675f5373aa3d9
На выходе получите
0200000000010218f739a82336bfec14c75a55ef28260b493ea89711319ba799368380328ddbe0000000001716001408a8ba315488b40811b9886ff4396e0c94ce183efeffffff
6cc66a094304e399a9678dfbf1f88a8f2223c67d38ad0c69f5a8426d54ab479a000000006a473044022062e7ba2ec9a4a26fba867624b7786f6e1cd11363186bcf73a5a163b2f32f1d1e02204 332986870d8e8d54545313deabab49586d851f7c74c185026b731b0e172d20b012103903c1d380a 2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff02
02450f000000000017a9148536bef594948115aa8ea99ce415767df30f8a3a87a06f2200000000001976a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888ac02
4730440220724686754b2c80564048cbafab84e07ab91f9e9a64c1baca8e726de70209e9cd02201f9 1ac61ce789e7032c2561dc24e26adca029d6449d82e96c252ace18d4dbba40121026f627029af8b372f3c81c5ae5cb4ce0971fb6d059e22351bc7191d9841a4156e00ac1f1800
Давайте на этом примере разберем: кто тут есть ху?
Заголовок транзакцииВерсия | 02000000 | первые 4 байта. Всегда одно и то же число |
Флаг | 0001 | показывает - есть ли в транзакции данные SegWit |
Число входов в транзакцию | 02 | |
Вход 1ИД входящей транзакции | 18f739a82336bfec14c75a55ef28260b493ea89711319ba799368380328ddbe0 | |
Номер выхода у входящей транзакции | 00000000 | |
Размер тратящего скрипта | 17 | длина scriptSig скрипта = 0x17 = 23 байта |
Тратящий скрипт | 16001408a8ba315488b40811b9886ff4396e0c94ce183e | |
sequence | feffffff | думаю лучше это название оставить на английском |
Вход 2ИД входящей транзакции | 6cc66a094304e399a9678dfbf1f88a8f2223c67d38ad0c69f5a8426d54ab479a | |
Номер выхода у входящей транзакции | 00000000 | |
Размер тратящего скрипта | 6a | длина scriptSig скрипта = 0x6a = 106 байт |
Тратящий скрипт | 473044022062e7ba2ec9a4a26fba867624b7786f6e1cd11363186bcf73a5a163b2f32f1d1e02204 332986870d8e8d54545313deabab49586d851f7c74c185026b731b0e172d20b012103903c1d380a 2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdf | |
Число выходов транзакции: 02Выход 1Количество сатошей в выходе
02450f0000000000 (0x00000000000f4502 = 1000706 = 0,01000706 BTC)
Длина запирающего скрипта
17 (0x17 = 23 байта)
Запирающий скрипт
a9148536bef594948115aa8ea99ce415767df30f8a3a87Выход 2Количество сатошей в выходе
a06f220000000000Длина запирающего скрипта
19Запирающий скрипт
76a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888acЧисло SegWit данных в первом входе: 02SegWit блок 1Длина данных:
47 (71 байт)
Данные:
30440220724686754b2c80564048cbafab84e07ab91f9e9a64c1baca8e726de70209e9cd02201f9 1ac61ce789e7032c2561dc24e26adca029d6449d82e96c252ace18d4dbba401SegWit блок 2Длина данных:
21 (33 байта)
Данные:
026f627029af8b372f3c81c5ae5cb4ce0971fb6d059e22351bc7191d9841a4156eЧисло SegWit данных во втором входе: 00Locktime:
ac1f1800 (0x00181fac = 1580972)
Вот собственно и вся транзакция txid = 2e4308716eaaf6d27d2b91bfe2a78fc7819176966b619b6d8dc675f5373aa3d9. Далее я попробую описать по шагам процесс создания новой транзакции, которая будет тратить какой-нибудь из выходов.
Кстати говоря, декодировать RAW транзакцию конечно удобней не вручную, а в консоли:
decoderawtransaction 0200000000010218f739a82336bfec14c75a55ef28260b493ea89711319ba799368380328ddbe0000000001716001408a8ba315488b40811b9886ff4396e0c94ce183efeffffff6cc66a094304e399a9678dfbf1f88a8f2223c67d38ad0c69f5a8426d54ab479a000000006a473044022062e7ba2ec9a4a26fba867624b7786f6e1cd11363186bcf73a5a163b2f32f1d1e02204332986870d8e8d54545313deabab49586d851f7c74c185026b731b0e172d20b012103903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff0202450f000000000017a9148536bef594948115aa8ea99ce415767df30f8a3a87a06f2200000000001976a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888ac024730440220724686754b2c80564048cbafab84e07ab91f9e9a64c1baca8e726de70209e9cd02201f91ac61ce789e7032c2561dc24e26adca029d6449d82e96c252ace18d4dbba40121026f627029af8b372f3c81c5ae5cb4ce0971fb6d059e22351bc7191d9841a4156e00ac1f1800 1
Даст красивый результат:
{
"txid": "2e4308716eaaf6d27d2b91bfe2a78fc7819176966b619b6d8dc675f5373aa3d9",
"hash": "3dc884c4d56e4d940ce3d52c7e41956e26c5393ace11f594baaac7699938d79a",
"version": 2,
"size": 397,
"vsize": 315,
"weight": 1258,
"locktime": 1580972,
"vin": [
{
"txid": "e0db8d3280833699a79b311197a83e490b2628ef555ac714ecbf3623a839f718",
"vout": 0,
"scriptSig": {
"asm": "001408a8ba315488b40811b9886ff4396e0c94ce183e",
"hex": "16001408a8ba315488b40811b9886ff4396e0c94ce183e"
},
"txinwitness": [
"30440220724686754b2c80564048cbafab84e07ab91f9e9a64c1baca8e726de70209e9cd02201f9 1ac61ce789e7032c2561dc24e26adca029d6449d82e96c252ace18d4dbba401",
"026f627029af8b372f3c81c5ae5cb4ce0971fb6d059e22351bc7191d9841a4156e"
],
"sequence": 4294967294
},
{
"txid": "9a47ab546d42a8f5690cad387dc623228f8af8f1fb8d67a999e30443096ac66c",
"vout": 0,
"scriptSig": {
"asm": "3044022062e7ba2ec9a4a26fba867624b7786f6e1cd11363186bcf73a5a163b2f32f1d1e0220433 2986870d8e8d54545313deabab49586d851f7c74c185026b731b0e172d20b[ALL] 03903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdf",
"hex": "473044022062e7ba2ec9a4a26fba867624b7786f6e1cd11363186bcf73a5a163b2f32f1d1e02204 332986870d8e8d54545313deabab49586d851f7c74c185026b731b0e172d20b012103903c1d380a 2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdf"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 0.01000706,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 8536bef594948115aa8ea99ce415767df30f8a3a OP_EQUAL",
"hex": "a9148536bef594948115aa8ea99ce415767df30f8a3a87",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2N5PbScRn7p7m2HEs1Bh8tshbN7TpgtRvxM"
]
}
},
{
"value": 0.02256800,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 0bb5f9fffd2c0f7bbb9dd4116341f3fba10d0418 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mgasj7m5vQWp4zixtHjiEgpGxex6ZCvhX8"
]
}
}
]
}
Создаем транзакциюИтак, давайте создадим RAW транзакцию в блокноте!
Сначала определимся, какой выход мы будем тратить? Давайте рассмотрим по отдельности оба выхода.
Выход 1. {
"value": 0.01000706,
"n": 0,
"scriptPubKey": {
"asm": "OP_HASH160 8536bef594948115aa8ea99ce415767df30f8a3a OP_EQUAL",
"hex": "a9148536bef594948115aa8ea99ce415767df30f8a3a87",
"reqSigs": 1,
"type": "scripthash",
"addresses": [
"2N5PbScRn7p7m2HEs1Bh8tshbN7TpgtRvxM"
]
}
},
В этом выходе запирающий скрипт имеет вид
OP_HASH160 8536bef594948115aa8ea99ce415767df30f8a3a OP_EQUAL
В переводе на русский это означает:
биткоины с этого выхода сможет потратить тот, кто напишет в транзакции отпирающий скрипт хэш которого равен 8536bef594948115aa8ea99ce415767df30f8a3a. Отпирающий скрипт в добавок должен вернуть значение OP_TRUE.
Такие запирающие скрипты являются стандартными и называются
P2SH (плачу за правильный хэша скрипта).
Выход 2. {
"value": 0.02256800,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 0bb5f9fffd2c0f7bbb9dd4116341f3fba10d0418 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mgasj7m5vQWp4zixtHjiEgpGxex6ZCvhX8"
]
}
тут запирающий скрипт другой
OP_DUP OP_HASH160 0bb5f9fffd2c0f7bbb9dd4116341f3fba10d0418 OP_EQUALVERIFY OP_CHECKSIG
В переводе на человеческий скрипт означает:
биткоины с этого выхода сможет потратить тот, кто предоставит публичный ключ хэш которого равен 0bb5f9fffd2c0f7bbb9dd4116341f3fba10d0418 и при этом у транзакции будет правильная цифровая подпись проверяемая данным публичным ключем.
Такие запирающие скрипты являются стандартными и называются
P2PKH (плачу за правильный хэш публичного ключа).
Для более простого объяснения давайте
потратим второй выход.
Первым делом, надо взять txid = 2e4308716eaaf6d27d2b91bfe2a78fc7819176966b619b6d8dc675f5373aa3d9
и перевернуть его с ног на голову! То есть
ИД входящей транзакции: d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e
На втором выходе транзакции имеется 0.022568 BTC, давайте потратим 0.02256 BTC (остальное оставим майнерам как комиссию)
Надо пересчитать сумму в сатоши, потом перевести в шестнадцатиричный вид, потом перевернуть с ног на голову 0.02256 BTC = 2256000 sat = 0x0000000000226C80 = 806С220000000000
Таким образом, на текущий момент, мы имеем следующие данные для транзакции:
Версия: 02000000
Флаг: не будет флага, шлем обычную транзакцию без SegWit
Число входов: 01
Вход 1ИД входящей транзакции: 2e4308716eaaf6d27d2b91bfe2a78fc7819176966b619b6d8dc675f5373aa3d9
Номер выхода у входящей транзакции: 01000000 (второй выход имеет номер 1 потому что нумерация начинается с нуля)
Размер тратящего скрипта: (пока нет, см. далее)
Тратящий скрипт: (пока нет, см. далее)
sequence: feffffff (это для простоты пусть будет такая постоянная величина)
Число выходов транзакции: 01
Выход 1Количество сатошей в выходе: 806С220000000000
Длина запирающего скрипта: (пока нет, см. далее)
Запирающий скрипт: (пока нет, см. далее)
Как видим, для транзакции не зватает скриптов.
Тратящий скриптТратящим скриптом для второго выхода служит просто публичный ключ от адреса mgasj7m5vQWp4zixtHjiEgpGxex6ZCvhX8
Получим публичный ключ командой консоли
getaddressinfo mgasj7m5vQWp4zixtHjiEgpGxex6ZCvhX8
{
"address": "mgasj7m5vQWp4zixtHjiEgpGxex6ZCvhX8",
"scriptPubKey": "76a9140bb5f9fffd2c0f7bbb9dd4116341f3fba10d041888ac",
"ismine": true,
"iswatchonly": false,
"isscript": false,
"iswitness": false,
"pubkey": "03903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdf",
"iscompressed": true,
"label": "wallet",
"timestamp": 1566751726,
"hdkeypath": "m/0'/0'/132'",
"hdseedid": "40a447c698b59ef21f858f0b7362d0fc96a7bfae",
"hdmasterkeyid": "40a447c698b59ef21f858f0b7362d0fc96a7bfae",
"labels": [
{
"name": "wallet",
"purpose": "receive"
}
]
}
Получаем для входа нашей новой транзакции:
Размер тратящего скрипта: 21 (это в шестнадцатиричном виде, а в десятичном 33 байта)
Тратящий скрипт: 03903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdfОсталось написать
запирающий скриптЯ хочу послать биткоины на адрес 2MvAAds6k4M5Z6EvfyGJXfGrTP12hhT2TMc.
Получить скрипт для этого адреса можно командой консоли
validateaddress 2MvAAds6k4M5Z6EvfyGJXfGrTP12hhT2TMc
{
"isvalid": true,
"address": "2MvAAds6k4M5Z6EvfyGJXfGrTP12hhT2TMc",
"scriptPubKey": "a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b0487",
"isscript": true,
"iswitness": false
}
Получаем для выхода нашей новой транзакции:
Длина запирающего скрипта: 17 (или 23 байта)
Запирающий скрипт: a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b0487Почти конечный итогВерсия: 02000000
Флаг: не будет флага, шлем обычную транзакцию без SegWit
Число входов: 01
Вход 1ИД входящей транзакции: d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e
Номер выхода у входящей транзакции: 01000000
Размер тратящего скрипта: 21
Тратящий скрипт: 03903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdf
sequence: feffffff
Число выходов транзакции: 01
Выход 1Количество сатошей в выходе: 806С220000000000
Длина запирающего скрипта: 17
Запирающий скрипт: a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b0487
Locktime:
00000000 (этот параметр можно делать любым, он игнорируется если sequence=feffffff или sequence=ffffffff )
Теперь открываем блокнот и пишем все в одну строчку
0200000001d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e010000002103903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff01806C22000000000017a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b048700000000
Наконец-то...Наша транзакция почти готова, теперь ее надо подписать. Делается это опять в консоли
signrawtransactionwithwallet 0200000001d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e010000002103903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff01806C22000000000017a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b048700000000
На выходе получим подписанную транзакцию!
{
"hex": "0200000001d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e01000 0006a47304402205fd610204bc40841382e299d0d326026ae3089eb4e570afb280967cfd271f1f4 0220701479b8fce69904d8d0d269b715c558954c30dddbaed369d4545fb257b1629c012103903c1 d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff01806c220000 00000017a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b048700000000",
"complete": true
}
УРА!Ну вот и все. Теперь можно отправить подписанную транзакцию в сеть командой консоли
sendrawtransaction 0200000001d9a33a37f575c68d6d9b616b96769181c78fa7e2bf912b7dd2f6aa6e7108432e010000006a47304402205fd610204bc40841382e299d0d326026ae3089eb4e570afb280967cfd271f1f40220701479b8fce69904d8d0d269b715c558954c30dddbaed369d4545fb257b1629c012103903c1d380a2b05c96e8ad40cbc8a1b647cadef7a1deff8df6b8528a337465cdffeffffff01806c22000000000017a9141ff37fd7b7cb61c95ca8e98ae3349661d4a95b048700000000
Ответом получим txid
eab054c14f9fd52d103fceb33945aa682283c9148c5be7834adf0a46c579538d