Перейти к основному содержимому
Блокчейн65ГЛАВА 65Транзакции Waves: тип, комиссия, подпись3Issue4Transfer12Data16Invokeцена по типу, не аукцион

Транзакции Waves: тип, комиссия, подпись

Прочитано0%
Квизы0/4
Тренажёрыне пройден0/1
Уровень 1 · Новичок

Зачем это нужно​

В Ethereum транзакция одна: «отправить данные по адресу». Всё остальное — перевод, выпуск токена, вызов контракта — это уже толкование этих данных кодом контракта.

В Waves сделано наоборот. Каждому действию соответствует свой тип транзакции со своим набором полей и своей ценой. Перевод — тип 4, запись данных — 12, вызов dApp — 16. Это заметно проще для чтения и заметно жёстче: нельзя придумать своё действие, можно только собрать его из имеющихся.

Эта глава — про то, как устроен этот набор, откуда берётся комиссия и как транзакция проходит путь от объекта в памяти до блока. Все ответы узла ниже сняты на локальном узле Waves 1.6.4.

Типы и цены​

У КАЖДОГО ДЕЙСТВИЯ СВОЙ НОМЕР ТИПА3Issueвыпустить токен1 WAVES4Transferперевести0,00112Dataзаписать в состояние0,00116InvokeScriptвызвать dApp0,005тип задаёт и смысл, и цену: выпуск токена стоит в тысячу раз дороже переводакомиссия фиксированная — не аукцион, как в Ethereum, а число из таблицывсего типов около двадцати; в работе постоянно нужны эти четыретип виден прямо в объекте транзакции, полем type — и в ответе узла тоже
Четыре типа, которые нужны постоянно; цена фиксирована и зависит от типа

Типов около двадцати. В повседневной работе нужны четыре:

НомерНазваниеЧто делаетКомиссия
3Issueвыпустить токен1 WAVES
4Transferперевести0,001 WAVES
12Dataзаписать в состояние аккаунта0,001 WAVES
16InvokeScriptвызвать функцию dApp0,005 WAVES
Важно

Комиссия в Waves фиксированная, а не аукцион. В Ethereum вы назначаете цену газа и соревнуетесь за место в блоке; здесь цена типа записана в правилах сети, и заплатить больше нет смысла. Это важно для расчётов: стоимость работы приложения считается заранее и точно.

Четыре шага транзакции​

ОТ ОБЪЕКТА ДО БЛОКА — ЧЕТЫРЕ ШАГА1собратьtransfer({ amount, recipient })обычный объект в памяти2подписатьвторым аргументом — сидпоявляются id и proofs3отправитьPOST /transactions/broadcastузел проверяет и отвечает 2004дождатьсяGET /transactions/info/<id>пока не 200 — в блок не попалаответ 200 на отправку значит «принято в очередь», а не «записано»: ждать надо шаг 4
Собрать, подписать, отправить, дождаться — и только четвёртый шаг говорит правду
const { transfer } = require('@waves/waves-transactions');

const tx = transfer({
amount: 500000000,
recipient: '3MDKRTnd5H6zoscVfvSBiazwQaNmwDouJDx',
chainId: 'R',
}, seed);

console.log('тип:', tx.type, '| комиссия:', tx.fee, '| id:', tx.id);
console.log('подписей:', tx.proofs.length);
тип: 4 | комиссия: 100000 | id: 4v5T8XJxrEMGRKBCsjs8htjWnm31UMfZsjkPWVn39AMm
подписей (proofs): 1
Нажми на часть выражения

Отправляем:

const r = await fetch(NODE + '/transactions/broadcast', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(tx),
});
ответ узла: 200

И ждём попадания в блок:

const info = await fetch(NODE + '/transactions/info/' + tx.id);
в блоке: 18 | применена: succeeded
Совет

200 на отправку значит «принято в очередь и предварительно проверено», а не «записано». Пока /transactions/info/<id> отвечает 404, транзакции в цепочке нет. Ожидание — это цикл с паузой, и писать его приходится почти всегда.

Проверяем, что деньги дошли​

баланс до перевода: {"address":"3MDKRTnd5H6z…","balance":0}
баланс после перевода: {"address":"3MDKRTnd5H6z…","balance":500000000}

Ровно пять WAVES. Комиссию заплатил отправитель, и на его счету стало на 500000000 + 100000 меньше.

Отвечено вопросов: 0 из 3
Чем набор типов транзакций Waves отличается от Ethereum?
Как назначается комиссия?
Ответ 200 на broadcast означает
Отвечено верно: 0 из 3

Когда узел отказывает​

ОТКАЗ УЗЛА ЧИТАЕТСЯ ПО ТРЁМ ПОЛЯМ{ "error": 112, "message": "State check failed. Reason: Fee for TransferTransaction (1000 in WAVES) does not exceed minimal value of 100000 WAVES.", "transaction": { …целиком то, что вы отправили… } }errorкод: 112 — не прошла проверка состояния, 306 — упал скрипт dAppmessageчеловеческая причина; в ней обычно есть и число, которого не хватилоtransactionваш же объект — удобно сверить, что ушло не то, что думали
Три поля отказа: код, человеческая причина и ваш собственный объект

Не хватает денег. Переводим больше, чем есть:

код: 400
{"error":112,"message":"State check failed. Reason: Attempt to transfer unavailable funds:
Transaction application leads to negative waves balance to (at least) temporary negative state,
current balance equals 500000000, …"}
Нажми на часть выражения

Слишком маленькая комиссия. Ставим 1000 вместо 100000:

код: 400
{"error":112,"message":"State check failed. Reason: Fee for TransferTransaction
(1000 in WAVES) does not exceed minimal value of 100000 WAVES."}

Сообщение прямо называет и то, что прислали, и то, что нужно. Такой отказ виден сразу, до блока.

Интересный факт

error: 112 — «не прошла проверка состояния». Этот же код выдаётся и при нехватке денег, и при маленькой комиссии, и при попытке распорядиться чужим активом. Смотреть надо не на код, а на message: там причина словами.

Подпись и поле proofs​

В объекте транзакции подпись лежит в массиве proofs, а не в одном поле. Массив — не прихоть: мест в нём до восьми.

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

tx.proofs // [ '4v5T8XJxrEMG…' ] — одна подпись
tx.proofs.length // 1

К этому вернёмся в главе про смарт-аккаунты. Пока достаточно помнить: подпись — это элемент массива, и обращаться к ней надо по индексу.

Читаем транзакцию из цепочки​

curl http://127.0.0.1:6869/transactions/info/<id>

Полезные поля ответа:

ПолеЧто означает
typeномер типа: 4 перевод, 12 данные, 16 вызов dApp
heightномер блока, в котором транзакция оказалась
applicationStatussucceeded или script_execution_failed
feeсколько списано комиссии
senderадрес отправителя
stateChangesдля типа 16: что именно изменил вызов
Важно

applicationStatus стоит проверять всегда. Транзакция может попасть в блок и не примениться — если скрипт dApp бросил ошибку после того, как комиссия уже была списана. Такое поведение похоже на Fabric: в цепочке запись есть, состояние не изменилось.

Отвечено вопросов: 0 из 3
Что означает error 112?
Почему подпись лежит в массиве proofs?
Зачем проверять applicationStatus?
Отвечено верно: 0 из 3

Типичные ошибки​

Ошибка 1. Считать 200 подтверждением.

Разобрано выше. Нужен цикл ожидания по /transactions/info/<id>.

Ошибка 2. Забыть chainId.

Библиотека по умолчанию подпишет для основной сети. Локальный узел такую транзакцию не примет, а сообщение будет про адрес, а не про сеть — и разбираться придётся долго.

Ошибка 3. Считать комиссию частью суммы.

transfer({ amount: balance }) // не пройдёт: на комиссию не осталось
transfer({ amount: balance - fee })

Узел откажет с «temporary negative state»: даже временный минус запрещён.

Ошибка 4. Дробная сумма.

amount: 1.5 * 100000000 // иногда 150000000.00000001
amount: 150000000 // так правильно

Ошибка 5. Повторная отправка того же объекта.

id считается из содержимого. Отправили дважды — второй раз узел ответит, что такая транзакция уже есть. Чтобы сделать перевод ещё раз, нужен новый объект: у него будет другая метка времени и другой id.

Отвечено вопросов: 0 из 3
Перевели ровно весь баланс. Что скажет узел?
Отправили один и тот же объект транзакции дважды. Что будет?
Забыли chainId. Что произойдёт?
Отвечено верно: 0 из 3

Шпаргалка по главе​

Что нужноКак
Переводtransfer({ amount, recipient, chainId }, seed)
Запись данныхdata({ data: [...], chainId }, seed)
Вызов dAppinvokeScript({ dApp, call, chainId }, seed)
ОтправитьPOST /transactions/broadcast с объектом транзакции
Проверить попаданиеGET /transactions/info/<id> — 404 значит «ещё нет»
Узнать комиссию заранееPOST /transactions/calculateFee
Список транзакций адресаGET /transactions/address/<адрес>/limit/10

Словарь главы​

ТерминЧто это
Тип транзакцииНомер, задающий и смысл действия, и набор полей, и цену
КомиссияФиксированная плата по типу; в Waves не аукцион
proofsМассив подписей, до восьми мест
id транзакцииСчитается из содержимого; повторить тот же объект нельзя
broadcastОтправка в сеть; ответ 200 — «принято в очередь»
applicationStatusПрименилась ли транзакция после попадания в блок
error: 112Не прошла проверка состояния
«Копейки»Целое число, в котором хранится сумма

Цель: скорость ≥ 95 зн/мин, точность ≥ 88%

const { transfer } = require('@waves/waves-transactions');

Что должен уметь после главы​

  • назвать четыре нужных типа транзакций и их цену;
  • объяснить, чем фиксированная комиссия отличается от аукциона газа;
  • собрать, подписать, отправить транзакцию и дождаться её попадания в блок;
  • прочитать отказ узла по трём полям и понять причину;
  • объяснить, зачем подпись лежит в массиве;
  • проверить applicationStatus и объяснить, зачем это нужно.

Проверка по главе​

Сводная проверка по всей главе: 10 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.

Куда дальше: проверенные ресурсы​

Видео по теме

ВидеоWAVES Transaction DemoThe Node: Blockchain News & Analysis
ВидеоWaves Smart Contracts: Escrow ExampleWaves Tech
ВидеоSigning transactions - Blockchain in Javascript (part 4)Simply Explained
ВидеоHow To Create Your Own Cryptocurrency Using Waves BlockchainHenry Odia
ВидеоCrash Course to Blockchain Tech with Waves (Part I)Openhack 2020 Australia

Комментарии

Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.