Как устроена платформа
Смарт-аккаунт¶
Каждая транзакция на блокчейн-платформе Waves Enterprise создана от имени какого-либо аккаунта. Благодаря использованию открытого и закрытого ключа можно удостовериться, что выпущенная с аккаунта транзакция в действительности была отправлена с этого аккаунта.
Но пары ключей может оказаться недостаточно для обеспечения безопасности транзакций. Например, утечка мнемонической фразы от аккаунта позволит злоумышленнику отправлять в блокчейн транзакции от имени аккаунта.
Чтобы повысить безопасность транзакций на блокчейн-платформе Waves Enterprise реализована технология смарт-аккаунта (Smart Account). Смарт-аккаунт – это аккаунт, на котором установлен скрипт, который проверяет все отправляемые аккаунтом транзакции на соответствие указанным в скрипте условиям. Этот скрипт позволяет проводить валидации исходящих транзакций, например, на множественную подпись (multisig). Ниже приведены некоторые примеры параметров, которые скрипт может использовать для проверки транзакций:
Тип транзакции — можно разрешить отправку транзакций только заданного в скрипте типа;
Подтверждение или подпись транзакции — можно установить правило, согласно которому массив подтверждений
proofs
в теле транзакции должен содержать определенную подпись транзакции, несколько определенных подписей или другие данные;Текущая высота блокчейна — владелец аккаунта может установить правило, согласно которому транзакции могут отправляться с его адреса только в том случае, если высота блокчейна превышает указанное в скрипте число N;
Произвольные данные, существующие в блокчейне — например, данные оракулов.
Также с помощью скрипта можно отменить все проверки, установив правило, согласно которому все транзакции, отправляемые с адреса, должны считаться валидными.
Со смарт-аккаунта могут быть отправлены только те транзакции, которые прошли валидацию скриптом.
Создание скрипта аккаунта¶
Владелец аккаунта создаёт скрипт аккаунта на языке RIDE.
Структура скрипта аккаунта¶
Скрипт аккаунта состоит из директивы и выражения.
Директива¶
В начале скрипта размещается директива. Например:
{-# STDLIB_VERSION 2 #-} {-# CONTENT_TYPE EXPRESSION #-} {-# SCRIPT_TYPE ACCOUNT #-}
Приведенная выше директива состоит из трёх аннотаций и сообщает компилятору следующую информацию:
в скрипте используется версия 2 библиотеки стандартных функций,
типом содержимого данного скрипта является
Expression
,создаваемый скрипт будет скриптом аккаунта.
Выражение¶
Выражение проверяет отправляемые аккаунтом транзакции на соответствие заданным условиям. Если условия не соблюдаются, транзакция не будет отправлена. Возможны следующие результаты выполнения выражения:
true
– транзакция разрешена,
false
– транзакция запрещена,ошибка.
Установка скрипта на аккаунт¶
Установить скрипт на аккаунт можно только с помощью транзакции 13. SetScript Transaction. При этом у аккаунта, отправляющего эту транзакцию, должна быть только роль contract_developer
, либо не должно быть ролей вообще.
К аккаунту можно прикрепить только один скрипт.
Открепить скрипт от смарт-аккаунта или заместить старый скрипт новым можно, только если старый скрипт не запрещает это. Для открепления или замены скрипта требуется отправить новую транзакцию установки скрипта SetScript Transaction.
Пример создания и применения скрипта аккаунта¶
В этом разделе приведен пример создания и развертывания скрипта вручную без использования клиентских библиотек и библиотек API.
В этом примере будет создан и развернут простой скрипт аккаунта, который проверяет наличие множественной подписи (две из двух) транзакции.
Предварительные условия¶
При создании этого скрипта аккаунта должны быть выполнены следующие условия:
У вас есть нода в блокчейн сети Waves Enterprise.
У вас есть три сгенерированных адреса в блокчейн сети Waves Enterprise:
3MxjWXEUcVCeiaEUqNcorB5HxSpLsgJCGxE – аккаунт alice,
3MqGVvfgqdqqU6P9mTAsLSxyRoRjrHF18Mf – аккаунт bob,
3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X – общий аккаунт.
Создание скрипта¶
В этом примере создается следующий скрипт:
В первых двух строках скрипта определяются 2 открытых ключа, закодированных в base58, для адресов alice и bob.
После этого пользователи собирают 2 открытых ключа в полях
proofs[0]
иproofs[1]
.Баланс аккаунта пополняется членами команды, после чего, когда 2 из 2 членов команды решают потратить деньги, они предоставляют свои подписи в одной транзакции.
Скрипт смарт-аккаунта, используя функцию sigVerify, проверяет эти подписи в
proofs
, и если две из двух подписей действительны, то и транзакция считается действительной; в противном случае транзакция не проходит в блокчейн.
В скрипте нет директивы, поэтому будут выбраны автоматические значения.
let alicePubKey = base58'Ey6Z9XkWsvG8JZwyxhkTjydRcGp1wg6rbC3AYcxq7Efr'
let bobPubKey = base58'5PvhyouzHn2Pcev56oBvwpnsGK5fEu1dA8fM2nJQM4HR'
let aliceSigned = if(sigVerify(tx.bodyBytes, tx.proofs[0], alicePubKey)) then 1 else 0
let bobSigned = if(sigVerify(tx.bodyBytes, tx.proofs[1], bobPubKey )) then 1 else 0
aliceSigned + bobSigned == 2
Конвертация скрипта в формат Base64¶
Используйте метод /utils/script/compile для компиляции скрипта и конвертации скрипта в формат Base64.
Для этого вы можете использовать Swagger:
Или вы можете использовать curl, чтобы скомпилировать скрипт и конвертировать его в формат Base64:
curl -X POST "http://localhost:6862/utils/script/compile" -H "accept: application/json" -H "Content-Type: application/json" -d "let alicePubKey = base58'Ey6Z9XkWsvG8JZwyxhkTjydRcGp1wg6rbC3AYcxq7Efr'let bobPubKey = base58'5PvhyouzHn2Pcev56oBvwpnsGK5fEu1dA8fM2nJQM4HR'let aliceSigned = if(sigVerify(tx.bodyBytes, tx.proofs[0], alicePubKey)) then 1 else 0let bobSigned = if(sigVerify(tx.bodyBytes, tx.proofs[1], bobPubKey )) then 1 else 0aliceSigned + bobSigned == 2"
Прикрепление скрипта к аккаунту¶
Чтобы прикрепить сконвертированный в формат Base64 скрипт к аккаунту, выполните следующие шаги:
Подготовьте JSON транзакции 13. SetScript Transaction для подписания. В качестве отправителя укажите общий аккаунт; в поле
script
задайте скрипт аккаунта:{ "type": 13, "version": 1, "sender": "3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X", "fee": 100000, "script": "<script>" }
Подпишите транзакцию с помощью метода /transactions/sign:
$ curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' \ --header 'X-API-Key: <it is a secret>' \ -d '{ "type": 13, "version": 1, "sender": "3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X", "fee": 100000, \ "script": "<script>" }' 'https://example.org/transactions/sign'
Метод вернёт JSON, готовый к публикации:
{ "type": 13, "id": "8w7yauNiENsJP8oDUpVEfiAzyEzMKoXbJEqS26Ht99mg", "sender": "3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X", "senderPublicKey": "66xdGznqt2AVLMZRHme9vFPC6cvN4yV95wRWPfTus3Qe", "fee": 100000, "timestamp": 1525797758819, "proofs": [ "4Ro4e4UrsVkaFbHtu96qZwHAdf8N4TtpjSGik9kRusmmYKCxicdsEqcgQrYden36nurqhY9EBkTKwD499kAi5rxe" ], "version": 1, "script": "<script>" }
Опубликуйте полученный JSON в блокчейн с помощью метода POST /transactions/broadcast:
$ curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' \ --header 'X-API-Key: <it is a secret>' \ -d '{ "type": 13, "id": "8w7yauNiENsJP8oDUpVEfiAzyEzMKoXbJEqS26Ht99mg", "sender": "3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X", \ "senderPublicKey": "66xdGznqt2AVLMZRHme9vFPC6cvN4yV95wRWPfTus3Qe", "fee": 100000, "timestamp": 1525797758819, \ "proofs": [ "4Ro4e4UrsVkaFbHtu96qZwHAdf8N4TtpjSGik9kRusmmYKCxicdsEqcgQrYden36nurqhY9EBkTKwD499kAi5rxe" ], \ "version": 1, "script": "<script>" }' \ 'https://example.org/transactions/broadcast'
Проверьте, применился ли скрипт:
$ curl http://example.org/addresses/scriptInfo/3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X { "address" : "3N7H4jTBMKtZfNCY86K2ND1rWcvFsGjDT3X", "script" : "<script>", "scriptText" : "<scriptText>", "complexity" : 27, "extraFee" : 400000 }
где
<scriptText>
– строковое представление скомпилированного<script>
(дерева выражений).
Теперь при отправке переводов с общего аккаунта с помощью транзакции 4. Transfer Transaction на другой аккаунт, скрипт будет проверять наличие обеих подписей (аккаунта alice и аккаунта bob) в поле proofs
.
Если подписи хотя бы одного из аккаунтов не будет, скрипт вернёт ошибку «State check failed. Reason: TransactionNotAllowedByScript» и транзакция перевода не будет опубликована в сети.