Перейти к содержимому

YoBit.Net





* * * * - 4 голосов

Применение raw-транзакций

Написано bronevik, 14 March 2013 · 5213 Просмотров

Использование raw-транзакций

Что это такое
Raw-транзакции (бувально -- «сырые») были введены в клиент биткойн в версии 0.7. Они предоставляют низкоуровневый интерфейс для создания, управления и рассылки транзакций.
Интерес к этой возможности появился у меня после того, как одна из транзакций, созданная «обычным порядком» заморозилась и никак не хотела включаться в блоки. Моя ошибка заключалась в том, что отправил я её с несинхронизированного клиента, который не запускал несколько дней. Блокчейн был трехдневной давности, и, что важнее, не было ни одного активного соединения с другими пирами. Созданная в таких условиях транзакция повисла без подтверждений вплоть до того, что более поздние включились в блоки, а она нет. С помощью обычной транзакции проблему было не решить: графический клиент уже считал эти монеты потраченными и не дал бы мне отправить их повторно. Но если сформировать raw-транзакцию, то сеть бы её приняла, так как монеты на самом деле не потрачены.
Однако для таких выкрутасов надо четко понимать, что именно ты делаешь. Уж точно не обойтись без понимания общей механики биткойн-транзакций. Её можно почерпнуть например из этой статьи: http://btcsec.com/transactions/

Что необходимо
Необходим доступ к командной строке клиента биткойн. Проще всего это сделать, зайдя в графическом клиенте в Help → Debug Window. Мной для опытов использовался клиент TerraCoin, просто потому, что именно в этой сети у меня возникла проблема. На практике разницы никакой, так как код terracoin был нещадно содран с биткойновского как раз нужной версии 0.7. Ну и естественно необходимо хотя бы небольшое количество монет.

Приступаем
Процесс создания raw-транзакции можно условно разделить на 3 этапа:
1. Создание транзакции. Описание её входов и выходов.
2. Подпись транзакции закрытым ключом.
3. Отправка созданной и подписанной транзакции в сеть.
Проследуем этими тремя этапами.

Создаем транзакцию.
Во-первых, надо понять, какие монеты в нашем распоряжении. Командуем




listunspent
и получаем список входящих транзакций в таком виде:






[
{
"txid" : "00f156f795bd513aa181ce55c177ccbc998c0ed40fea59939e9452e98df31f7c",
"vout" : 2,
"scriptPubKey" : "76a914a91eacfdd736d45877f646e22df1ed06deb60daf88ac",
"amount" : 5.10524239,
"confirmations" : 11587
},
{
"txid" : "13a554da1d0651167cc7eb4303e7680918d2b6088f8e7746bf55a81d8258ebda",
"vout" : 8,
"scriptPubKey" : "76a914a91eacfdd736d45877f646e22df1ed06deb60daf88ac",
"amount" : 7.61491087,
"confirmations" : 13017
},
Команда выдает информацию по каждой доступной входящей транзакции. Если их было много, то и список получится довольно длинным. Нам отсюда нужны 1,2 и 4 строчка — это соответственно хэш транзакции, номер её входа и количество монет.
Создадим следующую транзакцию: возьмем первую из входящих на сумму 5.10524239 монет, отправим 5 на адрес 1BJ2xTtQ7aRQdmShLo5CvuiNEsYs6VRa2q, остальное оставим на комиссию.
Создаем транзакцию (именно так, со всеми кавычками и скобками):




createrawtransaction '[{"txid":"00f156f795bd513aa181ce55c177ccbc998c0ed40fea59939e9452e98df31f7c","vout":2}]' '{"1BJ2xTtQ7aRQdmShLo5CvuiNEsYs6VRa2q":5}'
в ответ получаем хэш raw-транзакции:




01000000017c1ff38de952949e9359ea0fd40e8c99bccc77c155ce81a13a51bd95f756f1000200000000ffffffff010065cd1d000000001976a91470e9f652a6647769760f42391aa43b6063af39cf88ac00000000

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




decoderawtransaction 01000000017c1ff38de952949e9359ea0fd40e8c99bccc77c155ce81a13a51bd95f756f1000200000000ffffffff010065cd1d000000001976a91470e9f652a6647769760f42391aa43b6063af39cf88ac00000000
ответ:




{
"txid" : "16ddda0708fb8fb7d83a6658a79c8e958705db85aa36e1eed6e301dc7e566770",
"version" : 1,
"locktime" : 0,
"vin" : [
{
"txid" : "00f156f795bd513aa181ce55c177ccbc998c0ed40fea59939e9452e98df31f7c",
"vout" : 2,
"scriptSig" : {
"asm" : "",
"hex" : ""
},
"sequence" : 4294967295
}
],
"vout" : [
{
"value" : 5.00000000,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 70e9f652a6647769760f42391aa43b6063af39cf OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a91470e9f652a6647769760f42391aa43b6063af39cf88ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1BJ2xTtQ7aRQdmShLo5CvuiNEsYs6VRa2q"
]
}
}
]
}
Вроде бы можно отправлять.
Подписываем транзакцию закрытым ключом:




signrawtransaction 01000000017c1ff38de952949e9359ea0fd40e8c99bccc77c155ce81a13a51bd95f756f1000200000000ffffffff010065cd1d000000001976a91470e9f652a6647769760f42391aa43b6063af39cf88ac00000000

ответ:




{
"hex" : "01000000017c1ff38de952949e9359ea0fd40e8c99bccc77c155ce81a13a51bd95f756f100020000006a473044022011d0bb6772b4dc9a0ec47d1ab6d1b3cf48f24bffa3a93d6c45ae90fe1d9ad6f702206ab85665f740aa1708cd703880f2f654ae8b6f7e5da2dc4b10404a205aa2dbb80121035c174fa967e5a647efa4622da9aa547b20f5f4d938042a471ce690f165a6de08ffffffff010065cd1d000000001976a91470e9f652a6647769760f42391aa43b6063af39cf88ac00000000",
"complete" : true
}

Параметр complete отображает удачно или нет мы её подписали.
Теперь осталось просто отправить готовую транзакцию в сеть:




sendrawtransaction 01000000017c1ff38de952949e9359ea0fd40e8c99bccc77c155ce81a13a51bd95f756f100020000006a473044022011d0bb6772b4dc9a0ec47d1ab6d1b3cf48f24bffa3a93d6c45ae90fe1d9ad6f702206ab85665f740aa1708cd703880f2f654ae8b6f7e5da2dc4b10404a205aa2dbb80121035c174fa967e5a647efa4622da9aa547b20f5f4d938042a471ce690f165a6de08ffffffff010065cd1d000000001976a91470e9f652a6647769760f42391aa43b6063af39cf88ac00000000
На выходе этой команды получаем txid готовой транзакции:




2b2cab81094c9cd09ac84297baf23c43946a8f2d72147a5c1d3047027b6dd811

Прошедшую и принятую сетью транзакцию можно наблюдать в блокэксплорере:
<http://www.cryptocoi...d3047027b6dd811>

Нюансы
Понятно, что вряд ли придется создавать такие простые транзакции, как у меня. Как правило они содержат много входов и как минимум 2 выхода. Их перечисляем через запятую в команде createrawtransaction:




createrawtransaction '[{"txid":"txid1","vout":vout1},{“txid”:”txid2”, “vout”:vout2}, ...]' '{"adress1":5,"adress2":10, …}'


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

Пара интересных применений.
Как правило, чем более низкого уровня интерфейс, тем большей подготовки он требует, но тем больше возможностей он предоставляет. К примеру, атака double-spend была осуществлена как раз при помощи создания raw-транзакции. У нас к этому, разумеется, чисто научный интерес. :)
Второе применение относится к сфере защиты кошелька. При помощи raw-транзакции, зная закрытый ключ, можно отправлять монеты с кошелька, находящегося в оффлайне.
Для этого потребуется узнать приватный ключ, соответствующий адресу, на котором лежат монеты:




dumpprivkey adress

а зная его, подписать транзакцию им:




signrawtransaction hex [] priv ALL


где hex-выход команды createrawtransaction, а priv – команды dumpprivkey.
И вуаля, мы шлем монеты с кошелька, у которого даже нет доступа в сеть.

  • 8



Это ж форменное безобразие!

    • 0

Это ж форменное безобразие!

В каком  смысле?

    • 0