Bitcoin Forum
June 24, 2024, 10:23:19 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Эксперименты со скриптами биткоина где?  (Read 321 times)
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 04, 2018, 01:40:40 AM
 #1

Привет. Где-то давно попадался сайт, где можно было потренироваться в написании биткоин скриптов. Вводишь команды, смотришь стек и что возвращается в результате. Сейчас что-то сходу не могу рабочую версию нагуглить. Никто не в курсе случайно где?

OpenTrade - Open Source Cryptocurrency Exchange
A-Bolt
Legendary
*
Offline Offline

Activity: 2318
Merit: 2333


View Profile
October 04, 2018, 09:37:17 AM
 #2

http://www.crmarsh.com/script-playground/
https://siminchen.github.io/bitcoinIDE/build/editor.html
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 04, 2018, 10:14:15 AM
 #3


Спасибо.
По первой ссылке ничего правда не понятно, но вторая - вещь!

OpenTrade - Open Source Cryptocurrency Exchange
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 08, 2018, 11:20:16 AM
 #4

Прошу консультации: кто может объяснить работу со скриптами биткоина?

Вот мое понимание.

Обычно желающий потратить биткоины, в своей тратящей транзакции в vin.scriptSig пишет некий скрипт, а в vin.txid пишет транзакцию куда этот скрипт подставить.

Правило такое: если vin.scriptSig тратящей транзакции (currentTX) поставить перед (prevTX) vout.scriptPubKey из той транзакции которую тратят, то получившийся скрипт (currentTX.vin.scriptSig prevTX.vout.scriptPubKey) должен после выполнения, в стеке давать не ноль. Если в стеке не ноль, то транзакция prevTX считается израсходованной...

Вроде с этим все понятно.
Однако с некоторых пор, в сети биткоина появился новый тип транзакций, связанный с SegWit. В SegWit транзакциях помимо vin.scriptSig присутствует поле vin.txinwitness

Насколько я понял, в этом новом поле тоже пишется скрипт, и он тоже подставляется вперед prevTX.vout.scriptPubKey и тоже должен получиться не ноль. Но вот есть загвоздка в моем понимании:
1. vin.txinwitness это массив.
2. Каждый элемент массива что-то не очень похож на скрипт. Вот пример http://chainquery.com/bitcoin-api/getrawtransaction/e6511db40a71ca407965e011ad76a7711acc5cfccf51586aa71a78dc535e6a4b/1

3. Если это поле все-таки скрипты, тогда еще вопрос: если в одной транзакции есть и непустое vin.scriptSig и vin.txinwitness, то кто подставляется первым?

OpenTrade - Open Source Cryptocurrency Exchange
amaclin1
Sr. Member
****
Offline Offline

Activity: 784
Merit: 305


View Profile
October 08, 2018, 03:55:55 PM
 #5

Давай с самого начала начнем.

Можно начать с самой первой транзакции
https://www.blockchain.com/btc/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b

Скрипт выхода (scriptPub) этой транзакции из двух операндов состоит
PUSH ( 04678afdb0fe5... ) CHECKSIG

Чтобы потратить эту транзакцию надо придумать такой входной скрипт (scriptSig)
чтобы последовательное выполнение scriptSig + scriptPub над одним и тем же стеком
давало бы в конце ненулевое значение на вершине стека. Обращаю внимание: сперва выполняется
scriptSig, а потом scriptPub!

Тут надо понимать как работает операция CHECKSIG - она что-то крутит-вертит с транзакцией
(той в которой мы будем тратить) и еще берет scriptPub из первой транзакции - получает некоторый
дайджест. Потом надо сигнатуру, публичный ключ и дайджест скормить функции проверки правильности
подписи и в стек записать нолик или единичку в зависимости от того прошло или не прокатило.

Значит самый простой вариант scriptSig - это просто PUSH ( тутправильнаяподпись )

Можно изъебнуться. Например NOP NOP NOP PUSH ( чтонибудь ) DROP PUSH ( тутправильнаяподпись )
тоже будет приводить к тому же результату. Это достаточно давно заметили и решили
что клиент должен делать дополнительные проверки, например в scriptSig нельзя(?)
использовать ничего кроме PUSH-операций.

Потом Сатоши Накамото почесал репу, и решил - надо по-другому делать.
Он таки башковитый был, решил что предложенный вариант несколько кривоват.
Вернее даже не кривоват, наоборот, он слишком прямой. Надо бы изъебнуться так,
что владелец средств не показывает никому свой публичный ключ до того, как он
тратит бабки.

И стали все использовать другой вариант scriptPub который называется p2pkh

Об этом в следующей главе. Мне лениво много печатать, а если я не начну с самого начала,
то вы мысль не уловите - нахера было от p2pk переходить к p2pkh, потом к p2sh, а потом к сегвитам


Bitcoin SV GUI client for Windows and Linux
https://github.com/AlisterMaclin/bitcoin-sv/releases
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 08, 2018, 07:55:12 PM
Last edit: October 08, 2018, 09:21:31 PM by kzv
 #6

Ну можно было короче:

В первых версиях биткоина было так (pay-to-pubkey transaction):

кто хочет потратить, в своей транзакции на входе писал
vin.scriptSig = PUSH правильная_подпись
vin.txid = ид транзакции которую надо потратить.

На выходе транзакции которую собираются тратить стояло
vout.scriptPubKey = PUSH публичный_ключ CHECKSIG

Итого полный скрипт получался
Code:
PUSH правильная_подпись PUSH публичный_ключ CHECKSIG

Соответственно если подпись для публичного ключа действительно правильная, то предыдущая транзакция считалась потраченной.

В следующих версиях скрипты слегка усложнили.
(pay-to-pubkey-hash)

кто хочет потратить, в своей транзакции на входе пишет
vin.scriptSig = PUSH правильная_подпись PUSH публичный_ключ
vin.txid = ид транзакции которую надо потратить.

На выходе транзакции которую собираются тратить стоит
vout.scriptPubKey = DUPLICATE HASH160 хэш_публичного_ключа EQUALVERIFY CHECKSIG

Итого полный скрипт получается
Code:
PUSH правильная_подпись PUSH публичный_ключ DUPLICATE HASH160 хэш_публичного_ключа EQUALVERIFY CHECKSIG

Потом появилась еще одна разновидность
Pay-To-Script Hash

кто хочет потратить, в своей транзакции на входе пишет
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ
vin.txid = ид транзакции которую надо потратить.

На выходе транзакции которую собираются тратить стоит
vout.scriptPubKey = OP_HASH160 хэш_скрипта OP_EQUAL

Итого полный скрипт получается.
Code:
PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ OP_HASH160 хэш(vin.scriptSig) OP_EQUAL


В этом месте у меня уже нет полного понимания, как оно на самом деле работает. Походу дела как-то так:
1. Сначала исполняется скрипт vin.scriptSig
2. Потом берется хэш от vin.scriptSig (или берется хэш только от скрипта, а подписи не хэшируются ?)
3. Полученный хэш засовывается в стек и дальше начинает исполняться OP_HASH160 хэш_скрипта OP_EQUAL
4. Если на выходе стека получится не ноль, значит предыдущая транзакция считается потраченной.

Наконец самое последнее веяние:
SegWit транзакции.
Тут я как раз хотел у знатоков поинтересоваться - как они работают.

OpenTrade - Open Source Cryptocurrency Exchange
A-Bolt
Legendary
*
Offline Offline

Activity: 2318
Merit: 2333


View Profile
October 08, 2018, 09:12:38 PM
 #7

Pay-To-Script Hash

кто хочет потратить, в своей транзакции на входе пишет
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ
vin.txid = ид транзакции которую надо потратить.

На выходе транзакции которую собираются тратить стоит
vout.scriptPubKey = OP_HASH160 хэш_скрипта OP_EQUAL

В этом месте у меня уже нет полного понимания, как оно на самом деле работает.

А работает оно в два этапа.
Сначала выполняется вот этот скрипт: <ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ> OP_HASH160 <хэш_скрипта> OP_EQUAL
Тем самым, проверяется соответствие скрипта и его хеша, подтверждая право владельца скрипта на его выполнение.

А потом выполняется сам скрипт, тратящий выход: <sig1> <sig2> ... <ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ>.
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 08, 2018, 09:19:50 PM
 #8

Pay-To-Script Hash

кто хочет потратить, в своей транзакции на входе пишет
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ
vin.txid = ид транзакции которую надо потратить.

На выходе транзакции которую собираются тратить стоит
vout.scriptPubKey = OP_HASH160 хэш_скрипта OP_EQUAL

В этом месте у меня уже нет полного понимания, как оно на самом деле работает.

А работает оно в два этапа.
Сначала выполняется вот этот скрипт: <ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ> OP_HASH160 <хэш_скрипта> OP_EQUAL
Тем самым, проверяется соответствие скрипта и его хеша, подтверждая право владельца скрипта на его выполнение.

А потом выполняется сам скрипт, тратящий выход: <sig1> <sig2> ... <ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ>.

Но вот это все целиком тоже валидный скрипт:
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Как узнать: где кончаются подписи и начинается скрипт?

OpenTrade - Open Source Cryptocurrency Exchange
A-Bolt
Legendary
*
Offline Offline

Activity: 2318
Merit: 2333


View Profile
October 08, 2018, 10:13:47 PM
 #9

Но вот это все целиком тоже валидный скрипт:
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Как узнать: где кончаются подписи и начинается скрипт?

Вы неправильно написали:
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Правильно так:
vin.scriptSig = PUSH правильная_подпись1 PUSH правильная_подпись2 ... PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Понятно, в чём разница? PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ - это уже не скрипт, а данные (сериализованный скрипт), над которыми должен выполнить действия другой скрипт - scriptPubKey.

Как-то так:
PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ OP_HASH160 PUSH хэш_скрипта OP_EQUAL

Сериализованный скрипт стоит последним в scriptSig, тем он и выделяется среди впереди стоящих подписей.

В случае успешного выполнения PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ OP_HASH160 PUSH хэш_скрипта OP_EQUAL
дальше уже выполняется PUSH sig1 PUSH sig2 ... ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Обратите внимание: ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ стоит уже без PUSH. Это уже не данные, а скрипт - последовательность опкодов к исполнению.




kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 08, 2018, 10:25:21 PM
 #10

Но вот это все целиком тоже валидный скрипт:
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Как узнать: где кончаются подписи и начинается скрипт?

Вы неправильно написали:
vin.scriptSig = PUSH правильная_подпись1 [PUSH правильная_подпись2] [правильная_подпись3] [...] ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Правильно так:
vin.scriptSig = PUSH правильная_подпись1 PUSH правильная_подпись2 ... PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Понятно, в чём разница? PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ - это уже не скрипт, а данные (сериализованный скрипт), над которыми должен выполнить действия другой скрипт - scriptPubKey.

Как-то так:
PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ OP_HASH160 PUSH хэш_скрипта OP_EQUAL

Сериализованный скрипт стоит последним в scriptSig, тем он и выделяется среди впереди стоящих подписей.

В случае успешного выполнения PUSH ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ OP_HASH160 PUSH хэш_скрипта OP_EQUAL
дальше уже выполняется PUSH sig1 PUSH sig2 ... ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ

Обратите внимание: ЛЮБОЙ_ВАЛИДНЫЙ_СКРИПТ стоит уже без PUSH. Это уже не данные, а скрипт - последовательность опкодов к исполнению.


Спасибо огромное, я четвертый час это вот все нагуглить никак не могу. Теперь спать спокойно могу пойти  Smiley

OpenTrade - Open Source Cryptocurrency Exchange
amaclin1
Sr. Member
****
Offline Offline

Activity: 784
Merit: 305


View Profile
October 09, 2018, 04:04:05 AM
 #11

Ну молодцы, сами разобрались?
Отлично, мне работы меньше.
Я просто думал, что не только вам объяснить, но и другим полезно было бы понять,
почему ушли от p2pk к p2pkh, потом к p2sh (это было радикальное изменение,
уже без Сатоши, пришлось софт-форком улучшать то, до чего Сатоши не допер)

И поняв это, достаточно легко уже понять сегвит - тоже софт-форк, который исправляет
другие неучтенные проблемы.

Bitcoin SV GUI client for Windows and Linux
https://github.com/AlisterMaclin/bitcoin-sv/releases
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 11, 2018, 12:40:57 PM
 #12

Что-то не проканывает.

Задумал вот такой скрипт написать
Code:
OP_IF 83e815 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_RIPEMD160 5df9e3c695bb86153326a6ff4cfce8e95b3f55bf OP_EQUALVERIFY OP_ENDIF

Написал, получил адрес, послал туда тестовых битков.
адрес: 2N77oVk5k8MWE33hWS5QeS5bM2zVkgHcido
транзакция: 3a59dcef30879ebda1ffdaff4c1c46f06691d231b974acdc6f90907a973c658f

Пробую потратить такой транзакцией

Code:
02000000018f653c977a90906fdcac74b931d29166f0461c4cffdaffa1bd9e8730efdc593a000000006614c47907abd2a80492ca9388b05c0e382518ff3960514c4e630383e815b175a614388756dc41f4eeadcb3fc5064535d1121a49d3f48867a614388756dc41f4eeadcb3fc5064535d1121a49d3f488a6145df9e3c695bb86153326a6ff4cfce8e95b3f55bf8868feffffff01905f0100000000001976a91414466ff4b5a6d6e8a7e45152b47f0c5d8f9f0e4088ac83e81500

ОБЛОМ ((

Декодирую, вижу
Quote
"scriptSig": {
   "asm": "c47907abd2a80492ca9388b05c0e382518ff3960 1 630383e815b175a614388756dc41f4eeadcb3fc5064535d1121a49d3f48867a614388756dc41f4e eadcb3fc5064535d1121a49d3f488a6145df9e3c695bb86153326a6ff4cfce8e95b3f55bf8868",
   "hex": "14c47907abd2a80492ca9388b05c0e382518ff3960514c4e630383e815b175a614388756dc41f4e eadcb3fc5064535d1121a49d3f48867a614388756dc41f4eeadcb3fc5064535d1121a49d3f488a6 145df9e3c695bb86153326a6ff4cfce8e95b3f55bf8868"
},

В asm то, что я хочу видеть, в hex вижу пару лишних байтов

Code:
c47907abd2a80492ca9388b05c0e382518ff3960 OP_1 OP_PUSHDATA1 OP_PUSHDATA4 OP_IF 83e815 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_RIPEMD160 5df9e3c695bb86153326a6ff4cfce8e95b3f55bf OP_EQUALVERIFY OP_ENDIF

Лишние тут OP_PUSHDATA1 OP_PUSHDATA4
Понятно откуда они взялись: это пушится мой скрипт.
Непонятно - какого хрена они учитываются как данные, когда скрипт исполняетсяHuh

Получается в моем начальном скрипте надо делать как-то так:

Code:
OP_DROP OP_DROP OP_IF 83e815 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_RIPEMD160 5df9e3c695bb86153326a6ff4cfce8e95b3f55bf OP_EQUALVERIFY OP_ENDIF

?

OpenTrade - Open Source Cryptocurrency Exchange
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 11, 2018, 07:44:11 PM
 #13

Черт с ним со сложным скриптом. Решил с простыми поэкспериментировать. Тоже не работает нифига.

Делаю скрипт
OP_IF OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE 2 OP_EQUALVERIFY OP_ENDIF

Вот его адрес
2MwGFm13NMXNcv3yTKHWTJ3wFBfxDWhVbpS

Послал туда сатошей.

Теперь хочу забрать сатоши. Пишу транзакцию
 
Code:
02000000012d0cf45773e4730cfde672d85447c8c6761621ff708850eb2b0505247255ac5d00000000345114c47907abd2a80492ca9388b05c0e382518ff3960511c63a614388756dc41f4eeadcb3fc5064535d1121a49d3f48867528868feffffff01905f0100000000001976a914d5d4a489e479dc7ab7d64b8dbe2917575cffc79788aca2e81500

Там в транзакции получается скрипт
Code:
1 c47907abd2a80492ca9388b05c0e382518ff3960 1 OP_IF OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE 2 OP_EQUALVERIFY OP_ENDIF

И что имеем?
Тут скрипт работает без ошибок https://siminchen.github.io/bitcoinIDE/build/editor.html
А когда засылаю в сеть, пишет
Quote
16: mandatory-script-verify-flag-failed (Script failed an OP_EQUALVERIFY operation)

Спрашивается: чего я опять делаю не так?

OpenTrade - Open Source Cryptocurrency Exchange
Avraham Terra
Newbie
*
Offline Offline

Activity: 6
Merit: 0


View Profile
October 17, 2018, 12:56:42 AM
Last edit: October 17, 2018, 01:08:56 AM by Avraham Terra
 #14

Там в транзакции получается скрипт
Code:
1 c47907abd2a80492ca9388b05c0e382518ff3960 1 OP_IF OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE 2 OP_EQUALVERIFY OP_ENDIF

В результате работы этого скрипта остается 0x1

Делаю скрипт
OP_IF OP_RIPEMD160 388756dc41f4eeadcb3fc5064535d1121a49d3f4 OP_EQUALVERIFY OP_ELSE 2 OP_EQUALVERIFY OP_ENDIF

OP_IF убирает 0x1 из стека и делает OP_RIPEMD160 от пустой строки, в итоге получается 0xE63C7DC57882262676E009478111E6AE5C6C5198 и затем OP_EQUALVERIFY сравнивает его с 0x388756DC41F4EEADCB3FC5064535D1121A49D3F4

В симуляторе OP_RIPEMD160 от пустой строки срабатывает, а в реальном биткоине видимо нет.
kzv (OP)
Legendary
*
Offline Offline

Activity: 1722
Merit: 1285

OpenTrade - Open Source Cryptocurrency Exchange


View Profile WWW
October 17, 2018, 06:28:20 PM
 #15

Уже разобрался.
Симуляторы косячно ищут хэши.

OpenTrade - Open Source Cryptocurrency Exchange
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!