# База знаний Golos

[![](https://raw.githubusercontent.com/golos-blockchain/wiki/master/golos_logo.png)](https://golos.id/)

Данная Wiki точка сбора знаний по **блокчейну Голос** и его сервиса&#x43C;**.**\
\
Основные веб-клиенты - [golos.id](https://golos.id/) и [golos.in](https://golos.in/). Доступен и [golos.today](https://golos.today/), который выполняет роль тестового клиента, а также [десктоп-клиент](https://golos.id/ru--golos/@lex/alternativnyi-klient-blogov-golos-desktop-izmeneniya-v-tredakh-kommentariev) (установка на компьютере с ОС [Windows](https://files.golos.app/desktop-windows/)/[Linux](https://files.golos.app/desktop-linux/)).&#x20;

Из альтернативных [4-20.io](https://4-20.io/) и [expertgroup.org](https://expertgroup.org/), в сети TOR [goloszrorrdctlwf.onion](http://goloszrorrdctlwf.onion).\
\
Может оказаться полезным раздел [сервисы, игры, боты](https://golos.id/services), веб-клиенты форумов (напр. [golostalk.com](https://golostalk.com/)), биржи (напр. [gls.exchange](https://gls.exchange/)), мессенджер [chat.golos.app](https://chat.golos.app) (для [Android](https://golos.id/ru--golos/@lex/messendzher-na-android-a-takzhe-v-golos-desktop-versii-kontenta-posty-dlya-podpischikov)).

Начните изучение возможностей с раздела для [Пользователей](/users/welcome).

Если вас интересуют вопросы разработки для Голоса и на Голосе, полезную информацию вы найдёте в разделе для [Разработчиков](/developers/basics).


# Способы регистрации

Для получения доступа необходимо зарегистрироваться и создать аккаунт в блокчейне. Полученные логин и пароль с ключами можно использовать для входа через разные веб-клиенты (блоги, форумы, биржи), [сервисы/игры](https://golos.id/services) (работающие в сети блокчейна).&#x20;

Будьте внимательны прежде чем вводить пароль на незнакомых сайтах, в случае сомнений спрашивайте у сообщества. Доверенный сервис авторизации [golos.app](https://golos.app/)

### Способы регистрации:

* **Сервис** [**golos.app**](https://golos.app/) (с помощью почты @gmail.com, [инвайта](https://golos.id/ru--golos/@lllll1ll/registraciya-akkaunta-po-invait-kodu) от участника сообщества, переводом с бирж или через авторизацию ВКонтакте, Mail.ru, Яндексе...<br>
* **Через бота ВКонтакте** - [vk.com/reg\_golos\_ru](https://vk.com/reg_golos_ru) <br>
* **Если уже есть аккаунт, на** [golos.cf](https://golos.cf/reg/)

  Укажите логин и активный ключ регистратора, желаемые логин и пароль для нового аккаунта. Необходимо иметь на счету токены GOLOS (они будут переведены в Силу Голоса нового аккаунта).


# Старт на Golos Блоги

## Добро пожаловать на Голос!

Небольшое, но информативное руководство поможет вам разобраться в платформе.

Заходим на сайт [golos.id](https://golos.id) или [golos.in](https://golos.in), регистрируемся, записываем свой пароль и ключи (они будут сохранены и в файле), начинаем пользоваться!

### Какие главные секреты этой "кухни"?

Самый главный "секрет", это не гнаться за наградой. Публиковать интересный, увлекательный, полезный контент. Не унывать, если что-то не нравится другим пользователям. Пробовать писать что-то другое (читатели найдутся)!

Второй "секрет" - это общение. Больше общения.\
И если вы не нашли ответа на свой вопрос - спрашивайте в [чате сообщества](https://golos.chatbro.com/), в комментариях к постам старожилов, кто-то обязательно подскажет.

### Возьмут ли с меня деньги за пользование платформой?

Нет! Чтение, публикация, комментирование и апвоуты (лайки) бесплатны. Более того, Голос позволяет получать вознаграждения за активность (за посты. комментарии, репосты, торговлю на бирже и многое другое).

## Что можно делать на платформе Голос?

### Написание постов

Для того чтобы создать пост, нажмите на кнопку «Добавить пост» в верхнем правом углу экрана. Обратите внимание, что пост должен содержать: название, категорию, тэги (ключевые слова) и текст (который может включать в себя изображения, видео и прочее). Рекомендуем публиковать не более 4-х постов в день.

### Комментирование

Чтобы освоиться на платформе Голос, мы рекомендуем участникам комментировать как можно чаще. Высказывайтесь, делитесь своим мнением и находите интересных собеседников.

Для создания комментария нажмите кнопку «Ответить» после текста поста или комментария.

### Голос за (лайки)

Чтобы «лайкнуть» чей-то пост или комментарий, нажмите на кнопку в виде стрелочки в кружочке, она расположена под текстом поста или комментария.

Своим «лайком» вы даете автору знать, что его контент вам понравился, а пост будет выше в выдаче ленты Популярное, где возрастает вероятность получить благодарность читателей и в виде прямых вознаграждений/донатов.

### Голос против (дизлайки)

«Дизлайк» - это выражение отрицательного отношения к опубликованному посту или комментарию, понижению его в выдаче на сайте. Также «дизлайк» может уменьшить репутацию, если он поставлен участником с более высокой репутацией.

### Поделиться (реблог, репост)

Если вы хотите поделиться чьим-то постом с вашими подписчиками, нажмите на кнопку в виде стрелки назад под постом или в самой ленте. Пост появится в вашем блоге с обозначением "Поделился ...".

Также под каждым постом доступен [блок шеринга](https://golos.id/ru--golos/@lex/reposty-v-socseti-s-voznagrazhdeniem-golosami-i-prochie-novosti) в социальные сети. Для мотивации чаще делиться интересными постами (через партнёрский сервис Sharpay), Голос выплачивает токены за каждый репост и переходы по ссылкам из соцсетей.

### Продвинуть пост

В течение 7 дней любой пост на Голосе можно поднять в "блок продвигаемого контента", который закреплён сверху основных лент (Новое, Обсуждаемое, Популярное и Донаты). Кроме того, если в продвижение было отправлено >1 GBG к заголовку добавляется доп. отметка для обращения внимания.\
\
Кнопка "Продвинуть" доступна справа от тегов в конце любого поста.

![](/files/-MKV0zMqd430lldhgfoF)

Пост в продвижение которого отправлена наибольшая сумма в токенах GBG **будет закреплён первым**, в ленте Популярного, так как по сути это главная страница сайта - закрепляется топ-3 продвигаемых постов. Если другой пользователь отправляет большую сумму, пост сдвигается (его место всегда можно определить по ленте [Промо](https://golos.id/promoted), как и отправить дополнительный платёж и вновь попасть в продвигаемый топ).

### Подписки / лента

Для того, чтобы подписаться на автора, нажмите на ник автора и в выпадающем окошке нажмите на кнопку «Подписаться». Также можно перейти на страницу его профиля и нажать кнопку «Подписаться» в правом верхнем углу. Материал авторов, на которых вы подписались, появится у вас в Ленте.&#x20;

### Какие монеты есть на Голосе?

В Голосе два вида основных токенов (монет): Голос и Золотой. Также есть множество [UIA токенов](https://golos.id/ru--golos/@allforyou/torguem-na-vnutrennei-birzhe-golosa) (альтернативных монет созданных пользователями в эквиваленте ценности других криптовалют + для торговли ими).

**Голос (GOLOS)** - это основной токен. Он используется, чтобы обозначить размер вознаграждения пользователей платформы Голос в удобной для них валюте.

Сила Голоса (СГ, Golos Power) - определяет "вес" влияния вашего голоса (на ранжирование контента, на выбор делегатов, одобрение заявок на развитие и конечно на процент который вы получаете за хранение токенов в СГ). На данный момент в зависимости от размера вашей СГ процент от эмиссии новых токенов начисляется каждый час на CLAIM-баланс.

**Золотой (GBG)** - приравнивается к текущему курсу 1 мг золота на рынке драгоценных металлов, выраженному в токенах Голос.

> GBG расшифровывается как Gold backed by GOLOS (Золотой, обеспеченный ГОЛОСами).

### Выплаты вознаграждения

Начиная с декабря 2019 года (когда был принят [22-й хардфорк](/developers/hardforks/hf22_release)) - пользователи самостоятельно принимают решение насколько и что они готовы поддержать полученными как процент на Силу Голоса - токенами. Воспринимать такие награды/донаты можно как благодарность автору за понравившийся читателям контент.

### Ввод и вывод токенов

Токены GOLOS можно купить/продать через биржи указанные на [wallet.golos.id](https://wallet.golos.id/exchanges) (пока это RuDEX, шлюзы к разным криптовалютам на GolosDEX, Minter, Steem-Engine), иные формы обмена через сервисы или боты.

## Навигация по сайту

### Верхнее меню

*Лента* – Материал тех авторов, на которых вы подписаны\
*Новое* – Новые посты, отсортированы по дате, от нового к старому\
*Обсуждаемое* – Посты, получившие наибольшее количество комментариев\
*Популярное* – Популярные посты за неделю по мнению проголосовавших\
*Донаты* - Посты получившиеся наибольшее кол-во токенов от пользователей\
*Форумы* - Посты, написанные с разных форумов работающих в сети блокчейна

### Раздел «Профиль»

*Блог* – Все ваши посты и реблоги\
*Комментарии* – Все ваши комментарии\
*Ответы* – Ответы на ваши комментарии\
*Сообщения* – Личные сообщения из приватного мессенджера\
*Награды* – Полученные и отпр. донаты, авторские и кураторские награды\
\
*Кошелек* – Ваши балансы токенов (Голос, СГ, Золотой, UIA токены)\
*Биржа* – История совершенных сделок на внутренней бирже проекта\
*Настройки* – Персональные настройки аккаунта


# Кошелёк

Описание функций на вкладках кошелька

## Балансы <a href="#balansy" id="balansy"></a>

На первой вкладке кошелька представлены все виды балансов основных токенов блокчейна Голос - GOLOS и GBG. Также, в конце страницы отображается история последних операций, связанных с переводами токенов.

![](/files/-MO2d5mECiz8tr5n07-h)

### **НАКОПИТЕЛЬНЫЙ БАЛАНС**

По своей сути как "временный накопитель", чтобы отображать размер вашей доли от эмиссии токенов блокчейна, которая поступает (\~1 раз в час) пропорционально сумме Силы Голоса.

{% hint style="info" %}
На момент написания данной информации, делегаты блокчейна установили период востребования токенов равным **1 неделе**.
{% endhint %}

При этом если в течение этого промежутка времени вы не забрали свою долю - токены будут переведены на баланс фонда сообщества для развития проекта.

> Опции из дополнительного меню:

* *Пополнить TIP-баланс* - своего или другого аккаунта (нажав `РАСШИРЕННЫЕ ОПЦИИ`).
* *Увеличить Силу Голоса* - позволяет получить токены с баланса в Силу Голоса, чтобы увеличить вашу долю в проекте, влияние на платформе и получать ещё больше токенов на CLAIM-баланс.

### **TIP-БАЛАНС**

Не повторяясь описанием с сайта, это специальный баланс, с которого возможна отправка токенов другим пользователям (кроме бирж) с помощью постинг ключа, который используется намного чаще в разных сервисах и ботах. Тем самым обеспечивается дополнительная безопасность токенов, лежащих на основном балансе ГОЛОС (4-й на картинке).

> Опции из дополнительного меню (стрелочка справа от суммы на балансе):

* *Передать* - на другой аккаунт, при этом используется постинг ключ без необходимости ввода иных ключей или пароля.
* *Увеличить Силу Голоса* - позволяет перевести токены с этого баланса в Силу Голоса, чтобы увеличить вашу долю в проекте, влияние на платформе и получать больший процент на CLAIM-баланс.

### **СИЛА ГОЛОСА**

Токены GOLOS, вложенные в ваш аккаунт на долгосрочное хранение, чем больше у вас СГ, тем больший процент от эмиссии поступает на CLAIM-баланс и выше влияние на развитие проекта путём выбора делегатов и поддержки заявок воркеров через финансирование из [фонда сообщества](/users/update#dobavlena-sistema-vorkerov).

Сила Голоса, говоря иносказательно, это акции платформы, а каждый пользователь имеет свою долю в проекте, как и получает дивиденды :)

> Опции из дополнительного меню:

* *Уменьшить Силу Голоса* - вывод токенов в ликвидное состояние, который занимает 8 недель (раз в неделю равными долями 1/8 от той суммы, что была выбрана при включении понижения).
* *Делегировать Силу Голоса* - передача в пользование части токенов с помощью которой другой пользователь сможет больше влиять на ранжирование (лайки/дизлайки), и иметь более весомые награды за курирование контента.

### **ГОЛОС**

Это основной ликвидный баланс главного актива/криптовалюты проекта, токены с этого баланса можно отправлять на биржи.&#x20;

> Опции из дополнительного меню:

* *Передать* - на другой аккаунт. При переводе токенов на биржу или обменник не забывайте добавить заметку/memo, авторизоваться active-ключом или паролем для проведения транзакции.
* *Пополнить TIP-баланс* - своего или другого аккаунта (нажав `РАСШИРЕННЫЕ ОПЦИИ`).
* *Увеличить Силу Голоса* - перевести токены с баланса в Силу Голоса, чтобы увеличить вашу долю в проекте, влияние на платформе и получать больший процент на CLAIM-баланс.
* *Перевести в сейф* - это делается для сохранности, если есть подозрения, что активный ключ или пароль был скомпрометирован. Токены в сейф попадают мгновенно, а обратный вывод проводится 3 дня.

### **ЗОЛОТОЙ**

Cвободно перемещаемый и торгуемый на [внутренней бирже](https://golos.id/ru--golos/@allforyou/torguem-na-vnutrennei-birzhe-golosa) токен, приравненный к 1 мг золота. [Подробнее о GBG](/users/faq#pochemu-vveden-token-gbg-zolotoi).

> Опции из дополнительного меню:

* *Передать* - Золотые (GBG) передаются на другие аккаунты аналогично токенам GOLOS.
* *Перевести в сейф* - так же, как и с GOLOS выше.
* *Конвертация в Голос* - перевод токенов GBG в GOLOS занимает три с половиной дня. Конвертация осуществляется по среднему курсу в течение этих дней для снижения злоупотреблений спекуляцией.
* *Купить или продать* - ссылка на торговлю GBG в паре к GOLOS через внутреннюю биржу.

### СЕЙФ

Баланс для обеспечения сохранности токенов. Если есть подозрения, что активный ключ или пароль был скомпрометирован вы можете перевести ликвидные токены GOLOS и GBG в сейф и спокойно заниматься вопросом смены ключей/пароля.&#x20;

## Активы UIA

User Issued Assets - эмитированные пользователями активы (токены), которыми можно вознаграждать других, торговать на внутренней бирже, обмениваться, использовать в различных сервисах на блокчейне.&#x20;

![](/files/-MO2e6R234uZByPjIqSV)

Подробнее о UIA и торговле ими на внутренней бирже можно почитать [здесь](https://golos.id/ru--golos/@allforyou/torguem-na-vnutrennei-birzhe-golosa).&#x20;

## Инвайт-чеки

Чеки (инвайт-коды) — инструмент для передачи токенов другим людям вне блокчейна. [Подробнее](https://golos.id/ru--golos/@lex/cheki-kak-instrument-peredachi-tokenov) о инвайт-чеках.\
\
Использовать чек можно двумя способами: перевести его баланс на аккаунт или зарегистрировать новый аккаунт.

![](/files/-MO2dKml2OB8T_S2EPZS)

[Пример создания](https://golos.id/ru--golos/@lllll1ll/registraciya-akkaunta-po-invait-kodu) инвайта и регистрации нового аккаунта.

## Разрешения <a href="#razresheniya" id="razresheniya"></a>

На этой вкладке отображаются публичные ключи к вашему аккаунту, они начинаются с букв GLS и видны всем.

![](/files/-MO2dQEeM0EwTHq3YrFw)

Приватные ключи зашифрованы и блокчейн производит их расшифровку с применением главного пароля (полученного вами при регистрации).\
\
Вы можете узнать приватные ключи аккаунта, напр. нажав`показать приватный ключ` напротив ПОСТИНГ КЛЮЧА, и введя пароль. Ключ начинается на цифру 5, скопируйте его и пользуйтесь для авторизации. \
\
Ключи разного уровня доступа позволяют вам обеспечить большую безопасность для аккаунта, так как даже потеряв или скомпрометировав постинг ключ, никто не сможет распоряжаться вашими токенами (для этого нужен активный ключ или главный пароль). &#x20;

### **Постинг ключ**

Используется для авторизации на сайте, отправки постов и комментариев, голосования (лайки/дизлайки), отправки вознаграждений/донатов (кнопка отблагодарить). При этом его можно использовать даже с чужого компьютера, пользоваться ботами, сторонними приложениями, не рискуя своим основным балансом.

### **Активный ключ**

Для перевода токенов, выбора делегатов, выставления ордеров на внутренней бирже.

### **Ключ Владельца**

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

### **Ключ Заметок**

Memo ключ для зашифрованных к переводам токенов заметок (пока используется редко).

{% hint style="info" %}
Ключи - это основа управления аккаунтом! Рекомендуется хранить их в нескольких местах, а главный пароль особенно.\
\
Не вводите ключи в поля для этого не предназначенные и на непроверенных сайтах или сервисах.
{% endhint %}

Может пригодиться пост на тему [как работают ключи](https://golos.id/ru--golos/@lindsay/kak-rabotayut-klyuchi-i-paroli-golosa) в Голосе.

## Пароль

Нажимая на вкладку **Пароль**, вы видите следующую страницу:

![](/files/-MO2dY0XWOYpcwGmrKwD)

Эта вкладка понадобится только в том случае, если будет необходимость сбросить пароль (а вместе с ним будут сброшены и все ключи).


# Вопросы и ответы

## **Что такое Голос?**

Если проводить аналогию, блокчейн Голос это город, где можно построить очень многое: уже есть контентные проекты ([блоги](/users/welcome) и [форумы](https://golos.id/ru--golos/@lex/zapusk-foruma-golostalk-com)), приватный [мессенджер](https://golos.id/ru--golos/@lex/obmen-lichnymi-soobsheniyami-i-nachalo-dlya-golos-messenger), [внутренняя биржа](https://gls.exchange) с торговлей внутри проекта (а через внешние шлюзы и к другим криптовалютам), прочие [сервисы](https://golos.id/services), что угодно на выбор фантазии разработчиков :)\
\
Одно из популярных направлений, это Golos Блоги, медиаплатформа где можно публиковать посты, общаться в комментариях, репостить в социальные сети и получать за это токены GOLOS и другие.

Golos Блоги по своей сути очень близки Живому Журналу, но с элементами социальных сетей. Тут нет приоритета для тех или иных материалов, но чем интереснее, увлекательнее, полезнее контент - тем больше шансов получить благодарность в виде токенов от других пользователей.

## **В чем уникальность Голоса?**

Во-первых, блокчейн позволяет открыть двери в мир криптовалют через понятное взаимодействие с помощью ведения блога, общения в чатах, форумах (получая вознаграждения торгуемыми/ликвидными токенами), постепенно познавая множество иных "миниигр" на платформе и иных криптовалют на внутренней бирже.

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

В-третьих, это управляемая сообществом платформа, работа которой обеспечена серверами расположенными в разных странах и не зависит от прихоти 1 или 2 администраторов/владельцев. Многие способны запустить ноду блокчейна, веб-клиент, открыто обсуждать будущее, заказывать новые функции, влиять на дальнейшее развитие путём голосования согласно своей доли в проекте, да и просто через представителей в лице выбранных делегатов.

## **Чем Голос отличается от финансовой пирамиды?**

Вознаграждение пользователей осуществляется за счет эмиссии токенов. При этом распределением токенов управляют все пользователи сети.&#x20;

Отличие от финансовых пирамид фундаментально:

* открытый программный код;
* прозрачность всех операции;
* отсутствие конечного выгодоприобретателя;
* отсутствие обязательств на выплату фиксированного дохода;
* отсутствие центрального администратора.

Блокчейн - децентрализованный реестр сплошного учета транзакций со встроенными экономическими стимулами для участников сети, которые задаются математическим алгоритмом.

Для поддержания децентрализации предусмотрена система мотивации участников сети токенами. Токены эмитируются в соответствии с математическим алгоритмом и распределяются в качестве вознаграждения участникам сети.

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

## **Как эмитируются токены в Голосе?**

Согласно параметрам выбранным делегатами проекта по состоянию на май 2022 г. эмитируемые токены Голоса распределяются в следующей пропорции:

* 70% - поступают текущим держателям Силы Голоса на CLAIM-баланс (с которого можно как продолжать увеличивать свою долю, так и поддерживать участников проекта вознаграждая их полезную активность с TIP-баланса),
* 15% - поступает делегатам блокчейна на обеспечение технической поддержки функционирования сети и оплаты серверов,
* 5% - поступает в фонд сообщества (работников/воркеров), т.е. на дальнейшее развитие функционала, инфраструктуры веб-клиентов, приложений, маркетинг, графику и прочее.
* 10% - поступает в пул публикаций, токены с которого распределяются в зависимости от Силы Голоса кураторов при лайках/дизлайках под постами/комментариями (своего рода компенсация за ранжирование контента).

Данные параметры устанавливаются согласно медианы делегатских параметров и могут быть изменения делегатами проекта в любой момент.

## **На каких биржах торгуются токены?**

На данный момент токены проекта торгуются на [RuDEX](https://rudex.org/) и [GolosDEX](https://dex.golos.app), также доступны в [Minter](https://chainik.io/pool/GOLOSCHAIN/BNB) и [ECurrex](https://gateway.ecurrex.ru/buy_golos.php), при развитии оборота токенов и ликвидности, будет организован листинг и на более крупных площадках. Актуальный список доступен на странице <https://wallet.golos.id/exchanges>

## **Как обеспечивается работоспособность сети?**

Блокчейн Голос - это сеть из множества нод/серверов расположенных в разных уголках по всему миру. Такая децентрализация позволяет обеспечить устойчивость сети к атакам и блокировкам. Сайт [golos.id](https://golos.id/), [golos.in ](https://golos.in/)и другие лишь отображают данные из децентрализованной сети (базы данных) блокчейна и дают пользователям с ним взаимодействовать (записывать информацию).

Если по какой-то причине сайты будут заблокированы или атакованы на территории одной из стран, вопрос предоставления доступа пользователям Голоса к сети будет решаться путем создания зеркал сайта, иных клиентов и технических решений (актуальный список веб-клиентов указан на [главной странице](https://wiki.golos.id/) этой Вики).

Рекомендуется установка и [десктоп-клиента](https://golos.id/ru--golos/@lex/alternativnyi-klient-blogov-golos-desktop-izmeneniya-v-tredakh-kommentariev), по сути это сайт на вашем компьютере, который напрямую через ноды взаимодействует с блокчейном.

## **Почему введен токен GBG (Золотой)?**

В блокчейне Steem (форком которого является Голос) существует токен Стимдоллар SBD - это долговое обязательство блокчейна выплатить 1 американский доллар в Стимах в течении периода конвертации по среднему курсу. Наиболее близкой аналогий можно назвать это "облигациями".

В блокчейне Голос действует аналогичный токен Золотой (GBG), но он привязан к цене 1 миллиграмма золота. Это долговое обязательство блокчейна Голос выплатить стоимость 1 миллиграмма золота в Голосах в течении периода конвертации (3.5 дня) по среднему курсу.

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

## **Что такое децентрализация?**

Простыми словами, децентрализация - это отсутствие центрального органа управления. То есть нечто, что управляется не одним человеком / командой / органом, а сразу многими. Эти "многие" для управления добиваются консенсуса.

Простой пример - положив свои деньги в банк, вы доверяете банку (точнее руководству этого банка) ими управлять. То есть эти деньги, по сути, контролирует центральный орган управления банка.

Допустим у вас и еще у 100 человек есть свой бизнес (в котором вы все являетесь владельцами в зависимости от кол-ва токенов). Прежде чем вы что-то будете вместе делать, предстоит это обсудить с представителями сообщества в лице делегатов, крупными держателями акций проекта и т.д. Это и есть децентрализация, когда решение принимается многими участниками в обсуждениях, голосованиях, спорах :)

## Что такое отзывные UIA токены?

На [внутренней бирже](https://wallet.golos.id/market) Голоса вы могли встретить в некоторых торговых парах отметку что "*эмитент актива XXX может отзывать токены с баланса пользователей*". Обычно, в этом нет ничего опасного, так как владельцы шлюзов для обмена токенами оставляют эту возможность в технических целях (например, для противодействия мошенничеству или обработки ошибочных переводов).\
\
Однако, считаем нужным предупреждать пользователей о включенной опции, чтобы они лишний раз обратили внимание и потратили немного времени на уточнение данных по эмитенту актива и его репутации на проекте.


# Полезные статьи

* [Письмо новичку](https://golos.id/ru--blokcheijn/@liga.avtorov/tvorchestvo-bez-granic-pismo-novichku-na-golose) на Голос Блоги (автор [@liga.avtorov](https://golos.id/@liga.avtorov))
* Первые шаги на Голосе и [настройка профиля](https://golos.id/ru--golos/@vp-liganovi4kov/pervyi-shag-na-golose-znakomstvo-i-nastroika-profilya) (автор [@vp-liganovi4kov](https://golos.id/@vp-liganovi4kov))
* Описание [внутренней биржи](https://golos.id/ru--golos/@allforyou/torguem-na-vnutrennei-birzhe-golosa) на Голосе (автор [@allforyou](https://golos.id/@allforyou))
* Инструкция по [созданию UIA](https://golos.id/ru--golos/@allforyou/sozdaem-i-ispolzuem-uia-na-golose) токенов (автор [@allforyou](https://golos.id/@allforyou))
* [Как работают ](https://golos.id/ru--golos/@lindsay/kak-rabotayut-klyuchi-i-paroli-golosa)ключи и пароли на Голосе (автор [@lindsay](https://golos.id/@lindsay))
* Что означает и как работает [репутация](https://golos.id/ru--golos/@arcange/chto-takoe-reputaciya-na-golose-i-kak-ona-rabotaet) (автор [@arcange](https://golos.id/@arcange))


# Обновления на Голосе

С сентября 2019 г. (момента сохранения блокчейна силами сообщества). Подписывайтесь на новости https\://golos.id/@goloschain

## Сентябрь 2022

27 хардфорк (обновление протокола блокчейна)

### Делегирование СГ с правом на эмиссию

В дополнение к имеющемуся делегированию СГ с процентом, добавлена опция при которой станет возможным делегировать СГ с передачей права получения эмиссии. У получателя появляется автоматически наполняемый персональный пул для вознаграждений с TIP-баланса. [Подробнее >](https://golos.id/ru--golos/@lex/izmeneniya-27khf-gotovy-v-testovoi-seti-chast-1)

### Создание аккаунтов переводом токенов

Позволит купив токены на бирже или обменнике вывести их сразу для анонимного создания аккаунта. [Подробнее >](https://golos.id/ru--golos/@lex/izmeneniya-27khf-gotovy-v-testovoi-seti-chast-1)

### Функционал личной блокировки

На уровне блокчейна пользователь сможет противостоять хейту (сообщения в мессенджер, заметки к трансферам и донатам, игнор упоминаний @ника, а комментарии к постам/ответам будут с «токенизацией»). [Подробнее >](https://golos.id/ru--golos/@lex/izmeneniya-27khf-gotovy-v-testovoi-seti-chast-2)

## Июнь 2022

### Восстановление доступа с recovery-аккаунта

Добавлена форма смены recovery-аккаунта (доверенного аккаунта), кроме того реализован раздел восстановления старым паролем ключей после их сброса злоумышленником (угона аккаунта). [Подробнее >](https://golos.id/ru--golos/@lex/vosstanovlenie-dostupa-s-recovery-akkaunta-optimizaciya-delegatskikh-nod-pravki-registracii)

### Расширение для браузера Golos Keychain

Позволяет авторизовываться в различных сервисах, работающих на блокчейне Голос не только вводом ключей или используя веб-сервис golos.app. После входа доступны минимальные возможности кошелька аккаунта, по клику на логин и выбору настроек есть опция смены ноды. [Подробнее >](https://golos.id/ru--golos/@lex/donaty-v-messendzhere-rasshirenie-dlya-brauzera-golos-keychain-i-prochie-pravki)

## Май 2022

### Мессенджер на Android и Desktop

Обмен приватными сообщениями на устройствах с Android, добавлены уведомления, настройки включая выбор нод. В перспективе добавить на Google Play. Также, мессенджер включен в состав клиента Golos Desktop. [Подробнее >](https://golos.id/ru--golos/@lex/messendzher-na-android-a-takzhe-v-golos-desktop-versii-kontenta-posty-dlya-podpischikov)

### Внутренний обмен токенов

Функционал быстрого обмена токенов (GOLOS, GBG, UIA альтернативных шлюзов с LTC, DASH, HIVE, STEEM, USDT и другими). В обменнике, можно получить представление о сумме/курсе по сделке, ценности токенов в рублях (информация с CoinMarketCap). [Подробнее >](https://golos.id/ru--golos/@lex/bystryi-obmen-tokenov-ceny-s-coinmarketcap-pravki-desktop-klienta-vstraivanie-telegram-ssylok)

## Март 2022

### Golos Desktop - альтернативный клиент

Дополнительный способ обмена информацией аккаунтов и взаимодействия с кошельком. Минимизирует риски при блокировке публичных сайтов, так как работает напрямую с нодами блокчейна (плюсом полная прозрачность без фильтров, просмотр всего контента). [Подробнее >](https://golos.id/ru--golos/@lex/alternativnyi-klient-blogov-golos-desktop-izmeneniya-v-tredakh-kommentariev)

## Январь 2022

### Новый веб-клиент биржи DEX

Новый формат может позволить привлечь иную аудиторию, проекты заинтересованные в запуске своих шлюзов/обмена токенов, что в целом пойдёт на пользу всему блокчейну. [Подробнее >](https://golos.id/ru--golos/@graphenelab/reliz-novoi-birzhi-golos)

### Примеры операций и API для биржи

Биржевое API для сервисов-агрегаторов, примеры операций для автоматизации ордеров на GolosDEX, обновление Python-библиотеки. [Подробнее >](https://golos.id/ru--golos/@lex/posty-v-blogakh-primery-birzhevykh-operacii-api-birzhi-obnovlenie-python-biblioteki)

### Обновление ImageProxy и геймификация

Доработан сервис проксирования изображений для загрузки пользовательских файлов и расширен его функционал. Также были добавлены знакомые многим уровни (элементы геймификации). [Подробнее >](https://golos.id/ru--golos/@lex/obnovlenie-imageproxy-elementy-geimifikacii-udalenie-repostov)

## Ноябрь 2021

### Доработка интерфейса UIA-активов

Правила по депозиту и выводу UIA-токенов, запоминание и шифрование заметок. Эмитентам активов (создателям альтернативных UIA) токенов легче задавать необходимые пользователям подсказки для автоматизации. Добавлено [отображение токенов из ордеров](https://golos.id/ru--golos/@lex/balansy-tokenov-s-birzhi-utilita-analiza-dannykh-nod-obnovlenie-komponentov-i-prochee) на бирже (с возможностью отмены и перехода к торговым парам). [Подробнее >](https://golos.id/ru--golos/@lex/obnovlenie-interfeisa-uia-aktivov-servisa-ui-api-shifrovaniya-zapominaniya-memo-biblioteki-golos-lib-js)

### Сервис Golos OAuth

На базе сервиса регистрации был добавлен функционал OAuth [golos.app](https://golos.app) и подписи транзакций (GolosSigner), что расширяет возможности для клиентов/приложений блокчейна авторизовывать пользователей без запроса пароля/ключей. [Подробнее >](https://golos.id/ru--golos/@lex/golos-app-i-funkcional-oauth-signer-rasshirenie-uvedomlenii-i-prochie-pravki)

## Сентябрь 2021

26 хардфорк (обновление протокола блокчейна)

### Конвертация токенов GOLOS в GBG

Добавлена конвертация в стейблкоин (Gold backed by GOLOS), привязанный к стоимости 1 мг золота в токенах GOLOS. Кроме того изменен срок понижения Силы Голоса аккаунтов с 8 до 4 недель и другие изменения. [Подробнее >](https://golos.id/ru--golos/@lex/informaciya-o-nedavnikh-izmeneniyakh-26-khardforka-obnovleniya-koda-blokcheina)

### Сервис Golos Auth

Реализован отдельный сервис регистрации, OAuth и серверной авторизации, что позволит иметь более безопасную и функциональную основу для приложений и веб-клиентов к блокчейну. Сервис можно использовать как через API из своего интерфейса, так и запустить сконфигурируя его полностью под себя без затрат на проработку регистрации. [Подробнее >](https://golos.id/ru--golos/@lex/servis-golos-auth-nachalo-biblioteki-golos-libs-s-webassembly-event-plagin)

### Влияние на репутацию аккаунтов из профиля

Репутация приобретает большее значение, менять её возможно и из профиля, без привязки к постам/комментариям в рамках 7 дневного окна. Позволит быстрее реагировать сообществу на нечто полезное для проекта, и наоборот (по сути становясь отдельной "мини-игрой", с затратами батарейки аккаунта и вне общего пула наград). [Подробнее >](https://golos.id/ru--golos/@lex/informaciya-o-nedavnikh-izmeneniyakh-26-khardforka-obnovleniya-koda-blokcheina)

## Июль 2021

### Сервис уведомлений Golos Notify

Доработан сервис отображения активности, ускорения работы мессенджера, всплывающих уведомлений по наиболее актуальным операциям и действиях пользователей. [Подробнее >](https://golos.id/ru--golos/@lex/obnovlenie-servisa-golos-notify-js-biblioteki-i-prochie-pravki)

### Сервис прокси/кеширования фото

Реализован сервис кеширования загружаемых фото, с адаптацией под веб-клиенты (формат webp, фото стали более чем вдвое легче). Это позволило снять зависимость от внешних сервисов, оптимизацию изображений. [Подробнее >](https://golos.id/ru--golos/@lex/keshirovanie-foto-i-drugie-obnovleniya)

### Смешанная система вознаграждений

Наряду с [персональными пулами вознаграждений](/users/update#sistema-voznagrazhdenii-donaty) пользователи путём голосования за посты/комментарии распределяют и общий авторский пул. Добавлены ленты отображения всех постов/комментариев в блокчейне (без фильтров и скрытия по отрицательной репутации) с сортировкой по размеру ожидаемой выплаты. [Подробнее >](https://golos.id/ru--golos/@lex/vozvrashenie-obshego-pula-i-novye-pravki)

## Апрель 2021

### Добавлен мессенджер (приватные сообщения)

Возможность обмена личными сообщениями между пользователями блокчейна Голос в клиентах блогов и форумов. В планах десктоп/смартфон версии мессенджера. [Подробнее >](https://golos.id/ru--golos/@lex/obmen-lichnymi-soobsheniyami-i-nachalo-dlya-golos-messenger)

## Февраль 2021

### Внутренний поиск по блокчейну с Elasticsearch

Весь контент из блокчейна сохраняется в индексе Elasticsearch, что позволяет быстро найти любой пост или комментарий из имеющихся в базе \~10 млн. записей. Поиск по фразе, автору, тегам, периоду... [Подробнее >](https://golos.id/ru--golos/@lex/vnutrennii-poisk-na-golose-naidyotsya-vsyo)

### Возможность регистрации через соцсети

На странице регистрации веб-клиентов, помимо Gmail-почты и инвайта, добавлена возможность авторизации с помощью аккаунта ВКонтакте, Facebook, Яндекс и Mail.ru. [Подробнее >](https://golos.id/ru--golos/@lex/obnovleniya-v-blogakh-i-forumakh)

## Декабрь 2020

25 хардфорк (обновление протокола блокчейна)

### Добавление GOLOS в сервисе [C**oins.Black**](https://coins.black/)

Сервис обмена криптовалют, позволяющий купить токены, используя сотню вариантов оплаты при минимальной комиссии и отсутствии верификации личности. [Подробнее >](https://golos.id/ru--golos/@on0tole/pryamaya-pokupka-tokenov-golos-za-rubli-i-ne-tolko)

### Форумный веб-клиент на блокчейне

Этот формат может позволить привлечь иную аудиторию, проекты заинтересованные в нецензурируемости контента, расширить охват, что в целом пойдёт на пользу всему блокчейну. [Подробнее >](https://golos.id/ru--golos/@lex/zapusk-foruma-golostalk-com)

## Октябрь 2020

24 хардфорк (обновление протокола блокчейна)

### Возможность создания собственных токенов

Добавлен функционал эмитирования активов пользователями (User Issued Assets - UIA). Это позволит создавать на блокчейне свои собственные токены, торговать ими на внутренней бирже, использовать их в качестве вознаграждений/донатов, интеграции в сервисах, ботах, играх, для запуска бирж и шлюзов (открытия торговли с популярными криптовалютами). [Подробнее >](https://golos.id/ru--golos/@allforyou/sozdaem-i-ispolzuem-uia-na-golose)

### Сжигание токенов аккаунта bittrex

В целях снижения инфляции и долга GBG делегатами блокчейна было принято решение направить токены аккаунта `bittrex` на `null` (произведя их сжигание из экономики, выведение из оборота).

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

### Обновление базы знаний [wiki.golos.id](https://wiki.golos.id/)

Актуализация информации во всех разделах базы знаний о блокчейне Голос для пользователей, разработчиков, делегатов.

## Май 2020

23 хардфорк (обновление протокола блокчейна)

### Система вознаграждений (донаты)

Так как система вознаграждений с борьбой за распределение общего пула показала себя малоэффективной, было принято решение о внедрении персональных пулов вознаграждений.\
\
Теперь большая часть эмиссии токенов блокчейна поступает на [CLAIM-балансы](/users/welcome/wallet#claim-balans) пользователей пропорционально размеру их Силы Голоса к общей СГ в системе. Именно с этого баланса пользователи самостоятельно получают/востребуют токены (решая, сколько из них направить в увеличение СГ, а сколько на [TIP-баланс](/users/welcome/wallet#tip-balans) для вознаграждения развития активности сообщества).

### Снижение срока понижения Силы Голоса

С учётом перехода к новой системе вознаграждений и обсуждения влияния возможных спекуляций на рынке, принято компромиссное решение уменьшить срок понижения Силы Голоса до 8 недель (было 13 недель).

### Добавление системы чеков/инвайтов

Пользователи могут создавать чеки на любое количество ликвидных токенов, имеющихся на балансе. Такие чеки/коды на предъявителя представляют собой пару ключей (публичный и приватный).

Это удобный элемент для привлечения новых пользователей - отправлять им чек с балансом, который они могут использовать при [упрощенной регистрации](https://golos.id/ru--golos/@lllll1ll/registraciya-akkaunta-po-invait-kodu). С использованием чеков токены можно продавать/покупать через площадки цифрового контента, распечатывать в виде QR-кодов, игр и т.д. [Подробнее >](https://golos.id/ru--golos/@lex/cheki-kak-instrument-peredachi-tokenov)

### Реферальная программа

Дополнительный инструмент стимулирования привлечения аудитории. К каждой ссылке на посты пользователей при их авторизации добавляется `?invite=РЕФЕРЕР` Например, если вы поделились постом или прямой ссылкой на страницу Добро пожаловать (`https://golos.id/welcome?invite=АККАУНТ`) в случае регистрации после перехода по такой ссылке новый пользователь станет вашим рефералом.\
\
На протяжении 1 года вы (как приглашающий/реферер) будете получать 10% от вознаграждений, поступающих в адрес приглашенного/реферала. [Подробнее >](https://golos.id/ru--golos/@lex/referalnaya-programma-i-para-slov-o-fonde-soobshestva)

## Февраль 2020

### Вознаграждения за репосты в соцсети

При взаимодействии с блокчейн-проектом [Sharpay](https://sharpay.io/ru/#view) в Golos Блоги добавлен блок кнопок "Поделиться" в социальные сети. Каждый репост + органические визиты по таким ссылкам из соцсетей оплачиваются токенами GOLOS на баланс кошелька [личного кабинета](https://app.sharpay.io/profile/wallet) сервиса Sharpay. [Подробнее >](https://golos.id/ru--golos/@lex/reposty-v-socseti-s-voznagrazhdeniem-golosami-i-prochie-novosti)

### Удобный просмотр фотопостов&#x20;

Так как большое количество постов на Golos Блоги содержат фотографии и порой их интересно рассмотреть подробнее, по нажатию на фото теперь открывается [просмотрщик](https://golos.id/ru--golos/@lex/udobnyi-prosmotr-fotopostov-pravki-po-skrytiyu-kommentariev) с возможностью пролистывания + увеличения фото.

### Добавление Голос в рейтинги

Актуализирована информация о блокчейне Голос на [CoinMarketCap](<https://coinmarketcap.com/currencies/golos-blockchain/ >), [СoinGecko](<https://www.coingecko.com/en/coins/golos-blockchain >), [СryptoCompare](https://www.cryptocompare.com/coins/gls/overview) и в популярном приложении [Blockfolio](https://blockfolio.com/).

### Запуск альтернативных веб-клиентов

Был запущен дополнительный веб-клиент Golos Блоги [golos.in](https://golos.in), который расположен на других серверах и использует другие ноды. Кроме того, отдельно был выделен клиент [golos.today](https://golos.today) (для тестирования обновлений).

В сети TOR начал работать [goloszrorrdctlwf.onion](http://goloszrorrdctlwf.onion). Также при использовании децентрализованных DNS от [OpenNIC](https://www.opennic.org/) доступен [gol.oss](http://gol.oss).

## Декабрь 2019

22 хардфорк (обновление протокола блокчейна)

### Добавлена система воркеров

Это функционал, который позволяет оплачивать токенами из [общего фонда](https://golos.id/workers) сообщества любую полезную работу для блокчейна Голос: разработка кода, серверы, реклама, дизайн, документация и пр. Словом, всё что угодно, если эту активность голосованием поддержит сообщество.\
\
Подобная практика стимулирования активности токенами потенциально может привести к появлению новых приложений, сервисов, игр, маркетинговой активности и многому другому. Важно, что не только делегаты, а все участники сообщества могут голосовать по заявкам как "за", так и "против". [Подробнее >](https://golos.id/ru--golos/@lex/interfeis-dlya-zayavok-vorkerov)

### Настройки распределения эмиссии

У [делегатов](https://wiki.golos.id/witnesses/basics) блокчейна появилась возможность менять параметры % распределения эмиссии/печати токенов по пулам наград, чтобы более оперативно регулировать экономические процессы.\
\
По состоянию на май 2021 г. установлены след. параметры:

* 74% эмиссии - поступает держателям Силы Голоса на CLAIM-баланс (с которого можно как увеличивать свою долю, так и вознаграждать активность других пользователей через TIP-баланс);
* 15% - поступает делегатам блокчейна на обеспечение технической поддержки функционирования сети и оплаты серверов;
* 10% - поступает в фонд сообщества/воркеров, на дальнейшее развитие функционала, инфраструктуры, приложений, маркетинг и прочее;
* 1% - поступает в общий пул публикаций, токены с которого распределяются в зависимости от Силы Голоса кураторов при лайках/дизлайках (компенсация за ранжирование контента).

### Понижение Силы Голоса при неактивности

В случае, если на аккаунте в течение 6 месяцев не было совершенно действий с использованием активного ключа (перевод токенов с основного баланса, увеличение СГ, ставки на [внутренней бирже](https://golos.id/market/GBG/GOLOS), выбор [делегатов](https://golos.id/~witnesses) и др.) - запускается механизм понижения Силы Голоса, т.е. токены перемещаются с баланса СГ на ваш обычный/ликвидный баланс.

Тем самым эти аккаунты перестают влиять на выбор делегатов и получать долю от эмиссии токенов блокчейна пропорционально своей Силе Голоса (так как пассивны в управлении и развитии проекта).

### Изменение принципа голосования за делегатов

Если ранее можно было выбирать до 30 делегатов с полным весом своей Силы Голоса за каждого из них (о минусах подобного писали [тут](https://golos.id/newgolos/@newgolos/voterules323289)), теперь размер СГ станет делиться на кол-во поддерживаемых делегатов.

Напр. если у вас 30 000 Силы Голоса и вы поддержите 3 делегатов, в поддержку каждого из них будет отдано только по 10 000 СГ.

### Решение вопроса долга токена GBG

При объеме долга более 20% запускается механизм ежедневной конвертации 1% доступных на балансах GBG в GOLOS (при этом ордера на внутренней бирже отменяются перед конвертацией).\
\
Этот вариант был описан [здесь](https://golos.id/golos/@gusaru/sostoyanie-defolta-golos-blockchain-i-chto-s-etim-delat), а также [рассматривался](https://steemit.com/steem/@dantheman/steem-dollar-stability-enhancements) ранее как оптимальный одним из создателей проектов Bitshares/Steem/EOS. Данное решение позволит сделать стейблкоин более устойчивым в будущем.


# Основы

Раздел с описанием API/объектов/структур в блокчейне, примеры кода для популярных вариантов использования, гайд для формирования транзакций.

* [Операции и их типы](/developers/basics/operations)
* [Объекты и структуры](/developers/basics/object-structures)
* [Состояние (стэйт) системы](/developers/basics/state)
* [Плагины и их API](/developers/basics/plugins-api)
* [Библиотеки для работы](/developers/basics/libraries)
* [Примеры кода](/developers/basics/code-examples)
* [Формирование транзакций](/developers/basics/transaction-formatting)
* [Пропускная способность](/developers/basics/bandwidth)

Полезно будет ознакомиться с документацией блокчейна [Steem](https://developers.steem.io/) или [Hive](https://developers.hive.io/), которая во многом близка и для блокчейна Голос (форк с базы Steem в 2016).


# Операции и их типы

Операции в блокчейне GOLOS делятся на обычные и виртуальные. Обычные операции попадают в блокчейн через подписанную транзакцию участника сети.&#x20;

Виртуальные операции генерируются нодой когда срабатывают определенные условия в коде и носят больше информационный характер для участников сети.&#x20;

## Нумерация операций

В протоколе GOLOS [есть нумерация операций](https://github.com/golos-blockchain/golos/blob/master/libraries/protocol/include/golos/protocol/operations.hpp#L14) (начинается с нуля), там находятся как обычные, так и виртуальные операции:

* vote: 0
* comment: 1
* transfer: 2
* transfer\_to\_vesting: 3
* withdraw\_vesting: 4
* limit\_order\_create: 5
* limit\_order\_cancel: 6
* feed\_publish: 7
* convert: 8
* account\_create: 9
* account\_update: 10
* witness\_update: 11
* account\_witness\_vote: 12
* account\_witness\_proxy: 13
* pow: 14
* custom: 15
* report\_over\_production: 16
* delete\_comment: 17
* custom\_json: 18
* comment\_options: 19
* set\_withdraw\_vesting\_route: 20
* limit\_order\_create2: 21
* challenge\_authority: 22
* prove\_authority: 23
* request\_account\_recovery: 24
* recover\_account: 25
* change\_recovery\_account: 26
* escrow\_transfer: 27
* escrow\_dispute: 28
* escrow\_release: 29
* pow2: 30
* escrow\_approve: 31
* transfer\_to\_savings: 32
* transfer\_from\_savings: 33
* cancel\_transfer\_from\_savings: 34
* custom\_binary: 35
* decline\_voting\_rights: 36
* reset\_account: 37
* set\_reset\_account: 38
* delegate\_vesting\_shares: 39
* account\_create\_with\_delegation: 40
* account\_metadata: 41
* proposal\_create: 42
* proposal\_update: 43
* proposal\_delete: 44
* chain\_properties\_update: 45
* break\_free\_referral: 46
* delegate\_vesting\_shares\_with\_interest: 47
* reject\_vesting\_shares\_delegation: 48
* transit\_to\_cyberway: 49
* worker\_request: 50
* worker\_request\_delete: 51
* worker\_request\_vote: 52
* fill\_convert\_request: 53
* author\_reward: 54
* curation\_reward: 55
* comment\_reward: 56
* liquidity\_reward: 57
* interest: 58
* fill\_vesting\_withdraw: 59
* fill\_order: 60
* shutdown\_witness: 61
* fill\_transfer\_from\_savings: 62
* hardfork: 63
* comment\_payout\_update: 64
* comment\_benefactor\_reward: 65
* return\_vesting\_delegation: 66
* producer\_reward: 67
* delegation\_reward: 68
* auction\_window\_reward: 69

Номер операции нужен для низко-уровневого формирования транзакций и их подписи (подробнее в разделе [Формирование транзакций](/developers/basics/transaction-formatting)).


# Объекты и структуры

Рассматривая GOLOS необходимо разделять объекты и структуры протокола (операция, транзакция, блок, ассет, версия, полномочия) от объектов и структур которые существуют непосредственно в блокчейне (на которые влияют те или иные операции).

## Список объектов и структур протокола

Все, что касается протокола находится [в каталоге /libraries/protocol](https://github.com/golos-blockchain/golos/tree/master/libraries/protocol) исходного кода C++ ноды блокчейна GOLOS.

* **types / типы данных** в протоколе
* **operations / proposal\_operations / chain\_operations / chain\_virtual\_operations / операция** — все что связано с операциями и их обработкой;
* **transaction / транзакция** — все что связано с транзакцией (id, список операций, к какому блоку она ссылается);
* **block\_header / block / блок** — содержит транзакции, ссылается на предыдущий блок, содержит extensions который может использовать делегат для инициации голосования за переход на новую версию хардфорка;
* **asset / ассет** — структура токенов (отношение ассетов разного разряда друг к другу);
* **base / version / версия** — структура описывающая версию протокола сети, голос и время за переход на новую версию;
* **authority / полномочия** — структура описывающая связку ключей для определенного типа доступа аккаунта;
* **sign\_state / состояние подписи** — помощник по проверке подписей (или наличия ключа, который может ее сгенерировать).

## Объекты и структуры в блокчейне

Именно из объектов и структур самого блокчейна состоит состояния системы (стэйт). Каждый блок содержащий операции обрабатывается основным модулем database, который просчитывает все изменения и принимает решения по отложенным действиям. В каталоге [/libraries/chain/include/graphene/chain](https://github.com/golos-blockchain/golos/tree/master/libraries/chain/include/golos/chain) содержатся как объекты и структуры данных, так и внутреннее устройство блокчейна (evaluator, block\_log, dynamic\_global\_property\_object, [типы объектов](https://github.com/golos-blockchain/golos/blob/master/libraries/chain/include/golos/chain/steem_object_types.hpp)).

Состояние системы состоит из объектов:

* **dynamic\_global\_property\_object** — основной объект содержащий данные о текущем состоянии экономики и состоянии ноды (например, номер необратимого блока);
* **account\_object** — записи аккаунтов;
* **account\_authority\_object** — записи полномочий для аккаунтов;
* **witness\_object** — записи делегатов;
* **transaction\_object** — используется для транзакций в очереди (это позволяет проверять отсутствии дублей у новых транзакций и удалять транзакции из очереди, если она не выполнилась до срока истечения expire);
* **block\_summary\_object** — используется для индексации блоков и их hash, [для проверки TaPoS](/developers/basics/state) (транзакция должна ссылаться на прошлый блок, проверка происходит как раз по индексу, построенному из объектов `block_summary_object`);
* **witness\_schedule\_object** — состояние очереди делегатов;
* **witness\_vote\_object** — записи голосов за делегатов;
* **hardfork\_property\_object** — записи о текущем хардфорке сети;
* **withdraw\_vesting\_route\_object** — записи о маршруте распределения токенов при конвертации доли;
* **master\_authority\_history\_object** — записи изменений мастер полномочий;
* **account\_recovery\_request\_object** — запросы на восстановление аккаунта;
* **change\_recovery\_account\_request\_object** — запросы на смену доверенного аккаунта для восстановления доступа;
* **escrow\_object** — записи о трехсторонних сделках;
* **vesting\_delegation\_object** — записи о делегированной доли;
* **vesting\_delegation\_expiration\_object** — записи о возвращаемой делегированной доле после отмены делегирования;
* **account\_metadata\_object** — отдельные записи с мета-данными аккаунта;
* **proposal\_object** — записи proposal операций;
* **required\_approval\_object** — записи требуемых подтверждений для proposal операций;
* и другие...

## Объекты и структуры в API плагинах

Плагины предоставляющие API могут возвращать объекты как из блокчейна, так и собственные. Простые запросы с получением объекта по id отдают данные как есть, часто пропуская объект из блокчейна через конструктор аналогичного для API, чтобы скопировать состояние и отдать его пользователю, например: плагин `witness_api` использует отдельный объект `witness_api_object`. А плагин `database_api` использует `account_api_object`, который дополняет стандартный объект блокчейна аккаунт типами доступа копируя туда актуальные полномочия из индекса.

Если плагин расширяет стандартные таблицы индексов и объекты, то он создает новую структуру, отдельно ведет учет операций и заполняет индекс. Например, так поступает плагин `private_message`, обрабатывая custom операции (создавая объекты `message_object`, наполняющие индекс `message_index`).


# Состояние (стэйт) системы

Состояние системы — необходимый минимум данных, для функцонирования ноды. Каркас Graphene, на котором построен GOLOS, исполняет операции из транзакций в каждом блоке, который соответствует консенсусу (очереди делегатов, соответствие подписей). Каждый блок происходит обработка данных, отложенных действий, что приводит к иттерационной сущности состояния системы. Часть данных хранятся там постоянно, что накладывает определенные требования на серверное оборудование, на котором запущена нода.

> В разделе [Объекты и структуры в блокчейне](/developers/basics/object-structures) описана большая часть объектов, которые составляют состояние системы.

## Dynamic global property object (dgpo)

Данный объект хранит основные свойства сети, содержит информацию о токенах в обращении и другую важную информацию. В исходном коде он часто представлен в виде переменной dgp, нода модифицирует его состояние с каждой иттерацией, поэтому dynamic global property можно с уверенностью считать самой важной частью состояния системы. Рассмотрим его публичные свойства, доступные через метод get\_dynamic\_global\_properties при обращении к плагину database\_api:

* **current\_witness** (пример значения: "blockchained") — делегат актуального блока;
* **head\_block\_number** (пример значения: 34939787) — номер актуального блока;
* **head\_block\_id** (пример значения: "0215238bf875e34e09a0c7335c3751c40520e73f") — идентификатор (он же хэш) актуального блока;
* **time** (пример значения: "2020-02-19T11:40:57") — время генерации актуального блока;
* **last\_irreversible\_block\_num** (пример значения: 34939769) — номер последнего необратимого блока;
* **current\_supply** (пример значения: "200739832.421 GOLOS") — общее количество токенов GOLOS в системе;
* **total\_vesting\_fund** (пример значения: "80099681.756 GOLOS") — количество токенов GOLOS переведенных в долю сети (GOLOS POWER);
* **total\_vesting\_shares** (пример значения: "251336005597.634797 GESTS") — общая количественная мера доли сети в GESTS;
* **total\_reward\_fund\_steem** (пример значения: "255.357 GOLOS") — баланс пула наград;
* **total\_reward\_shares2** (пример значения: "21280044314718424") — количественная мера конкуренции за пул наград;
* **current\_aslot** (пример значения: 35108019) — текущий номер слота делегата на подпись (содержит в себе нумерацию слота от старта в сети, включая пропущенные делегатами блоки);
* **recent\_slots\_filled** (пример значения: "340282366920938463463374607431768211455") — используется для вычисления процента делегатов участвующих в подписи блоков;
* **participation\_count** (пример значения: 128) — необходимо разделить на 128, чтобы получить процент делегатов участвующих в подписи блоков;
* **maximum\_block\_size** (пример значения: 65536) — максимальный размер блока в байтах (голосуемый параметр сети);
* **average\_block\_size** (пример значения: 209) — средний размер блока, рассчитывается по формуле `average_block_size = (99 * average_block_size + new_block_size) / 100`, используется для обновления current\_reserve\_ratio для поддержания около 50% или меньше в пропускной способности сети;
* **max\_virtual\_bandwidth** (пример значения: "5986734968066277376") — максимальная пропускная способность сети рассчитывается по формуле `maximum_block_size * CHAIN_BANDWIDTH_AVERAGE_WINDOW_SECONDS / CHAIN_BLOCK_INTERVAL`, максимальная виртуальная пропускная способность сети по формуле `max_bandwidth * current_reserve_ratio`
* **current\_reserve\_ratio** (пример значения: 20000) — Раз в 20 блоков (1 минута) происходит проверка `average_block_size <= 25% maximum_block_size`. Если оно выполняется, то данное значение увеличивается на 1 (линейно, каждый блок), но не более CHAIN\_MAX\_RESERVE\_RATIO (20000). Если условие не выполнено, то current\_reserve\_ratio делится пополам, что должно сразу снизить нагрузку на сеть, защищая ее от участников, использующих объемные транзакции. Другими словами уменьшение вдвое резервного соотношения не уменьшит вдвое использование сети, но ограничит пользователей которые уже попытаются превысить более 50% от их пропускной способности. Когда резервное соотношение падает вдвое от максимального значения (10000 вместо 20000), восстановление общей виртуальной пропускной способности займет около 7 суток.
* и другие...

## Уникальность транзакций и TaPoS (Transactions as Proof of Stake)

Нода проверяет все входящие транзакции на уникальность в пуле транзакций. После того как наступает expiration (ограничено в настройках константой CHAIN\_MAX\_TIME\_UNTIL\_EXPIRATION в один час), транзакция удаляется из пула.

Все транзакции в GOLOS должны [соответствовать концепции TaPoS](https://github.com/super3/invictus.io/blob/master/assets/pdf/TransactionsAsProofOfStake10.pdf), то-есть ссылаться на один из прошлых блоков (ref\_block\_num в 2 байтовом представлении (бинарное «и» десятичного представления номера блока с hex `ffff`) и ref\_block\_prefix состоящий из десятичного представления 5, 6, 7, 8 байтов от бинарного состояния хэша в обратном порядке), что позволяет иницатору транзакции опираться на актуальное для него состояние системы не беспокоясь о необратимом блоке. В случае, если он опирался на состояние системы в случайном минорном форке, то транзакция не попадет в основную цепочку. Таким образом участники сети могут контролировать исполнение очереди транзакций и строить взаимодействие не дожидаясь необратимости блока. Это, в свою очередь, накладывает ограничение на финальный учет подобных действий, поэтому большинство важных транзакций должны находиться уже в необратимом состоянии для проверяющей стороны.

Нода выделяет пространство block\_summary\_object с размерностью в 2 байта (чтобы номер блока прошедший через операцию бинарного «и» с hex `ffff` умещался в диапазоне от 0 до 65536) и принимая новые блоки перезаписывает по кругу идентификаторы (хэши) в этом пространстве (и индексе block\_summary\_index). 65537 блоков охватывают временной промежуток 196611 секунд (примерно 2.27 суток). Соответственно новые транзакции могут ссылаться только на блоки из этого пространства, чтобы нода могла сверить соответствие идентификатора блока (из ref\_block\_num) с контрольной суммой из ref\_block\_prefix.


# Плагины и их API

Плагины представляют собой универсальный инструмент расширения ноды и её возможностей. Часть из них лишь отдают данные, подготавливают индексы, отвечают на сложные запросы пользователей с фильтрацией данных, часть из них обрабатывают custom операции и могут предоставлять совершенно отдельный сервис.&#x20;

В данном разделе описаны некоторые доступные плагины GOLOS, предоставляющие пользователям доступ через API. Вы можете сами изучить API того или иного плагина, если будете следовать следующей инструкции:

* Открыть основной заголовочный файл плагина ([пример для database\_api](https://github.com/golos-blockchain/golos/blob/master/plugins/database_api/include/golos/plugins/database_api/plugin.hpp)), изучить `DEFINE_API_ARGS` (название API метода, тип возвращаемого значения);
* Открыть основной файл плагина ([пример для database\_api](https://github.com/golos-blockchain/golos/blob/master/plugins/database_api/api.cpp#L152)), изучить `DEFINE_API` (проверка параметров запроса, `CHECK_ARGS_COUNT`, формирование возвращаемого значения определенного типа);
* Изучить `plugin_initialize`, который может обрабатывать `boost::program_options::variables_map` для более тонкой настройки плагина через конфигурационный файл ноды.

## Протокол запросов

Все запросы должны быть сформированы в JSON и выполнены через RPC. Транспортный протокол зависит от настройки ноды, возможны варианты как JSON-RPC через стандартные HTTP запросы, так и через WebSocket.

Для этого в конфигурационном файле ноды должны быть подключены плагины: json\_rpc, webserver. Чтобы принимать транзакции от пользователей также должен быть включен плагин network\_broadcast\_api. Настройки для портов:

```
# Количество потоков для клиентов rpc. Оптимальное значение *количество ядер минус 1*
webserver-thread-pool-size = 2

# IP:PORT для HTTP подключений
webserver-http-endpoint = 0.0.0.0:8090

# IP:PORT для WebSocket подключений
webserver-ws-endpoint = 0.0.0.0:8091
```

Чтобы обрабатывать запросы с поддержкой SSL, необходимо пробросить используемые порты через проксирующий сервер (например, nginx или apache), тогда станут возможными запросы через https/wss.

## Формирование API запроса

Правила формирования запросов к публичной ноде довольно простые:

```
{"id":REQUEST_ID,"jsonrpc":"2.0","method":"call","params":["PLUGIN_NAME","PLUGIN_API_METHOD",[ARGS]]}
```

* REQUEST\_ID — номер запроса, носит необязательный характер (можно все запросы нумеровать единицей), но при соединении через web sockets (ws) позволяет ассоциировать ответы по запросам с аналогичным id;
* PLUGIN\_NAME — название плагина, к которому выполняется запрос (например: database\_api, committee\_api);
* PLUGIN\_API\_METHOD — название метода, обрабатывающего запрос (например: get\_accounts из database\_api);
* ARGS — массив упорядоченных параметров, передаваемый методу плагина.

## network\_broadcast\_api

Плагин, отвечающий за прием и рассылку между узлами сети подписанных блоков и транзакций

* **broadcast\_block** — передача подписанного блока (signed\_block) другим узлам сети;
* **broadcast\_transaction** — передача подписанной транзакции (signed\_transaction) другим узлам сети;
* **broadcast\_transaction\_synchronous** — передача подписанной транзакции (signed\_transaction) другим узлам сети (ждет вхождения в блок и возвращает хэш транзакции, номер блока и номер транзакции в блоке, или возвращает false в случае истечения срока действия транзакции);
* **broadcast\_transaction\_with\_callback** — то же, что и broadcast\_transaction\_synchronous, кроме проверки транзакции на валидность перед передачей в пул транзакций и регистрации метода обратного вызова (callback).

## database\_api

* **get\_account\_count** — возвращает количество аккаунтов в сети;
* **get\_accounts** — возвращает массив аккаунтов по запрошенным логинам (отличается от **lookup\_account\_names** дополнительной информацией);

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_accounts",[["xel"]]]}
```

Ответ:

```javascript
[
  {
    "id": 89772,
    "name": "xel",
    "owner": {
      "weight_threshold": 1,
      "account_auths": [],
      "key_auths": [
        [
          "GLS53nbKGcMwXw8zWMNLBm5XXLTW9fqZeQT5J7dC3Qso7GwJ7F8Hb",
          1
        ]
      ]
    },
    "active": {
      "weight_threshold": 1,
      "account_auths": [],
      "key_auths": [
        [
          "GLS81ApmkpdaJfbCXe7ZkbaiMeVcaQFW361sqC9r414fxVq9jNH3i",
          1
        ]
      ]
    },
    "posting": {
      "weight_threshold": 1,
      "account_auths": [],
      "key_auths": [
        [
          "GLS7WLHYqZrf9RYW273X34Aee7mK9pet8t83xgQ8jxeeZXXG3cTvS",
          1
        ]
      ]
    },
    "memo_key": "GLS8iWbEMQB3WaXHLrCVyDoJAuPQhaiCby3g3PNL4h2hdWq7kiACb",
    "json_metadata": "{"profile":{}}",
    "proxy": "",
    "last_owner_update": "2019-05-10T14:10:30",
    "last_account_update": "2019-05-10T14:10:30",
    "created": "2017-12-06T01:22:18",
    "mined": false,
    "owner_challenged": false,
    "active_challenged": false,
    "last_owner_proved": "1970-01-01T00:00:00",
    "last_active_proved": "1970-01-01T00:00:00",
    "recovery_account": "lex",
    "last_account_recovery": "1970-01-01T00:00:00",
    "reset_account": "null",
    "comment_count": 4,
    "lifetime_vote_count": 0,
    "post_count": 0,
    "can_vote": true,
    "voting_power": 9802,
    "last_vote_time": "2020-01-05T12:10:48",
    "balance": "23.549 GOLOS",
    "savings_balance": "0.000 GOLOS",
    "sbd_balance": "0.000 GBG",
    "sbd_seconds": "32824410702",
    "sbd_seconds_last_update": "2020-02-17T12:02:54",
    "sbd_last_interest_payment": "2018-02-05T16:51:54",
    "savings_sbd_balance": "0.000 GBG",
    "savings_sbd_seconds": "0",
    "savings_sbd_seconds_last_update": "2019-12-11T16:05:15",
    "savings_sbd_last_interest_payment": "2019-12-11T16:05:15",
    "savings_withdraw_requests": 0,
    "vesting_shares": "341688.730149 GESTS",
    "delegated_vesting_shares": "0.000000 GESTS",
    "received_vesting_shares": "0.000000 GESTS",
    "vesting_withdraw_rate": "0.000000 GESTS",
    "next_vesting_withdrawal": "1969-12-31T23:59:59",
    "withdrawn": "185064241674",
    "to_withdraw": "185064241674",
    "withdraw_routes": 0,
    "benefaction_rewards": 0,
    "curation_rewards": 0,
    "delegation_rewards": 0,
    "posting_rewards": 0,
    "proxied_vsf_votes": [
      0,
      0,
      0,
      0
    ],
    "witnesses_voted_for": 0,
    "average_bandwidth": 2721294841,
    "average_market_bandwidth": 1080000000,
    "lifetime_bandwidth": "632909000000",
    "lifetime_market_bandwidth": "6119410000000",
    "last_bandwidth_update": "2020-02-18T10:58:18",
    "last_market_bandwidth_update": "2020-02-07T02:04:09",
    "last_comment": "2020-02-18T10:54:03",
    "last_post": "1970-01-01T00:00:00",
    "post_bandwidth": 0,
    "witness_votes": [],
    "reputation": 0,
    "posts_capacity": 3,
    "comments_capacity": 32112,
    "voting_capacity": 12,
    "referrer_account": "",
    "referrer_interest_rate": 0,
    "referral_end_date": "1970-01-01T00:00:00",
    "referral_break_fee": "0.000 GOLOS",
    "last_active_operation": "2020-02-17T12:02:54"
  }
]
```

* **get\_block** — возвращает информацию о блоке по его номеру;

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_block",["34940353"]]}
```

Ответ:

```javascript
{
  "previous": "021525c0c311e480cde023eea5c2ba26e0d06c82",
  "timestamp": "2020-02-19T12:09:15",
  "witness": "pzm",
  "transaction_merkle_root": "0000000000000000000000000000000000000000",
  "extensions": [],
  "witness_signature": "1f17e84a65e103c9cc476d27a29dbba4e5100ab60c79015418a5eeab0cf867b1ee7b4407b408b6d2d28fed9f08820defadb7f4ba715f4c520bb49c3fa5e5e8412a",
  "transactions": []
}
```

* **get\_chain\_properties** — возвращает медианные значения голосуемых параметров сети;

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_chain_properties",[]]}
```

Ответ:

```javascript
{
  "account_creation_fee": "1.000 GOLOS",
  "maximum_block_size": 65536,
  "sbd_interest_rate": 0,
  "create_account_min_golos_fee": "0.030 GOLOS",
  "create_account_min_delegation": "0.150 GOLOS",
  "create_account_delegation_time": 2592000,
  "min_delegation": "0.010 GOLOS",
  "max_referral_interest_rate": 1000,
  "max_referral_term_sec": 15552000,
  "min_referral_break_fee": "0.001 GOLOS",
  "max_referral_break_fee": "100.000 GOLOS",
  "posts_window": 7200,
  "posts_per_window": 2,
  "comments_window": 32767,
  "comments_per_window": 50,
  "votes_window": 15,
  "votes_per_window": 5,
  "auction_window_size": 0,
  "max_delegated_vesting_interest_rate": 8000,
  "custom_ops_bandwidth_multiplier": 10,
  "min_curation_percent": 7500,
  "max_curation_percent": 7500,
  "curation_reward_curve": "square_root",
  "allow_distribute_auction_reward": true,
  "allow_return_auction_reward_to_fund": true,
  "worker_reward_percent": 1000,
  "witness_reward_percent": 1500,
  "vesting_reward_percent": 7500,
  "worker_request_creation_fee": "100.000 GBG",
  "worker_request_approve_min_percent": 1500,
  "sbd_debt_convert_rate": 100,
  "vote_regeneration_per_day": 10,
  "witness_skipping_reset_time": 21600,
  "witness_idleness_time": 2592000,
  "account_idleness_time": 15552000
}
```

* **get\_dynamic\_global\_properties** — возвращает данные о динамических глобальных свойствах сети;

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_dynamic_global_properties",[]]}
```

Ответ:

```javascript
{
  "id": 0,
  "head_block_number": 34940424,
  "head_block_id": "021526082557e35d8f65271a46ddfec351eeb2de",
  "time": "2020-02-19T12:12:48",
  "current_witness": "blockchained",
  "total_pow": 1719078,
  "num_pow_witnesses": 172,
  "virtual_supply": "223046315.397 GOLOS",
  "current_supply": "200741691.274 GOLOS",
  "confidential_supply": "0.000 GOLOS",
  "current_sbd_supply": "7129967.558 GBG",
  "confidential_sbd_supply": "0.000 GBG",
  "total_vesting_fund_steem": "80100561.317 GOLOS",
  "total_vesting_shares": "251334390154.901765 GESTS",
  "total_reward_fund_steem": "254.756 GOLOS",
  "total_reward_shares2": "21159194891210756",
  "sbd_interest_rate": 0,
  "sbd_print_rate": 0,
  "sbd_debt_percent": 4046,
  "average_block_size": 318,
  "maximum_block_size": 65536,
  "current_aslot": 35108656,
  "recent_slots_filled": "340282366920938463463374607431768211455",
  "participation_count": 128,
  "last_irreversible_block_num": 34940409,
  "max_virtual_bandwidth": "5986734968066277376",
  "current_reserve_ratio": 20000,
  "custom_ops_bandwidth_multiplier": 10,
  "is_forced_min_price": true,
  "transit_block_num": 29585430,
  "transit_witnesses": "76766b0000000000000000000000000078746172000000000000000000000000646d696c617368000000000000000000726f706f7800000000000000000000006c657800000000000000000000000000676f6c6f73636f72650000000000000076696b00000000000000000000000000737465657073686f740000000000000073746968692d696f0000000000000000676f6c6f73696f0000000000000000006c6164797a6172756c656d0000000000797564696e612d63617400000000000063726561746f720000000000000000006b756e6100000000000000000000000064656e69732d736b7269706e696b00007072696d7573000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "worker_requests": [
    [
      "91600047785731",
      0
    ]
  ]
}
```

* **get\_escrow** — возвращает информацию о трехсторонней сделке по логину аккаунта и идентификатору сделки (id);
* **get\_expiring\_vesting\_delegations** — возвращает список возвращаемой делегированной доли (по времени истечения возврата);
* **get\_hardfork\_version** — возвращает версию текущего хардфорка;
* **get\_next\_scheduled\_hardfork** — возвращает следующий запланированный хардфорк;
* **get\_potential\_signatures** — возвращает потенциальные публичные ключи для подписи транзакции;
* **get\_recovery\_request** — возвращает данные по запросу на восстановление доступа к аккаунту;
* **get\_required\_signatures** — возвращает публичные ключи из предложенных, которые необходимы для подписи транзакции (нужно направить транзакцию без подписи и предоставить открытые ключи);
* **get\_transaction\_hex** — возвращает hex значение сырой транзакции;
* **get\_vesting\_delegations** — возвращает список делегированной доли аккаунта;
* **get\_withdraw\_routes** — возвращает массив путей понижения доли для аккаунта;
* **lookup\_account\_names** — возвращает массив аккаунтов по запрошенным логинам;
* **lookup\_accounts** — возвращает массив логинов аккаунтов по нижней границе с указанием количества возвращаемых элементов (не более 1000);
* **verify\_account\_authority** — проверяет подпись транзакции отдельным аккаунтом с указанием публичного ключа;
* **verify\_authority** — принимает подписанную транзакцию и возвращает TRUE, если транзакция подписана всеми необходимыми ключами;

## account\_by\_key

* **get\_key\_references** — возвращает массив логинов аккаунтов, которые содержат указанный публичный ключ.

Пример запроса:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["account_by_key","get_key_references",[["GLS53nbKGcMwXw8zWMNLBm5XXLTW9fqZeQT5J7dC3Qso7GwJ7F8Hb"]]]}
```

Ответ:

```
[
  [
    "xel"
  ]
]
```

## account\_history

* **get\_account\_history** — возвращает историю операций (в том числе и виртуальных), связанных с определенным аккаунтом.&#x20;

Пример запроса:

```
{"id":1,"method":"call","jsonrpc":"2.0","params":["account_history","get_account_history",["xel","-1","1"]]}
```

Ответ:

```javascript
[
  [
    84,
    {
      "trx_id": "de0c1837f59023dd183e1f6f0d338f60432af2ab",
      "block": 34910086,
      "trx_in_block": 1,
      "op_in_trx": 1,
      "virtual_op": 0,
      "timestamp": "2020-02-18T10:54:03",
      "op": [
        "comment_options",
        {
          "author": "xel",
          "permlink": "re-lex-re-on0tole-re-lex-re-on0tole-re-lex-voznagrazhdeniya-za-shering-po-socsetyam-i-otkaz-ot-flagov-20200218t105406785z",
          "max_accepted_payout": "1000000.000 GBG",
          "percent_steem_dollars": 10000,
          "allow_votes": true,
          "allow_curation_rewards": true,
          "extensions": []
        }
      ]
    }
  ],
  [
    85,
    {
      "trx_id": "b35973bbf446a37d3d64492388231f7d5531f93b",
      "block": 34910171,
      "trx_in_block": 0,
      "op_in_trx": 0,
      "virtual_op": 0,
      "timestamp": "2020-02-18T10:58:18",
      "op": [
        "delete_comment",
        {
          "author": "xel",
          "permlink": "re-lex-re-on0tole-re-lex-re-on0tole-re-lex-voznagrazhdeniya-za-shering-po-socsetyam-i-otkaz-ot-flagov-20200218t105406785z"
        }
      ]
    }
  ]
]
```

## operation\_history

* **get\_ops\_in\_block** — возвращает массив операций по номеру блока (можно указать необходимость показывать только виртуальные операции);

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["operation_history","get_ops_in_block",["31913871","false"]]}
```

Ответ:

```javascript
[
  {
    "trx_id": "0000000000000000000000000000000000000000",
    "block": 31913871,
    "trx_in_block": 65535,
    "op_in_trx": 0,
    "virtual_op": 1,
    "timestamp": "2019-11-05T23:23:18",
    "op": [
      "producer_reward",
      {
        "producer": "xanoxt",
        "vesting_shares": "488.592569 GESTS"
      }
    ]
  }
]
```

* **get\_transaction** — возвращает данные транзакции по её хэшу (id);

## witness\_api

* **get\_active\_witnesses** — возвращает массив делегатов в текущем раунде (из 21 слота, при наличии такого количества делегатов);

Пример:

```javascript
{"id":1,"method":"call","jsonrpc":"2.0","params":["witness_api","get_active_witnesses",[]]}
```

Ответ:

```javascript
[
  "blockchained",
  "litrbooh",
  "lex",
  "prizm.space",
  "aleksw",
  "pzm",
  "anyx",
  "miner-113",
  "ladyzarulem",
  "rise",
  "xanoxt",
  "on0tole",
  "primus",
  "lulz",
  "actual",
  "vvk",
  "lindsay",
  "erikkartmen",
  "arcange",
  "jackvote",
  "solox"
]
```

* **get\_witness\_by\_account** — возвращает делегата в соответствием с его логином;
* **get\_witness\_count** — возвращает количество аккаунтов, заявивших о желании быть делегатом;
* **get\_witness\_schedule** — возвращает очередь делегатов дополненную расчитанными медианными значениями параметров сети и мажориторной версией хардфорка;
* **get\_witnesses** — возвращает массив делегатов в соответствием с их id (можно запросить нескольких в массиве);
* **get\_witnesses\_by\_vote** — возвращает массив делегатов, отсортированных по потенциалу полученных голосов (указывается левая граница списка и количество возвращаемых значений в массиве, но не более 100);
* **lookup\_witness\_accounts** — возвращает массив логинов аккаунтов, которые заявляли себя как делегаты (указывается левая граница списка и количество возвращаемых значений в массиве, но не более 1000).


# Библиотеки для работы

Наличие библиотеки для конкретного языка программирования зависит от наличия заготовок для работы с криптографией, большими числами и транспортными протоколами (http/ws). Так как GOLOS исторически эволюционировал из Graphene, многие библиотеки для кодовой базы Steem нередко подходят для Golos. Отличительной особенностью является формат общения с нодой (структура json-rpc), порядок и наименование параметров при описании операции, формат сложных данных в бинарном виде.

Каждый разработчик может поднять свою ноду для взаимодействия с GOLOS, но для начинающих разбираться существуют [публичные ноды](https://wallet.golos.id/nodes).

Ниже перечислены основные библиотеки, которые поддерживают большинство API запросов к ноде и формирование транзакций.

## JavaScript

Фаворит для разработки приложений библиотека [golos-lib-js](https://github.com/golos-blockchain/libs/tree/master/golos-lib-js). В нем есть поддержка всего что нужно как для серверного (nodejs), так и для пользовательского (js в браузерах) взаимодействия с Golos:

* Создание и кодирование ключей;
* API-запросы;
* Формирование транзакций;
* Упрощенный конструктор транзакций для операций;
* Функции обратного вызова для запросов;

[Документация](https://github.com/golos-blockchain/libs/tree/master/golos-lib-js/docs) golos-lib-js доступна на GitHub. Также примеры для часто используемых операций смотрите в [разделе Примеры кода](/developers/basics/code-examples).

## Python

Библиотека <https://github.com/golos-blockchain/lib-python>, наиболее **актуальная** **на текущий момент** и поддерживает последние изменения в блокчейне (26 ХФ).\
<https://pypi.org/project/golos-lib-python/>\
\
За её основу была взята[ golos-python](https://github.com/bitfag/golos-python) от[ @vvk](https://golos.id/@vvk) (актуальна до 23 ХФ).

[Библиотека golos-python](https://github.com/Privex/golos-python) от [@someguy](https://golos.id/@someguy123)/[@ksantoprotein](https://golos.id/@ksantoprotein) поддерживает как API запросы, так и формирование транзакций. [Документация](https://golos-python.readthedocs.io/en/latest/index.html) к ней на английском языке.

## PHP

Сложность разработки поддержки на PHP в том, что нет стандартных библиотек для работы с криптографией. Поэтому необходим полный доступ к серверу, чтобы собрать secp256k1 для PHP и включить поддержку [GMP](https://ru.wikipedia.org/wiki/GNU_Multi-Precision_Library). Это накладывает определенные ограничения на разработчиков (требует опыт в администрировании).

Несмотря на это, существует [библиотека php-graphene-node-client](https://github.com/t3ran13/php-graphene-node-client/) с поддержкой GOLOS от [@t3ran13](https://golos.id/@t3ran13), установка возможна через Docker.

## GO

[Библиотека golos-lib-go](https://github.com/golos-blockchain/golos-lib-go) от [@asuleymanov](https://golos.id/@asuleymanov) также подходит для API запросов и изучения формирования транзакций.

## Другое

Если вы не нашли требуемый язык программирования, то можно обратить внимание на существующие библиотеки для Steem и EOS. Чтобы модифицировать их и получить поддержку Golos достаточно проверить формат json-rpc запросов, поменять chain\_id (в GOLOS он равен `782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12` — это префикс для подписи сырых транзакций) и настроить конструктор операций.

* [C# Ditch](https://github.com/Chainers/Ditch) — быстрая и простая библиотека на C# использующая .NET стандарта 2.0;
* [Elixir API wrapper](https://github.com/metachaos-systems/steemex) — библиотека на Elixir для API-запросов;
* [Swift Steem](https://github.com/steemit/swift-steem) — библиотека на Swift.


# Примеры кода

Начинающим разработчикам всегда рекомендуется прочесть документации по той или иной библиотеке. Это помогает как понять работу библиотеки, так и запомнить возможности, которые можно использовать при разработке приложений. В данном разделе описаны наиболее популярные запросы в виде примеров.&#x20;

Наиболее используемая библиотека для приложений Golos — [golos-lib-js](https://github.com/golos-blockchain/libs/tree/master/golos-lib-js), поэтому примеры с её использованием. Подробная документация на английском с указанием всех методов и их атрибутов [доступно по ссылке](https://github.com/golos-blockchain/libs/tree/master/golos-lib-js/docs).

### Подключение библиотеки

В зависимости от серверного (nodejs) или браузерного (js) использования библиотеку нужно подключать разными способами.

Для nodejs актуальной инструкцией будет установка библиотеки через \
`npm install golos-lib-js --save` \
и подключением её в js файле через\
`var golos = require('golos-lib-js');`

Для js подключения можно либо самому собрать webpack библиотеки через консоль `npm build`, либо воспользоваться уже собранной библиотекой от [jsDelivr CND](https://cdn.jsdelivr.net/npm/golos-lib-js@latest/dist/golos.min.js) или [Unpkg CDN](https://unpkg.com/golos-lib-js@latest/dist/golos.min.js). Просто добавьте к файлу script и укажите url библиотеки: `<script type="text/javascript" src="https://unpkg.com/golos-lib-js@latest/dist/golos.min.js"></script>`, после чего у вас будет доступ через консоль к глобальной переменной `golos`.

### Использование публичной ноды

Пока у вашего приложения нет большого потока пользователей, для работы с блокчейном можно использовать и публичные API-ноды от делегатов, их список доступен [здесь](https://wallet.golos.id/nodes).

В нём указаны адреса для JSON-RPC запросов через WebSocket over SSL, **для запросов через HTTPS** просто замените `wss` на `https`и уберите `ws` в конце.

Пример настройки для работы с нодой через HTTPS:

```javascript
var api_gate='https://golos.lexai.host';
golos.config.set('websocket',api_gate);
```

### API-запросы

В разделе [Плагины и их API](/developers/basics/plugins-api) были перечислены основные плагины и запросы к ним — все они доступны в библиотеке. Для того, чтобы выполнить тот или иной запрос, достаточно перевести его название в [CamelCase](https://ru.wikipedia.org/wiki/CamelCase).

Например, если вы решили выполнить запрос get\_database\_info к плагину database\_api, то вам необходимо выполнить код:

```javascript
golos.api.getDatabaseInfo(function(err,response){
    if(!err){
        //получен ответ
        console.log(response);
    }
    else{
        //ошибка
        console.log(err);
    }
});
```

В случае, если запрос требует входных данных, то вы добавляете их в начало вызова.

### Транслирование транзакций (broadcast)

Для каждой операции из протокола Golos существует отдельный метод в библиотеке golos-lib-js, который принимает приватный ключ (для подписи транзакции) и параметры операции. Название операции, аналогично API методам, должно быть переведено в [формат CamelCase](https://ru.wikipedia.org/wiki/CamelCase). Пример кода для трансляции (broadcast) операции `account_metadata` (запись в блокчейн мета-данных аккаунта):

```javascript
var posting_key='5K...';//приватный ключ
var user_login='test';//логин аккаунта
var metadata={'name':'Тестовый аккаунт','photo':'https://cdn.pixabay.com/photo.jpg'};
golos.broadcast.accountMetadata(posting_key,user_login,JSON.stringify(metadata),function(err,result){
    if(!err){
        //транзакция принята публичной нодой
        console.log(result);
    }
    else{
        //нода не приняла транзакцию
        console.log(err);
    }
});
```

### Динамические глобальные свойства сети

Часть новичков хотят периодически опрашивать ноду и получать актуальные данные о DGP (Dynamic Global Properties), чтобы на основе этого показывать новые блоки, исполнять условия по необратимому блоку или подсвечивать в списке делегатов последнего, кто подписал блок. Для этого достаточно запрашивать данные по таймеру каждые 3 секунды (время между блоками):

```javascript
var dgp={}
function update_dgp(auto=false){
    golos.api.getDynamicGlobalProperties(function(err,response){
        if(!err){
            dgp=response;
        }
    });
    if(auto){
        setTimeout("update_dgp(true)",3000);
    }
}
update_dgp(true);
```

### Работа с ключами

Криптографические ключи представляют собой координаты X и Y которые записаны в общепринятом формате DER на эллептической кривой secp256k1 (в качестве хеш-функции служит SHA-256). В библиотеке golos-lib-js преобразования и работа с ключами относятся к модулю `golos.auth`.

В Graphene экосистеме придумали механизм человекочитаемых паролей. По причинам перебора использовать их не рекомендуется, поэтому, чтобы усложнить множественный перебор приватных ключей к публичному пришли к определенным правилам формирования ключей в виде конкатенации строк: логин аккаунта, пароль (сложный), тип доступа.

Часть приложений условились использовать эти правила, таким образом упрощая доступ пользователем к разным возможностям аккаунта по общему паролю. Например, пользователь test зарегистрирован используя общий пароль PK3452JENDK332. При авторизации в приложении используя эти логин и пароль, приложение может самостоятельно сформировать ключи нужного типа доступа, просто используя конкатенацию строк. Пользователь хочет перевести токены? Приложение формирует налету приватный активный ключ по строке testPK3452JENDK332active. Пользователь награждает кого-то? Приложение формирует приватный постинг ключ по строке testPK3452JENDK332posting. Это упрощает доступ для пользователя по общему паролю, но лишает гибкости и подвергает опасности аккаунт. Типы доступа имеют разные полномочия и при компрометации доверенного окружения доверенного окружения пользователя или сайта доступ к аккаунту может быть перехвачен.

### Регистрация аккаунта

Обычно, при регистрации пользователя, приложение генерирует пароль самостоятельно. Но бывает исключения, когда приложение позволяет использовать свой пароль для генерации ключей. Библиотека позволяет самостоятельно указать строки для генерации ключа в методе `golos.auth.toWif(account_login,general_pass,auth_type);`. В примере ниже представлена функция для генерации случайного пароля заданной длины и генерации ключа по нему без привязки к пользователю и типу доступа:

```javascript
function pass_gen(length=100,to_wif=true){
    let charset='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=_:;.,@!^&*$';
    let ret='';
    for (var i=0,n=charset.length;i<length;++i){
        ret+=charset.charAt(Math.floor(Math.random()*n));
    }
    if(!to_wif){
        return ret;
    }
    let wif=golos.auth.toWif('',ret,'');
    return wif;
}
```

Получить публичный ключ по заданному приватному можно методом `golos.auth.wifToPublic(wif)`. Для тех приложений, которые хотят формировать ключи по кокатенации логина, пароля и типа доступа, существует метод `golos.auth.getPrivateKeys(account_login,general_pass,auth_types);`. Метод возвращает массив по шаблону result.*type* для приватных ключей (которые нужно передать пользователю) и result.\_type\_Pubkey для публичных ключей (которые нужно транслировать в блокчейн для сохранения за аккаунтом пользователя).

### Конвертация токенов GOLOS в долю сети

Для автоматической конвертации всех доступных токенов GOLOS в долю сети VESTS необходимо запросить информацию об аккаунте и конвертировать их себе же в долю операцией transfer\_to\_vesting:

```javascript
var current_user='test';
var active_key='5K...';//приватный активный ключ
golos.api.getAccounts([current_user],function(err,response){
    if(!err){
        //получен ответ
        if(typeof response[0] !== 'undefined'){
            if('0.000 GOLOS'!=response[0].balance){
                golos.broadcast.transferToVesting(active_key,current_user,current_user,response[0].balance,function(err,result){
                    if(!err){
                        console.log('конвертация в долю сети',response[0].balance);
                        console.log(result);
                    }
                    else{
                        console.log(err);
                    }
                });
            }
            else{
                console.log('баланс на нуле');
            }
        }
        else{
            console.log('аккаунт не найден',current_user);
        }
    }
    else{
        //ошибка
        console.log(err);
    }
});
```

### Перевод токенов

Пример перевода 1.000 GOLOS из баланса аккаунта в фонд воркеров:

```javascript
var current_user='test';
var active_key='5K...';//приватный активный ключ
var target='workers';
var fixed_amount='1.000 GOLOS';
var memo='Заметка';//utf-8 включая emoji
golos.broadcast.transfer(active_key,current_user,target,fixed_amount,memo,function(err,result){
    if(!err){
        //получен ответ
        console.log(result);
    }
    else{
        //ошибка
        console.log(err);
    }
});
```

### Смена ключей аккаунта

Бывает, что есть необходимость сменить доступы у аккаунта. Это может быть по причине добавления нового ключа, делегирование управления или создание условий для мульти-подписного управления аккаунтом (когда для выполнения операций требуется подпись несколькими ключами).

Полномочия для выполнения операций имеют следующую структуру:

* *weight\_threshold* — необходимый вес для одобрения транзакции с операциями нужного типа;
* *account\_auths* — массив аккаунтов и их весов. Аккаунты могут добавить вес транзакции при добавлении к ней подписи ключом;
* *key\_auths* — массив публичных ключей и их весов.

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

Пример полномочий с одним ключом:

```javascript
{
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
        ["GLS6LWhhUzKmYM5VcxtC2FpEjzr71imfb7DeGA9yodeqnvtP2SYjA", 1]
    ]
}
```

Если у аккаунта будет записаны эти полномочия в тип доступа posting, то для совершения операции награждения блокчейн будет требовать подпись транзакции ключом `5KRLZitDd5c9uZzDgTMF4se4eVewENtZ29GbCuKwbT3msRbtLgi` (которому соответствует указанный в полномочиях публичный ключ `GLS6LWhhUzKmYM5VcxtC2FpEjzr71imfb7DeGA9yodeqnvtP2SYjA`).

При делегировании управления другому аккаунту, например `test`, необходимо изменить полномочия на:

```javascript
{
    "weight_threshold": 1,
    "account_auths": [
        ["test", 1]
    ],
    "key_auths": [
        ["GLS6LWhhUzKmYM5VcxtC2FpEjzr71imfb7DeGA9yodeqnvtP2SYjA", 1]
    ]
}
```

После этого блокчейн будет требовать подпись либо указанным ключом, либо ключом аналогичного типа доступа аккаунта `test`.

Мульти-подписное управление предполагает усложнение полномочий, например для управления 2 из 3 можно использовать полномочие:

```javascript
{
    "weight_threshold": 4,
    "account_auths": [],
    "key_auths": [
        ["GLS6LWhhUzKmYM5VcxtC2FpEjzr71imfb7DeGA9yodeqnvtP2SYjA", 2],
        ["GLS5mK1zLnYHy7PbnsxRpS4NbKjEoH2J9eBmgSjVKJ5BKQpLLj9T4", 2],
        ["GLS4uiqeDPsoteSFVbTWPBUbmfzxYkJyXYmA6B1pAFWZ59n4iBuUK", 2]
    ]
}
```

Для того чтобы транзакция была принята блокчейном, необходимо добавить подписи как минимум 2 из 3 указанных ключей. В этом примере публичному ключу `GLS4uiqeDPsoteSFVbTWPBUbmfzxYkJyXYmA6B1pAFWZ59n4iBuUK` соответствует приватный ключ `5KMBKopgd56MZvV8FYhp5AP7AWFyLKiybqRnZYgjXukw34VRE78`.

### Передача права голосования прокси (proxy)

Если пользователь не принимает участие в выборе делегатов, он может делегировать право распоряжаться его долей другому аккаунту. Для этого существует операция `account_witness_proxy`, ей может воспользоваться приложение регистратор, чтобы не загружать своего пользователя лишней информацией об устройстве блокчейн-системы.

Если пользователь решит самостоятельно участвовать в выборе делегатов, то первый же голос за делегата отменит прокси.

```javascript
var account_login='test';
var active_key='5K...';
var proxy_login='proxy';
golos.broadcast.accountWitnessProxy(active_key,account_login,proxy_login,function(err,result){
    if(!err){
        console.log(result);
    }
    else{
        console.log(err);
    }
});
```

### Custom операции

Когда разработчикам нужно ввести свою структуру в блокчейн, сделать децентрализированное приложение (dApp), которое будет мониторить блоки и учитывать операции в сети — они могут использовать custom операции. Custom операция имеет гибкую структуру:

Разработчики могут сами придумать структуры данных, протокол команд и их учет через custom операции.

### Трехсторонние Escrow сделки

Трехсторонние сделки работают по принципу проверки выполнения условий гарантом (`agent`). Получатель и гарант должны подтвердить начало сделки операцией `escrow_approve` (гарант получает комиссию на этом этапе), иначе при достижении даты дедлайна ратификации (`ratification_deadline`) происходит возврат всех токенов инициатору сделки.

Если наступает момент спора, то отправитель или получатель могут инициировать разбирательство операцией `escrow_dispute`, после чего принятие решения по сделке передается гаранту (именно он решает кто и сколько токенов получит). Если сделка повисла и долгое время не разрешается — договор истекает (`escrow_expiration`) и всеми токенами управляет либо агент (если был открыт диспут), либо любая из сторон сделки.

Создание escrow перевода:

```javascript
var account_login='test';
var active_key='5K...';
var receiver_login='receiver';
var token_amount='100.000 GOLOS';//количество передаваемых токенов
var escrow_id=1;//номер escrow назначается вручную для согласования заявки (uint32)
var agent_login='agent';
var fee='10.000 GOLOS';//комиссия гаранта
var json_metadata='{}';//дополнительные мета-данные в формате json
var ratification_deadline=new Date().toISOString().substr(0,19);//дата принудительной окончания сделки и возврата средств если гарант и получатель не подтвердили участие в сделке (дедлайн в формате ISO вида 2019-10-17T13:30:18)
var escrow_expiration=new Date().toISOString().substr(0,19);//дата окончания принятия решения по сделке, после чего невозможно инициировать спор (дедлайн в формате ISO вида 2019-10-17T13:30:18)
golos.broadcast.escrowTransfer(active_key,account_login,receiver_login,token_amount,escrow_id,agent_login,fee,json_metadata,ratification_deadline,escrow_expiration,function(err,result){
    if(!err){
        console.log(result);
    }
    else{
        console.log(err);
    }
});
```

Подтверждение участие в сделке по предложенным условиям (свое участие должны подтвердить гарант и получатель операцией `escrow_approve`):

```javascript
var account_login='test';
var receiver_login='receiver';
var agent_login='agent';
var escrow_id=1;//номер escrow назначается вручную для согласования заявки (uint32)

var who=agent_login;//кто подтверждает свое участие
var active_key='5K...';//ключ подтверждающий стороны (who)

var approve=true;//false в случае отказа от участия в сделке
golos.broadcast.escrowApprove(active_key,account_login,receiver_login,agent_login,who,escrow_id,approve,function(err,result){
    if(!err){
        console.log(result);
    }
    else{
        console.log(err);
    }
});
```

Требование диспута (открыть спор по сделке может отправитель или получатель операцией `escrow_dispute`):

```javascript
var account_login='test';
var receiver_login='receiver';
var agent_login='agent';
var escrow_id=1;//номер escrow назначается вручную для согласования заявки (uint32)


var who=receiver_login;//кто подтверждает свое участие
var active_key='5K...';//ключ подтверждающий стороны (who)

golos.broadcast.escrowDispute(active_key,account_login,receiver_login,agent_login,who,escrow_id,function(err,result){
    if(!err){
        console.log(result);
    }
    else{
        console.log(err);
    }
});
```

Отпустить средства (операция `escrow_release`):

```javascript
var account_login='test';
var receiver_login='receiver';
var agent_login='agent';
var escrow_id=1;//номер escrow назначается вручную для согласования заявки (uint32)
var token_amount='100.000 VIZ';//количество передаваемых токенов

var who=receiver_login;//кто решил отпустить средства (если открыт диспут, то только гарант решает кому и сколько перевести)
var active_key='5K...';//ключ инициатора операции (who)
var receiver=account_login;//получателем средств может быть только другая сторона сделки до истечения срока сделки, иначе — любая из сторон сделки

golos.broadcast.escrowRelease(active_key,account_login,receiver_login,agent_login,who,receiver,escrow_id,token_amount,function(err,result){
    if(!err){
        console.log(result);
    }
    else{
        console.log(err);
    }
});
```

Чтобы получить информацию об escrow, необходимо вызвать API запрос `get_escrow` плагина `database_api`:

```javascript
var account_login='test';
var escrow_id=1;
golos.api.getEscrow(account_login,escrow_id,function(err,response){
    if(!err){
        //получен ответ
        console.log(response);
    }
    else{
        //ошибка
        console.log(err);
    }
});
```

### Система предложенных операций (proposal)

Для управления системой предложенных операций существует 3 операции: создания предложения, предоставление подписи (обновление), удаление предложения. После создания предложения блокчейн система будет ожидать все необходимые подписи для осуществления операций заложенных внутрь предложения, после чего выполнит их. Если подошел срок истечения, то предложение не будет выполнено. Системой предложенных операций пользуются для управления мультиподписными аккаунтами. Для создания предложения используйте операцию `proposal_create`:

```javascript
var account_login='test';
var active_key='5K...';//активный приватный ключ
var title='payments-14';//наименование предложения (играет роль идентификатора, должно быть уникальным)
var memo='Платежи по договору №14';

var expiration_date=new Date();//дата экспирации, когда предложенные операции будут отклонены или выполнены при получении всех необходимых подписей
expiration_date.setDate(expiration_date.getDate() + 10);//плюс десять дней от текущего момента
var expiration_time=expiration_date.toISOString().substr(0,19);//дата истечения предложения в формате ISO
console.log('expiration_time',expiration_time);

var proposed_operations=[];
proposed_operations.push({'op':['transfer',{'from':'escrow','to':'test','amount':'10.000 GOLOS','memo':memo}]});
proposed_operations.push({'op':['transfer',{'from':'escrow2','to':'test','amount':'10.000 GOLOS','memo':memo}]});

var review_period_date=new Date(expiration_date.getTime() - 10);//дата прекращения приема подписей (минус 10 секунд до даты экспирации)
var review_period_time=review_period_date.toISOString().substr(0,19);//дата истечения предложения в формате ISO
console.log('review_period_time',review_period_time);

var extensions=[];

golos.broadcast.proposalCreate(active_key,account_login,title,memo,expiration_time,proposed_operations,review_period_time,extensions,function(err,result){
    console.log(err,result);
});
```

Чтобы получить информацию о предложениях сделанных пользователем, нужно выполнить API запрос `get_proposed_transactions` к плагину `database_api` (будет возвращен массив предложений):

```javascript
var looking_account='test';
var from=0;
var limit=100;
golos.api.getProposedTransactions(looking_account,from,limit,function(err,response){
    console.log(err,response);
});
```

Система предложений поддерживает все существующие операции в блокчейне, но не позволяет смешивать операции требующие разных полномочий (например, операции `tranfer`, требующие active полномочия, и операции `upvote`, требующие posting полномочия). Предоставить подпись нужного типа доступа можно операцией `proposal_update` указав логин подписавшего транзакцию в массиве на добавление или удаления из списка подтвердивших предложение (для этого есть 4 типа массивов: active, owner, posting и key для использования одиночных ключей). Как только предоставлены все необходимые подписи — операции из предложения будут исполнены (при условии, что не указан период `review_period_time`), в случае ошибки выполнения повторная попытка будет предпринята при экспирации. Пример:

```javascript
var account_login='escrow';
var active_key='5K...';//активный приватный ключ

var proposal_author='test';//автор предложения
var proposal_title='payments-14';//идентификатор предложения

var active_approvals_to_add=[];//список аккаунтов подписавших данную транзакцию активным типом доступа для подтверждения предложения
var active_approvals_to_remove=[];//список аккаунтов для удаления из списка подтвердивших предложение
var owner_approvals_to_add=[];
var owner_approvals_to_remove=[];
var posting_approvals_to_add=[];
var posting_approvals_to_remove=[];
var key_approvals_to_add=[];
var key_approvals_to_remove=[];
var extensions=[];

active_approvals_to_add.push(account_login);

golos.broadcast.proposalUpdate(active_key,proposal_author,proposal_title,active_approvals_to_add,active_approvals_to_remove,master_approvals_to_add,master_approvals_to_remove,regular_approvals_to_add,regular_approvals_to_remove,key_approvals_to_add,key_approvals_to_remove,extensions,function(err,result){
    console.log(err,result);
});
```

Предложение может удалить заявитель или любой участник, чья подпись требуется. Для этого достаточно выполнить операцию `proposal_delete` подписав её активным ключом:

```javascript
var account_login='escrow2';//участник предложения
var active_key='5K...';//активный приватный ключ

var proposal_author='test';//автор предложения
var proposal_title='payments-14';//идентификатор предложения

var extensions=[];

golos.broadcast.proposalDelete(active_key,proposal_author,proposal_title,account_login,extensions,function(err,result){
        console.log(err,result);
});
```

## js запросы к публичной ноде без библиотеки

Если вашему приложению не требуется криптография и подпись транзакций, то вы можете использовать нативные средства для json-rpc запросов через js.

Пример для WebSocket соединения:

```javascript
var api_gate='wss://golos.lexai.host/ws';
var latency_start=new Date().getTime();
var latency=-1;
var socket = new WebSocket(api_gate);
socket.onmessage=function(event){
    latency=new Date().getTime() - latency_start;
    let json=JSON.parse(event.data);
    if(json.result){
        console.log(json.result);
    }
    else{
        console.log(json.error);
    }
    socket.close();
}
socket.onopen=function(){
    socket.send('{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_dynamic_global_properties",[]]}');
};
```

Пример для HTTP соединения:

```javascript
var api_gate='https://golos.lexai.host';
var latency_start=new Date().getTime();
var latency=-1;
var xhr = new XMLHttpRequest();
xhr.overrideMimeType('text/plain');
xhr.open('POST',api_gate);
xhr.setRequestHeader('accept','application/json, text/plain, */*');
xhr.setRequestHeader('content-type','application/json');
xhr.onreadystatechange=function(){
    if(4==xhr.readyState && 200==xhr.status){
        latency=new Date().getTime() - latency_start;
        console.log(xhr);
        let json=JSON.parse(xhr.response);
        if(json.result){
            console.log(json.result);
        }
        else{
            console.log(json.error);
        }
    }
}
xhr.send('{"id":1,"method":"call","jsonrpc":"2.0","params":["database_api","get_dynamic_global_properties",[]]}');
```


# Формирование транзакций

Есть правила формирования транзакций, заложенные в протокол Golos. Данные, подписываемые криптографическим ключом, должны соответствовать всем структурам и правилам бинарного представления, заложенным в код. В данном разделе вы узнаете как кодируются ключи, как происходит бинарное представление данных или их подготовка.

## Структура транзакции для подписи

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

* **chain\_id** — идентификатор цепи, в Golos это fc::sha256::hash от строки `GOLOS`: `782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12`. Стоит отметить, что fc::sha256::hash преобразует строку в c\_str, добавляя в начало ее hex значения `56495A` длину строки, в итоге sha256 рассчитывается от hex значения `0356495A`;
* **tapos\_link** — [Transactions as Proof of Stake концепция](/developers/basics/state) заключается в том, чтобы каждая транзакция ссылалась на конкретный блок, который должен быть в цепи для ее работы. Бинарное представление является отображением параметров транзакции ref\_block\_num и ref\_block\_prefix.
* **expiration** — unixtime экспирации транзакции (она должна быть включена в цепь до времени экспирации);
* **operations** — массив операций находящихся в транзакции, бинарное представление каждой операции состоит из всех аттрибутов операции согласно протоколу;
* **extensions** — массив служебных расширений транзакции (не используется, поэтому в бинарном формате представляет собой hex значение массива без элементов: `00`);

## Зачем необходим chain\_id

Открытый и свободный код блокчейн систем основанных на Graphene позволяют запускать новые цепочки, как без изменений, так и полностью переработанные с собственными механиками и экономикой. Более того, множество проектов запускают публичные тестовые цепочки для проверки изменений. Чтобы ноды не путались и транзакции из одной сети нельзя было применять в форке (или цепи с аналогичными аккаунтами и ключами) — существует идентификатор цепи, который присутствует как метка в каждой транзакции и операции подписи.

## Формат ключей

Приватные и публичные ключи в Golos находятся по [алгоритму ESDCA](https://ru.wikipedia.org/wiki/ECDSA) ([теория](https://habr.com/ru/post/188958/)), и используют криптографию для проверки подписей набора данных. Многие разработчики не являясь специалистами в криптографии просто используют специализированные библиотеки, не вдаваясь в подробности.

Рассмотрим этапность преобразования приватного ключа (состоящего из 32 байт) в читаемый WIF формат:

* Ключу добавляем бинарный префикс в hex представлении `80`;
* Вычисляем sha256 хэш от sha256 хэша бинарного представления ключа для контрольной суммы (checksum);
* Добавляем в конец ключа первые 8 байт от контрольной суммы;
* Кодируем полученный бинарный результат через base58 алгоритм с использованием алфавита: `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`;

Этапность преобразование публичного ключа (состоящего из 32 байт) в читаемый формат:

* Получаем контрольную сумму хэшированием бинарного представления ключа [алгоритмом ripemd160](https://ru.wikipedia.org/wiki/RIPEMD-160);
* Добавляем в конец ключа первые 8 байт от контрольной суммы;
* Кодируем полученный бинарный результат через base58 алгоритм с использованием алфавита: `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`;
* Добавляем префикс сети (строковое значение `GOLOS`);

В библиотеке golos-lib-js используется модуль `auth` ([ссылка на GitHub](https://github.com/golos-blockchain/golos-lib-js/blob/master/src/auth/index.js)), который позволяет предустановленными методами работать с ключами и подписывать данные.

## Представление разных типов данных в бинарном виде

* **string** — строковое значение в бинарном виде представляет собой байт содержащий длину строки и саму строку (например, строковое значение логина аккаунта `escrow` будет соответствовать hex значению `06657363726f77` в бинарном представлении);
* **integer** — числовое значение переворачивается в бинарном представлении и пустая размерность заполняется нулями (если задан тип значения). Например, процент апвоута указываемый в операции `upvote` представляет собой uint16\_t, для передачи которого достаточно 2 байта. Если необходимо передать значением 10.00%, то в целочисленном значении это будет 1000, в hex представлении `03EB`, перевернутое значение которого будет `EB03`.&#x20;
* **date** — поля дат из JSON представления записаны в ISO формате (например, `2019-02-07T06:19:23` в часовом поясе UTC+0, он же GMT). Для их бинарного значения записывается в десятичном формате unixtime по правилам представления **integer**. Пример `2019-02-07T06:19:23` в unixtime будет `1549520363` (hex значение `5C5BCDEB`), который в бинарном значении будет представлять собой hex: `EBCD5B5C`.
* **asset** — бинарное значение токенов GOLOS представляет собой последовательность значений: целочисленный integer размерностью 8 байт без точности (0.012 будет представлять собой 12, 1.002 будет представлять собой 1002). Например: `1.002 GOLOS` в JSON значении внутри операции будет иметь бинарное представление в hex: `EA030000000000000356495A`.
* **public\_key** — значение публичного ключа в бинарном представлении содержит 33 байта, первый байт — значение для восстанавления публичного ключа ([recovery id в ECDSA](https://crypto.stackexchange.com/questions/18105/how-does-recovering-the-public-key-from-an-ecdsa-signature-work)), 16 байт — координаты точки публичного ключа по оси X, последние 16 байт по оси Y. Например, бинарное значение `026a1dbaacb805f145f9276025627102152840bb1aa09b7fac580f892d93b572b4` соответствует приватному ключу с recovery\_id равным `02` и точке с координатами X в hex представлении `6a1dbaacb805f145f927602562710215` и Y в hex представлении `2840bb1aa09b7fac580f892d93b572b4`. Что соответствует публичному ключу `GLS5hDwvV1PPUTmehSmZecaxo1ameBpCMNVmYHKK2bL1ppLGRvh85`.
* **operation\_type** — тип операции представляет собой целочисленное значение номера операции по протоколу GOLOS записанное в 1 байт (подробнее читайте в разделе [Операции и их типы](/developers/basics/operations)). Например, операция `transfer` в бинарном виде будет иметь запись в hex `02`.

## Пример структуры транзакции

Разберем пример транзакции в формате JSON и её представление в бинарном виде:

```javascript
{"ref_block_num":9023,"ref_block_prefix":1971875185,"expiration":"2019-02-07T06:19:23","operations":[["transfer",{"from":"test1","to":"test2","amount":"1.002 GOLOS","memo":"<3"}]],"extensions":[]}
```

* **ref\_block\_num** — ссылка на номер блока после побитового «и» с hex `ffff` (например, число 9023 в hex представлении `233F`, согласно представлению integer должно быть перевернуто, получаем `3F23`);
* **ref\_block\_prefix** — 4 байта (5, 6, 7, 8) от бинарного состояния идентификатора блока в десятичном формате, которое можно получить API запросом `get_block_header` с номером следующего блока (9024) к плагину database\_api. Ответ будет содержать поле `previous` с идентификатором `0000233F716D887523BB63AD3E6107C96EDCFD8A` искомого блока. Берем `716D8875` для бинарного представления, переворачиваем байты — `75886D71` и переводим в десятичный формат для JSON: `1971875185`.
* **expiration** — unixtime экспирации транзакции. `2019-02-07T06:19:23` в unixtime будет `1549520363` (hex значение `5C5BCDEB`), который в бинарном значении будет перевернут и представлять собой hex: `EBCD5B5C`.
* **operations** — массив операций (так как в массиве один элемент, hex: `01`);
  * **transfer** — операция перевода токенов (по нумерации операции в протоколе hex: `02`);
    * **from** — логин аккаунта отправителя (длина строки `test1` и hex представление: `057465737431`);
    * **to** — логин аккаунта получателя (длина строки `test2` и hex представление: `057465737432`);
    * **amount** — передаваемое количество токенов GOLOS (`1.002 GOLOS` в hex: `EA030000000000000356495A00000000`);
    * **memo** — заметка для получателя (длина строки `<3` и hex представление: `023C33`);
* **extensions** — массив служебных расширений транзакции (так как не используется и не имеет элементов, то имеет представление `00`).

Итоговое бинарное представление данных транзакции в hex: `3F23716D8875EBCD5B5C0102057465737431057465737432EA030000000000000356495A00000000023C3300`;

Чтобы отправить транзакцию в блокчейн, необходимо дополнить данное представление **chain\_id** в начале и подписать приватным ключом. Полученную подпись необходимо добавить в JSON поле массив `signatures`, например:

```javascript
{"ref_block_num":9023,"ref_block_prefix":1971875185,"expiration":"2019-02-07T06:19:23","operations":[["transfer",{"from":"test1","to":"test2","amount":"1.002 GOLOS","memo":"<3"}]],"extensions":[],"signatures":["1f500f2a5d721e45c53e76fca786d690c7c0556f1923aa07c944e26614b50481d353e88f82e731be74c18e3fb8d117dc992a475991974b6e1364a66f5ccb618f83"]}
```

И передать этот JSON через API запрос `broadcast_transaction` плагину `network_broadcast_api`.

## Получение ref\_block\_num и ref\_block\_prefix для формирования транзакции

Нода блокчейна хранит идентификаторы последних 65537 блоков (подробнее читайте [про концепцию TaPoS](/developers/basics/state)). Обычно разработчики ссылаются на один из последних блоков, обычно, выполняя очередь действий:

* Получают данные о состоянии системы через API запрос `get_dynamic_global_properties` к плагину `database_api`;
* Используя значение поля `head_block_number` минус 3 блока устанавливают для какого блока будут формировать ref\_block\_num и запрашивать его идентификатор;
* Получают идентификатор используемого блока, выполняя API запрос `get_block_header` к плагину `database_api`, запрашивая искомый блок плюс один блок (так как заголовок каждого блока содержит ссылку на идентификатор прошлого блока, искомый идентификатор находится в следующем);
* Из идентификатора формируют ref\_block\_prefix.

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

Пример получения `ref_block_num` и `ref_block_prefix` на PHP в [исходном коде библиотеки php-graphene-node-client](https://github.com/t3ran13/php-graphene-node-client/blob/d3521ad5ae8866771adb0cb5ffd4ccadf6c892dc/Tools/Transaction.php#L64).

## Порядок сериализации данных в операции

Все операции и их параметры записаны в протоколе GOLOS и находятся [в файле steem\_operations.hpp](https://github.com/golos-blockchain/golos/blob/master/libraries/protocol/include/golos/protocol/steem_operations.hpp).

Именно там можно изучить типы параметров и их требуемый порядок в операции. **Внимание!** Порядок параметров в структуре операции не совпадает с порядком параметров в самой операции. Рассмотрим пример на операции `escrow_transfer_operation`, структура операции (часто перед операцией присутствует комментарий её описывающий):

```cpp
/**
 *  The purpose of this operation is to enable someone to send money contingently to
 *  another individual. The funds leave the *from* account and go into a temporary balance
 *  where they are held until *from* releases it to *to* or *to* refunds it to *from*.
 *
 *  In the event of a dispute the *agent* can divide the funds between the to/from account.
 *  Disputes can be raised any time before or on the dispute deadline time, after the escrow
 *  has been approved by all parties.
 *
 *  This operation only creates a proposed escrow transfer. Both the *agent* and *to* must
 *  agree to the terms of the arrangement by approving the escrow.
 *
 *  The escrow agent is paid the fee on approval of all parties. It is up to the escrow agent
 *  to determine the fee.
 *
 *  Escrow transactions are uniquely identified by 'from' and 'escrow_id', the 'escrow_id' is defined
 *  by the sender.
 */
struct escrow_transfer_operation : public base_operation {
    account_name_type from;
    account_name_type to;
    account_name_type agent;
    uint32_t escrow_id = 30;

    asset token_amount = asset(0, TOKEN_SYMBOL);
    asset fee;

    time_point_sec ratification_deadline;
    time_point_sec escrow_expiration;

    string json_metadata;

    void validate() const;

    void get_required_active_authorities(flat_set<account_name_type> &a) const {
        a.insert(from);
    }
};
```

Порядок параметров в операции задается уже в конце файла методом:

```cpp
FC_REFLECT((graphene::protocol::escrow_transfer_operation), (from)(to)(token_amount)(escrow_id)(agent)(fee)(json_metadata)(ratification_deadline)(escrow_expiration));
```

Кроме описания структуры операции есть еще обработка параметров в методе `validate`, найти который можно [в файле steem\_operations.cpp](https://github.com/golos-blockchain/golos/blob/master/libraries/protocol/steem_operations.cpp#L588):

```cpp
void escrow_transfer_operation::validate() const {
    validate_account_name(from);
    validate_account_name(to);
    validate_account_name(agent);
    FC_ASSERT(fee.amount >= 0, "fee cannot be negative");
    FC_ASSERT(token_amount.amount >=
              0, "tokens amount cannot be negative");
    FC_ASSERT(from != agent &&
              to != agent, "agent must be a third party");
    FC_ASSERT(fee.symbol == TOKEN_SYMBOL, "fee must be TOKEN_SYMBOL");
    FC_ASSERT(token_amount.symbol ==
              TOKEN_SYMBOL, "amount must be TOKEN_SYMBOL");
    FC_ASSERT(ratification_deadline <
              escrow_expiration, "ratification deadline must be before escrow expiration");
    validate_json_metadata(json_metadata);
}
```

Большинство операций проверяют наличие подписи соответствующих полномочий, например в структуре `escrow_transfer_operation` присутствует проверка подписи инициатора операции (поле `from`) активных полномочий в методе `get_required_active_authorities`.


# Пропускная способность

Блокчейн Голос является системой с нулевыми комиссиями за транзакции. Однако, объём информации, который можно записать в блокчейн в единицу времени, не бесконечен. Для контроля над расходованием общей пропускной способности был разработан специальный механизм её распределения.

## Пропускная способность аккаунта

Максимально доступная bandwidth аккаунта в системе напрямую зависит от количества Силы Голоса (vesting shares).

У аккаунта в системе существует 3 ограничителя пропускной способности:

1. forum bandwidth: ограничивает объём операций постинга постов и комментариев, апвоутов.
2. market bandwidth: ограничивает объём операций трансфера монет и выставления/отмены рыночных ордеров на внутренней бирже.
3. post bandwidth: штрафует аккаунт уменьшением выплаты за пост, если аккаунт постит слишком много постов.

## forum и market bandwidth

При превышении данного типа bandwidth возникает ошибка: *Account exceeded maximum allowed bandwidth per vesting share.*

Данные типы bandwidth по сути являются единой сущностью. Отличие в том, что market bandwidth представляет собой 1/10 от общей bandwidth аккаунта. Например, пусть bandwidth аккаунта - 100 KB. Тогда:

* forum bandwidth: 100 KB
* market bandwidth: 10 KB

Время восстановления bandwidth от 0 до 100% определяется константой `STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS` и составляет 7 дней (актуально для 0.17.0).

### Механизм вычисления bandwidth

В исходных текстах происходит в database.cpp в `bool database::update_account_bandwidth`.

При получении транзакции аккаунта нода golosd проверяет, не превысил ли аккаунт отведённую ему полосу пропускания. Это происходит по следующей формуле:

`has_bandwidth = (account_vshares * max_virtual_bandwidth) > (account_average_bandwidth * total_vshares)`

* `has_bandwidth`: результат сравнения, получается True если есть доступная полоса, и False если нет
* `account_vshares` - Сила Голоса аккаунта в виде vesting shares
* `max_virtual_bandwidth` - максимальная виртуальная пропускная способность сети.&#x20;
* `account_average_bandwidth` - показатель использования аккаунтом своей полосы
* `total_vshares` - суммарное значение vesting shares всех аккаунтов в блокчейне

Если вышеуказанную формулу записать как `(account_vshares * max_virtual_bandwidth) / (account_average_bandwidth * total_vshares)`, то получится число, показывающее долю использования аккаунтом своей полосы.

В данной формуле все переменные являются легко доступными параметрами, кроме `account_average_bandwidth`. Для получения данного значения требуется провести ряд вычислений.

1. С помощью API-метода [`get_account_bandwidth`](https://github.com/golos-blockchain/wiki/tree/ac1bf1ca5f43039f31ab27d77195dbc63dae37a1/developers/api-dokumentatsiya/api-golos-ch1.md) можно получить значение bandwidth на момент последней совершённой транзакции. Данное значение не будет актуальным на текущий момент времени, так как bandwidth всё время восстанавливается (уменьшается % потраченной пропускной способности). **Note:** это же значение bandwidth можно получить с помощью API-вызова `get_accounts`, однако в этом случае bandwidth будет находиться в поле `'new_average_bandwidth'` (а поле `'average_bandwidth'` следует проигнорировать, так как оно относится к устаревшему механизму контроля bandwidth и является deprecated).
2. В результатах вышеупомянутого вызова так же присутствует поле `"last_bandwidth_update"`, оно показывает момент последнего обновления bandwidth.
3. Если с момента последнего обновления прошло больше времени чем `STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS`, то `account_average_bandwidth` автоматически становится 0, это означает, что аккаунт может воспользоваться всей своей доступной полосой пропускания.
4. Если же времени прошло меньше, то следует подсчитать, на сколько восстановилась bandwidth. Для этого применяется следующая формула: `new_bandwidth = ((STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - elapsed_time) * account_average_bandwidth) / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS`, где
   * `elapsed_time` - сколько прошло времени с момента последнего обновления bandwidth
   * `account_average_bandwidth` - значение bandwidth на момент последнего обновления
5. Теперь у golosd есть данные о текущем состоянии bandwidth аккаунта, но теперь ему так же нужно определить, можно ли разрешить аккаунту совершить транзакцию. Для этого golosd подсчитывает, как изменится bandwidth после принятия транзакции, и не будет ли при этом превышена полоса пропускания. Для этого вычисляется bandwidth транзакции: `trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION`, где &#x20;
   * `trx_size` - размер транзакции в байтах. Для market-операций этот размер дополнительно умножается на 10, из-за чего и происходит то, что для market операций доступная bandwidth в 10 раз меньше чем для forum
   * `STEEMIT_BANDWIDTH_PRECISION` - константа, определяющая точность вычислений при работе с bandwidth
6. Вычисляется финальное значение `account_average_bandwidth = new_bandwidth + trx_bandwidth`

### Получение значений bandwidth в килобайтах

Мы можем самостоятельно вычислять максимально доступную bandwidth аккаунта и потреблённую на текущий момент.

Для получения значения потреблённой полосы, получается формула следующего вида:\
`used_kb = account_average_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024`

Для получения максимально доступной аккаунту полосы получается следующая формула. Какую долю от суммарной СГ имеет аккаунт, такую долю он и может взять из общей `max_virtual_bandwidth`:

`avail_kb = account_vshares/total_vesting_shares * max_virtual_bandwidth / STEEMIT_BANDWIDTH_PRECISION / 1024`

Практическую реализацию вычисления bandwidth вы можете посмотреть в функции `get_bandwidth` в [functions.py](https://github.com/bitfag/golos-scripts/blob/master/functions.py), которая используется в скрипте [get\_bandwidth.py](https://github.com/bitfag/golos-scripts/blob/master/get_bandwidth.py).

## Глобальная пропускная способность

При общей высокой загруженности сети срабатывает механизм ограничения общей пропускной способности через снижение `max_virtual_bandwidth`.

В исходных текстах механизм реализован в database.cpp в функции `void database::update_global_dynamic_data()` и работает по следующему алгоритму:

1. Примерно раз в минуту (каждые 20 блоков) происходит пересчёт `max_virtual_bandwidth`. Первым делом проверяется, не превышает ли средний размер блока (`average_block_size`) 1/4 от максимального размера блока (`maximum_block_size`).
   1. Если превышает, то `current_reserve_ratio` уменьшается в 2 раза, что по сути приводит к уменьшению `max_virtual_bandwidth` так же в 2 раза.
   2. Если не превышает, и ранее `current_reserve_ratio` был ограничен, то происходит линейный рост этого показателя путём инкремента на 1 единицу.

Таким образом, ограничение общей пропускной способности активируется, когда средний размер блока становится более 25% от текущего максимально размера блока. При этом ограничение срабатывает достаточно резко, т.к. `max_virtual_bandwidth` падает сразу в 2 раза. При этом, недостаток bandwidth сразу же могут испытать те пользователи, которые имеют потребление полосы выше 50%. Восстановление же общей доступной полосы после включения ограничения происходит плавно, в течение 3-4 дней.

## post bandwidth

Является самостоятельным ограничителем и никак не связана с пропускной способностью сети. Предназначение - штрафовать аккаунт, который постит слишком часто.

Реализация в исходных текстах находится в steem\_evaluator.cpp в `void comment_evaluator::do_apply()`


# Тестнет (ноды для тестов)

Для экспериментов (до использования вашего кода в основной цепи блокчейна) рекомендуются проверять запуская ноду тестнета.

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

**<https://apibeta.golos.today>** или **wss/apibeta.golos.today/ws**

Password (of @lex): `P5Jw6xSsoDhFtrNp1CGAWyzhVez6dFuxCQ9dn4QC7aZZW9R3WmUq`\ <mark style="color:green;">`Для всех аккаунтов ключи сброшены на`</mark> <mark style="color:green;"></mark> \
Posting: `5HwQScueMZdELZpjVBD4gm6xhiKiMqGx18g4WtQ6wVr4nBdSxY5` \
Active: `5K67PNheLkmxkgJ5UjvR8Nyt3GVPoLEN1dMZjFuNETzrNyMecPG` \
Owner: `5KD45zFh5WNFaW8mZTSx4eicy8FzwEmm5psNKH7GLg5bVQwUw6s` \
Memo: `5Kek6zP5vQmDRXXNBtZkxUtoMT3iW1xEYXcifkA2UHb2VT5UD7P`\
\
В лайвтест-цепи работают dev-приложения:

* Blogs [beta.golos.today](https://beta.golos.today) (на [github](https://github.com/golos-blockchain/ui-blogs/tree/beta))
* Wallet [devwallet.golos.today](https://devwallet.golos.today/) (на [github](https://github.com/golos-blockchain/ui-wallet/tree/dev))
* Messenger [devchat.golos.app](https://devchat.golos.app/) (на [github](https://github.com/golos-blockchain/ui-messenger/tree/dev))
* Forum [dev.golostalk.com](https://dev.golostalk.com) (на [github](https://github.com/golos-blockchain/ui-forums/tree/dev))
* Authorization [dev.golos.app](https://dev.golos.app) (на [github](https://github.com/golos-blockchain/ui-auth/tree/dev))
* Notify [devnotify.golos.app](https://devnotify.golos.app) (на [github](https://github.com/golos-blockchain/notify/tree/dev))
* ImageProxy [devimages.golos.today](https://devimages.golos.today/) (на [github](https://github.com/golos-blockchain/imageproxy/tree/dev))
* Exchange [devdex.golos.app](https://devdex.golos.app/) (на [github](https://github.com/golos-blockchain/ui-dex/tree/develop))


# API-документация

* [Плагины и их API](/developers/basics/plugins-api)
* [API часть 1](/developers/api/api-golos-ch1)
* [API часть 2](/developers/api/api-golos-ch2)
* [API часть 3](/developers/api/api-golos-ch3)
* [API часть 4](/developers/api/api-golos-ch4)
* [Cli-wallet API](/developers/api/cli-wallet)


# API part 1

Автор: [@asuleymanov](https://golos.id/@asuleymanov)

Представляю Вам первую часть моей публикации. В данную часть не вошли 18 из 72 (раздела Database\_API) найденных мною команд. Их я опишу позже.

***get\_trending\_tags***

Параметры:`"method":"get_trending_tags", "params":["after_tag","limit"], "id":4`

Описание: Отображает ограниченный список меток(тэгов) включающие словосочетания из первого параметра.

***get\_block\_header***

Параметры:`"method":"get_block_header", "params":["blocknumber"], "id":19`

Описание: Отображает краткую информацию по указанному блоку.

***get\_block***

Параметры:`"method":"get_block", "params":["blocknumber"], "id":20`

Описание: Отображает расширенную информацию по указанному блоку.

***get\_ops\_in\_block***

Параметры:`"method":"get_ops_in_block", "params":["block_num","only_virtual"], "id":21`

Описание: Команда должна отображать только операции в заданном блоке, но к сожалению ответ приходит пустой.

***get\_state***

Параметры:`"method":"get_state", "params":["path"], "id":22`

Описание: Отображает текущее состояние сети GOLOS. Оставить путь пустым для текущей информации.

***get\_trending\_categories***

Параметры:`"method":"get_trending_categories", "params":["searchafter","limit"], "id":23`

Описание: Позволяет искать ограниченное количество трендов категорий как текущие, так и прошлые.

***get\_best\_categories***

Параметры:`"method":"get_best_categories", "params":["after","limit"], "id":24`

Описание: Что именно делает данная команда мне пока непонятно.

***get\_active\_categories***

Параметры:`"method":"get_active_categories", "params":["after","limit"], "id":25`

Описание: Что именно делает данная команда мне пока непонятно.

***get\_recent\_categories***

Параметры:`"method":"get_recent_categories", "params":["after","limit"], "id":26`

Описание: К сожалению команда выдает все время пустой ответ. Так что неизвестно для чего она нужна. Мое понимание что она должна отображать ограниченное количество активностей в категории начиная с новой.

***get\_config***

Параметры:`"method":"get_config", "params":[], "id":27`

Описание: Отображает текущую конфигурацию узла.

***get\_dynamic\_global\_properties***

Параметры:`"method":"get_dynamic_global_properties", "params":[], "id":28`

Описание: Отображает различную информацию о текущем состоянии сети GOLOS.

***get\_chain\_properties***

Параметры:`"method":"get_chain_properties", "params":[], "id":29`

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

***get\_feed\_history***

Параметры:`"method":"get_feed_history", "params":[], "id":30`

Описание: Отображает историю конверсий GBG / GOLOS.

***get\_current\_median\_history\_price***

Параметры:`"method":"get_current_median_history_price", "params":[], "id":31`

Описание: Отображает текущую медианную цену конвертации GBG / GOLOS.

***get\_witness\_schedule***

Параметры:`"method":"get_witness_schedule", "params":[], "id":32`

Описание: Отображает текущее состояние делегирования.

***get\_hardfork\_version***

Параметры:`"method":"get_hardfork_version", "params":[], "id":33`

Описание: Отображает текущую версию ХФ GOLOS.

***get\_next\_scheduled\_hardfork***

Параметры:`"method":"get_next_scheduled_hardfork", "params":[], "id":34`

Описание: Отображает дату и версию ХФ GOLOS

***get\_key\_references***

Параметры:`"method":"get_key_references", "params":["key"], "id":35`

Описание: К сожалению сказать что делает данная команда не возможно. (Любой её вызов приводит к ошибке).

***get\_accounts***

Параметры:`"method":"get_accounts", "params":[["username"]], "id":36`

Описание: Отображает данные о пользователях указанных в запросе. Можно запрашивать сразу по нескольким пользователям разделив их запятыми.

***get\_account\_references***

Параметры:`"method":"get_account_references", "params":["accountid"], "id":37`

Описание: В настоящее время запрос возвращает ошибку. По идее должен выдавать информацию о пользователе по его ID.

***lookup\_account\_names***

Параметры:`"method":"lookup_account_names", "params":[["username"]], "id":38`

Описание: Отображает данные о пользователях указанных в запросе. Можно запрашивать сразу по нескольким пользователям разделив их запятыми.

***lookup\_accounts***

Параметры:`"method":"lookup_accounts", "params":["username","limit"], "id":39`

Описание: Действует как функция поиска для отображения имен пользователей, содержащих буквы, заданные в первом параметре. Второй параметр задает количество выдаваемых записей.

***get\_account\_count***

Параметры:`"method":"get_account_count", "params":[], "id":40`

Описание: Показывает количество пользователей зарегистрированных в сети GOLOS.

***get\_conversion\_requests***

Параметры:`"method":"get_conversion_requests", "params":["username"], "id":41`

Описание: Отображает текущие запросы на конвертацию указанным пользователем.

***get\_account\_history***

Параметры:`"method":"get_account_history", "params":["username","from","limit"], "id":42`

Описание: История всех действий пользователя в сети GOLOS в виде транзакций.

***get\_owner\_history***

Параметры:`"method":"get_owner_history", "params":["username"], "id":43}`

Описание: Отображает имя пользователя если он изменил право собственности на блокчейн.

***get\_recovery\_request***

Параметры:`"method":"get_recovery_request", "params":["username"], "id":44`

Описание: Если статус пользователя в настоящее время отмечен для восстановления, вернет true, в противном случае возвращается «null».

***get\_escrow***

Параметры:`"method":"get_escrow", "params":["from","escrow_id"], "id":45`

Описание: Данная команда должна отображать операции реализованные с помощью операций посредничества. К сожалению проверить эту команду нету возможности(у меня).

***get\_withdraw\_routes***

Параметры:`"method":"get_withdraw_routes", "params":["username","withdraw_route_type"], "id":46`

Описание: Команда по идее должна выдавать все переводы(или только активные) на счету пользователя в зависимости от типа(второй параметр). Который задается строкой вида **incoming**, **outgoing** или **all**. Но к сожалению никаких данных я в ответ не получал, так что сказать что и как выдается в ответ возможности нет.

***get\_account\_bandwidth***

Параметры:`"method":"get_account_bandwidth", "params":["username","bandwidth_type"], "id":47`

Описание: Отображает пропускную способность(пока не понял что это) пользователя в зависимости от типа.

Тип задается числом:

0- post

1- forum

2- market

3- old\_forum

4- old\_market

***get\_savings\_withdraw\_from***

Параметры:`"method":"get_savings_withdraw_from", "params":["username"], "id":48`

Описание: Команды "get\_savings\_withdraw\_from" и "get\_savings\_withdraw\_to" обе отображают данные о выводах из "СЕЙФА" для данного пользователя. Хотя как я понимаю одна из них должна отображать данные о переводе на счет "СЕЙФА" для данного пользователя.

***get\_savings\_withdraw\_to***

Параметры:`"method":"get_savings_withdraw_to", "params":["username"], "id":49`

Описание: Команды "get\_savings\_withdraw\_from" и "get\_savings\_withdraw\_to" обе отображают данные о выводах из "СЕЙФА" для данного пользователя. Хотя как я понимаю одна из них должна отображать данные о переводе на счет "СЕЙФА" для данного пользователя.

***get\_order\_book***

Параметры:`"method":"get_order_book", "params":["limit"], "id":50`

Описание: Отображает список заявок на внутренней бирже на покупку и продажу в сети GOLOS.

***get\_open\_orders***

Параметры:`"method":"get_open_orders", "params":["username"], "id":51`

Описание: Отображает список заявок на внутренней бирже на покупку и продажу в сети GOLOS для указанного пользователя.

***get\_liquidity\_queue***

Параметры:`"method":"get_liquidity_queue", "params":["startusername","limit"], "id":52`

Описание: Что именно делает данная команда мне пока непонятно.

***get\_transaction\_hex***

Параметры:`"method":"get_transaction_hex", "params":["trx"], "id":53`

Описание: Что именно делает данная команда мне пока непонятно. Так как не понятно что за параметр передается в запрос.

***get\_transaction***

Параметры:`"method":"get_transaction", "params":["txid"], "id":54`

Описание: Отображает детали транзакции по заданному ID транзакции.

***get\_required\_signatures***

Параметры:`"method":"get_required_signatures", "params":["trx", "availablekeys"], "id":55`

Описание: Что именно делает данная команда мне пока непонятно. Так как не понятно что за параметры передаются в запрос.

***get\_potential\_signatures***

Параметры:`"method":"get_potential_signatures", "params":["trx"], "id":56`

Описание: Что именно делает данная команда мне пока непонятно. Так как не понятно что за параметр передается в запрос.

***verify\_authority***

Параметры:`"method":"verify_authority", "params":["trx"], "id":57`

Описание: Что именно делает данная команда мне пока непонятно. Так как не понятно что за параметр передается в запрос.

***verify\_account\_authority***

Параметры:`"method":"verify_account_authority", "params":["userid/username","signer"], "id":58`

Описание: Что именно делает данная команда мне пока непонятно. Так как не понятно что за параметр передается в запрос.

***get\_active\_votes***

Параметры:`"method":"get_active_votes", "params":["username","permalink"], "id":59`

Описание: Отображает список пользователей проголосовавших за указанную запись.

***get\_account\_votes***

Параметры:`"method":"get_account_votes", "params":["username"], "id":60`

Описание: Отображает все голоса которые выставлены указанным пользователем.

***get\_content***

Параметры:`"method":"get_content", "params":["username","permalink"], "id":61`

Описание: Получает информацию о публикации, за исключением комментариев.

***get\_content\_replies***

Параметры:`"method":"get_content_replies", "params":["username","permalink"], "id":62`

Описание: Отображает список всех комментариев для выбранной публикации.

***get\_discussions\_by\_author\_before\_date***

Параметры:`"method":"get_discussions_by_author_before_date", "params":["username","start_permalink","before_date","limit"], "id":63`

Описание: Отображает ограниченное количество публикации (четвертый параметр) пользователя. Второй параметр задает линк стартовой публикации, если пусто то с самого начала. Третий параметр задает дату до какого момента показывать. Третий параметр является строкой, формат ввода (YYYY-MM-DDTHH:MM:SS

***get\_replies\_by\_last\_update***

Параметры:`"method":"get_replies_by_last_update", "params":["username","start_permalink","limit"], "id":64`

Описание: Странное поведение команды.\
При указание первого и третьего параметра(обязателен) отображает ограниченное количество комментариев во всех публикациях заданного пользователя по времени поступления считая от последнего.\
При указании второго параметра отображает непосредственно публикацию и еще ограниченное количество публикаций сторонних авторов.

***get\_witnesses***

Параметры:`"method":"get_witnesses", "params":[["witnessid"]], "id":65`

Описание: Отображает данные о делегатах в соответствии с заданными ID. Можно запрашивать данные сразу по нескольким делегатам разделив их ID запятыми.

***get\_witness\_by\_account***

Параметры:`"method":"get_witness_by_account", "params":["username"], "id":66`

Описание: Отображает данные о делегате (если он им является) в соответствии с данными из запроса.

***get\_witnesses\_by\_vote***

Параметры:`"method":"get_witnesses_by_vote", "params":["username/blank", "limit"], "id":67 <br>`\
Описание: Отображает ограниченный список делегатов одобряющих голосование. Если первый параметр пуст то отображаются ведущие делегаты, если первый параметр указан то список начинается с указанного делегата.

***lookup\_witness\_accounts***

Параметры:`"method":"lookup_witness_accounts", "params":["search_username", "limit"], "id":68`

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

***get\_witness\_count***

Параметры:`"method":"get_witness_count", "params":[], "id":69`

Описание: Отображает количество делегатов.

***get\_active\_witnesses***

Параметры:`"method":"get_active_witnesses", "params":[], "id":70`

Описание: Отображает список всех активных делегатов.

***get\_miner\_queue***

Параметры:`"method":"get_miner_queue", "params":[], "id":71`

Описание: Создает список майнеров, ожидающих попасть в DPOW цепочку, чтобы создать блок.

## Использование`curl`

Простой способ использовать команду - с помощью`curl`, используя следующий формат:

`curl --data '{"jsonrpc": "2.0", <Параметры>}' https://golos.lexai.host`

Историческая справка

* [Статья № 1](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisanie-api-golos-chast-1)
  * Начало разбора команд из раздела Database\_Api
* [Статья № 2](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisani-golosapi-chast-2)
  * Окончание разбора команд из раздела Database\_Api
* [Статья № 3](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisanie-golosapi-chast-3)
  * Разбор команд из разделов Market\_History\_API и Follow\_API
* [Статья №4](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisani-golosapi-chast-4)
  * Команды из раздела Network\_Brodcast\_API и Login\_API


# API part 2

Автор: [@asuleymanov](https://golos.id/@asuleymanov)

В первой части было описано много команд. Если быть точным 54. В этой статье я постараюсь описать оставшиеся команды из раздела Database\_API. А также приоткрою завесу тайны на некоторые команды из прошлого выпуска.\
В общем в данный выпуск вошли три группы команд. Условно разделю их на три типа:

1. **Невыясненные**
   * сюда вошли команды результаты вызова которых не ясны. В основном это связано с тем, что так и не нашлось вразумительное объяснение, какой параметр надо передавать.
2. **Команды из прошлого выпуска**
   * сюда вошли 4 команды из прошлого выпуска, так как удалось разобраться что за параметр необходимо передавать.
3. **Неразобранные**
   * сюда вошли команды описание которых не вошло в прошлый выпуск.

## Невыясненные

***set\_subscribe\_callback***\
Параметры:`"method":"set_subscribe_callback", "params":[["cb","clearfilter"]], "id":0`\
Описание: Не выяснено.

***set\_pending\_transaction\_callback***\
Параметры:`"method":"set_pending_transaction_callback", "params":["cb"], "id":1`\
Описание: Не выяснено.

***set\_block\_applied\_callback***\
Параметры:`"method":"set_block_applied_callback", "params":["cb"], "id":2`\
Описание: Не выяснено.

***cancel\_all\_subscriptions***\
Параметры:`"method":"cancel_all_subscriptions", "params":["cb"], "id":3`\
Описание: Не выяснено.

## Команды из прошлого выпуска

***get\_ops\_in\_block***

Параметры:`"method":"get_ops_in_block", "params":[block_num,only_virtual], "id":21`

Описание: Отображает операции которые были в указанном блоке. При этом если параметр only\_virtual выставлен в значение true то отображаются только виртуальные операции(что это выяснить так и не удалось)

> [@ropox](https://golos.id/@ropox)\
> Как я понимаю, "виртуальные операции" операции сделанные самим блокчейном. author\_reward, curation\_reward. Их не увидеть по команде get\_block, только вот так. get\_ops\_in\_block или get\_account\_history. К примеру блок 6754128.

***get\_transaction\_hex***

Параметры:`"method":"get_transaction_hex", "params":["trx"], "id":53`

Описание: Отображает HEX строку(что именно это такое не ясно). В параметр передается подписанная транзакция.

***get\_potential\_signatures***

Параметры:`"method":"get_potential_signatures", "params":["trx"], "id":56`

Описание: Отображает потенциальный ключ для данной транзакции. В параметр передается подписанная транзакция.

***verify\_authority***

Параметры:`"method":"verify_authority", "params":["trx"], "id":57`

Описание: Отвечает TRUE если транзакция подписана правильно. В параметр передается подписанная транзакция.

**P.S. Описание транзакции, т.е. её составление я попробую разобрать в следующей статье.**

## Не разобранные

Отступление. Все нижеописанные команды в виде параметр принимают структуру/объект такого вида(условно назову его ***dsc***):

```
uint32 limit = 0  - количество возвращаемых записей не может быть больше 100. По умолчанию 0 
map[string] select_authors - массив содержит имена авторов 
map[string] select_tags - Список тегов, сообщения без этих тегов фильтруются
map[string] filter_tags - Список тегов, сообщения с этими тегами фильтруются;
uint32 truncate_body = 0 - Количество байтов возвращаемого тела сообщения, 0 для всех, *параметр не обязателен*
string start_author - имя автора с которого начинать искать, *параметр не обязателен*
string start_permlink - ссылка публикации с которой начинать искать, *параметр не обязателен*
string parent_author - имя автора стартовавшего дискуссию, *параметр не обязателен*
string parent_permlink - постоянная ссылка на родительскую дискуссию, *параметр не обязателен*
```

Пояснения. Вначале указан тип параметра, а потом сам параметр.

***get\_discussions\_by\_trending***\
Параметры:`"method":"get_discussions_by_trending", "params":[dsc], "id":6`\
Описание: Отображает ограниченное количество публикаций начиная с самой дорогой по вознаграждению.

***get\_discussions\_by\_trending30***\
Параметры:`"method":"get_discussions_by_trending30", "params":[dsc], "id":7`\
Описание: Отображает ограниченное количество публикаций по вознаграждению.

***get\_discussions\_by\_created***\
Параметры:`"method":"get_discussions_by_created", "params":[dsc], "id":8`\
Описание: Отображает ограниченное количество публикаций начиная с самой новой.

***get\_discussions\_by\_active***\
Параметры:`"method":"get_discussions_by_active", "params":[dsc], "id":9`\
Описание: Отображает ограниченное количество записей в которых была активность начиная с самой новой.

***get\_discussions\_by\_cashout***\
Параметры:`"method":"get_discussions_by_cashout", "params":[dsc], "id":10`\
Описание: Отображает ограниченное количество публикаций, отсортированных по времени выплат.

***get\_discussions\_by\_payout***\
Параметры:`"method":"get_discussions_by_payout", "params":[dsc], "id":11`\
Описание: Отображает ограниченное количество публикаций , отсортированных по выплатам.

***get\_discussions\_by\_votes***\
Параметры:`"method":"get_discussions_by_votes", "params":[dsc], "id":12`\
Описание: Отображает ограниченное количество публикаций, отсортированных по величине голосов.

***get\_discussions\_by\_children***\
Параметры:`"method":"get_discussions_by_children", "params":[dsc], "id":13`\
Описание: Отображает ограниченное количество публикаций, отсортированных по количеству комментариев.

***get\_discussions\_by\_hot***\
Параметры:`"method":"get_discussions_by_hot", "params":[dsc], "id":14`\
Описание: Отображает ограниченное количество публикаций, отсортированных по популярности.

***get\_discussions\_by\_feed***\
Параметры:`"method":"get_discussions_by_feed", "params":[dsc], "id":15`\
Описание: Отображает ограниченное количество публикаций, из фида конкретного автора

***get\_discussions\_by\_blog***\
Параметры:`"method":"get_discussions_by_blog", "params":[dsc], "id":16`\
Описание: Отображает ограниченное количество публикаций, из блога конкретного автора.

***get\_discussions\_by\_comments***\
Параметры:`"method":"get_discussions_by_comments", "params":[dsc], "id":17`\
Описание: Отображает ограниченное количество публикаций, из комментариев конкретного автора.

***get\_discussions\_by\_promoted***\
Параметры:`"method":"get_discussions_by_feed", "params":[dsc], "id":18`\
Описание: Отображает ограниченное количество публикаций, отсортированных с помощью увеличенной суммы баланса (К сожалению мне так и не удалось понять что тут имеется ввиду.)

Историческая справка

* [Статья № 1](https://www.gitbook.com/book/cyberfund/golos/edit#)
  * Начало разбора команд из раздела Database\_Api
* [Статья № 2](https://www.gitbook.com/book/cyberfund/golos/edit#)
  * Окончание разбора команд из раздела Database\_Api
* [Статья № 3](https://www.gitbook.com/book/cyberfund/golos/edit#)
  * Разбор команд из разделов Market\_History\_API и Follow\_API


# API part 3

Автор: [@asuleymanov](https://golos.id/@asuleymanov)

В предыдущей части я завершил описание API команд из раздела Database\_API. Осталось еще 3 раздела. В данной статье я постараюсь описать 2 из 3 раздела, а именно Market\_History\_API и Follow\_API.\
Последний раздел NetworkBrodcast\_API я оставлю на финал (как самое вкусное и желанное), пусть будет в виде вишенки на торте.

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

## Market\_History\_API

В данном разделе содержатся команды для получения данных о операциях проводимых на внутренней бирже сети.

***get\_ticker***\
Параметры:`"method":"get_ticker", "params":[], "id":0`\
Описание: Возвращает рыночный тикер для внутреннего рынка GBG:GOLOS.

***get\_volume***\
Параметры:`"method":"get_volume", "params":[], "id":1`\
Описание: Возвращает объем рынка за последние 24 часа.

***get\_order\_book***\
Параметры:`"method":"get_order_book", "params":["limit"], "id":2`\
Описание: Отображает список заявок на внутренней бирже на покупку и продажу в сети GOLOS.

***get\_trade\_history***\
Параметры:`"method":"get_trade_history", "params":["start","end","limit"], "id":3`\
Описание: Возвращает историю торговли для внутреннего рынка GBG:GOLOS.\
start - время начала торговой истории\
end - время окончания торговой истории

***get\_recent\_trades***\
Параметры:`"method":"get_recent_trades", "params":["limit"], "id":4`\
Описание: Возвращает N последних сделок для внутреннего рынка GBG:GOLOS.

***get\_market\_history***\
Параметры:`"method":"get_market_history", "params":[["bucket_seconds","start","end"]], "id":5`\
Описание: Возвращает историю для внутреннего рынка GBG:GOLOS.\
bucket\_seconds - размер стакана(среза) в секундах\
start - время начала торговой истории\
end - время окончания торговой истории

***get\_market\_history\_buckets***\
Параметры:`"method":"get_market_history_buckets", "params":[], "id":6`\
Описание: Возвращает размер секунд стакана(среза), отслеживаемых плагином.

В последних двух командах использовано слово стакан(срез). Я к сожалению не биржевой человек и не сильно понимаю все её хитрости. Поэтому если кто то сможет это разъяснить буду очень этому признателен.

## Follow\_API

Данный раздел позволяет получить данные о подписках, подписчиках и репостах пользователей.

***get\_followers***\
Параметры:`"method":"get_followers", "params":["following","startFollower","follow_type","limit"], "id":0`\
Описание: Возвращает список:\
Либо всех подписчиков пользователя "following".\
Либо если указано имя пользователя в параметре "startFollower" возвращается список совпадающих подписчиков.\
Параметр "follow\_type" может принимать только такие строковые значения (undefined,blog,ignore)

***get\_following***\
Параметры:`"method":"get_following", "params":["follower","startFollower","follow_type","limit"], "id":1`\
Описание: Как я понимаю.(К сожалению никакие попытки получить результата успехом не увенчались)\
Возвращает список:\
Либо всех на кого подписан пользователь "follower".\
Либо если указано имя пользователя в параметре "startFollower" возвращается список совпадающих пользователей на которых они подписаны.\
Параметр "follow\_type" может принимать только такие строковые значения (undefined,blog,ignore)

***get\_follow\_count***\
Параметры:`"method":"get_follow_count", "params":["username"], "id":2`\
Описание: Возвращает данные о количестве подписчиков и подписок указанного пользователя.

***get\_feed\_entries***\
Параметры:`"method":"get_feed_entries", "params":["account","entry_id","limit"], "id":3`\
Описание: Возвращает краткие данные о записях из ленты указанного пользователя.\
Параметр "entry\_id" установленный в 0 выдает самые свежие данные.

***get\_feed***\
Параметры:`"method":"get_feed", "params":["account","entry_id","limit"], "id":4`\
Описание: Возвращает полные данные о записях из ленты указанного пользователя.\
Параметр "entry\_id" установленный в 0 выдает самые свежие данные.

***get\_blog\_entries***\
Параметры:`"method":"get_blog_entries", "params":["account","entry_id","limit"], "id":5`\
Описание: Возвращает краткие данные о записях из блога указанного пользователя.\
Параметр "entry\_id" установленный в 0 выдает самые свежие данные.

***get\_blog***\
Параметры:`"method":"get_blog", "params":["account","entry_id","limit"], "id":6`\
Описание: Возвращает полные данные о записях из блога указанного пользователя.\
Параметр "entry\_id" установленный в 0 выдает самые свежие данные.

***get\_account\_reputations***\
Параметры:`"method":"get_account_reputations", "params":["lowerBoundName","limit"], "id":7`\
Описание: Возвращает данные о репутации пользователей отфильтрованных по шаблону.

***get\_reblogged\_by***\
Параметры:`"method":"get_reblogged_by", "params":["author","permlink"], "id":8`\
Описание: Возвращает список пользователей которые либо создали запись либо сделали её репост.

***get\_blog\_authors***\
Параметры:`"method":"get_blog_authors", "params":["username"], "id":9`\
Описание: Возвращает список авторов и количество репостов этого автора пользователем.


# API part 4

Автор: [@asuleymanov](https://golos.id/@asuleymanov)

В предыдущей части описания я обещал приоткрыть завесу тайны над тем как именно можно самому добавлять записи в блокчейн. Собственно я опишу команды из раздела Network\_Brodcast\_API и Login\_API. И попробую рассказать о процедуре генерации транзакции, её подписи и отправки в блокчейн.

## Команды раздела Network\_Brodcast\_API

***broadcast\_block***\
Параметры:`"method":"broadcast_block", "params":["signed_block"], "id":0`\
Описание: Скорее всего данная команда должна загружать в блокчейн собранный и подписанный блок. Но проверить его мне не удалось.

***broadcast\_transaction***\
Параметры:`"method":"broadcast_transaction", "params":["trx"], "id":1`\
Описание: Транзакция будет проверяться на достоверность в локальной базе данных до начала трансляции. Если он не может применяться локально, будет вызвана ошибка, и транзакция не будет транслироваться.

***broadcast\_transaction\_synchronous***\
Параметры:`"method":"broadcast_transaction_synchronous", "params":["trx"], "id":2`\
Описание: Этот вызов не будет возвращен до тех пор, пока транзакция не будет включена в блок.

***broadcast\_transaction\_with\_callback***\
Параметры:`"method":"broadcast_transaction_with_callback", "params":["confirmationCallback","trx"], "id":3`\
Описание: Эта версия широковещательной транзакции регистрирует метод обратного вызова, который будет вызываться, когда транзакция включена в блок. Метод обратного вызова включает идентификатор транзакции, номер блока и номер транзакции в блоке.

### Команды раздела Login\_API

***login***\
Параметры:`"method":"login", "params":["username","password"], "id":0`\
Описание: Позволяет подключаться к учетным записям в сети GOLOS.

***get\_api\_by\_name***\
Параметры:`"method":"get_api_by_name", "params":["apiname"], "id":1`\
Описание: Возвращает уникальный идентификатор API по его имени.Пример идентификатора "login\_api" или "follow\_api".

***get\_version***\
Параметры:`"method":"get_version", "params":[], "id":2`\
Описание: Возвращает данные о версии компонентов блокчейн

## Процедура подписания и отправки

Для примера я возьму самую простую операцию голосования. С её помощью я разберу как происходит генерация транзакции и её подписание.

### Операция

Первым шагом мы создаем операцию.\
Если посмотреть на саму операцию то она имеет вид

```
['vote',
   {'author': 'author',
    'permlink': 'permlink',
    'voter': 'voter',
    'weight': weight}]
```

Тут можно четко определить:

* тип операции `vote`(голосование)
* собственно саму публикацию за которую производиться голосование (параметры `author` и `permlink`)
* кто голосует (параметр `voter`)
* и соответственно вес голоса который он готов отдать (параметр `weight`)

### Транзакция

Следующим шагом мы создаем непосредственно транзакцию с необходимой нам операцией. Транзакция может содержать от одной до нескольких операций. В нашем случае это 1 операция голосования и сгенерированная транзакция выглядит так:

```
trx = {'ref_block_num': 36029,
    'ref_block_prefix': 1164960351,
    'expiration': '2017-06-13T12:24:17',
    'operations': [['vote',
                     {'author': 'xeroc',
                      'permlink': 'piston',
                      'voter': 'xeroc',
                      'weight': 10000}]],
    'extensions': [],
    'signatures': [],
}
```

Можно заметить что наша операция является частью массива`operations`.\
Давайте разберем те поля в транзакции которые у нас появились, но нам неизвестны.

* Параметр

  `ref_block_num`

  указывает на номер предыдущего блока.
* Параметр

  `ref_block_prefix`

  получаем из идентификатора блока, а именно последние 4 байта.
* Параметр

  `expiration`

  проставляет время истечения действия транзакции. Если до этого времени не произошло включение транзакции в блок, то она считается недействительной.
* Параметр

  `extensions`

  расширение.
* Параметр

  `signatures`

  собственно подпись. Данный параметр проставляется в момент подписания.

Примет получения параметров`ref_block_num`и`ref_block_prefix`на python:

```
DGP = get_dynamic_global_properties()
ref_block_num = DGP["head_block_number"] 
&0xFFFF
ref_block_prefix = struct.unpack_from("<I", unhexlify(DGP["head_block_id"]), 4)[0]
```

Цель этих двух параметров для предотвращения повторения запросов.

### Сериализация (приведение к жесткой структуре)

Прежде чем переходить непосредственно к процессу подписи. Надо сериализовать (привести к жесткой структуре) транзакцию. Это необходимо чтобы на стороне ноды было проще проверить правильность подписания транзакции. Т.е. после такой обработки мы будем точно знать порядок в каком располагались поля при подписании.\
При этом из процесса сериализации исключается параметр`signatures`и`extensions`.

И так на примере нашей транзакции порядок будет таким (Все примеры будут на языке python):

1. Создание буфера

   `buf = b""`
2. Добавление в буфер параметра

   `ref_block_num`

   `buf += struct.pack("<H", trx["ref_block_num"])`
3. Добавление в буфер параметра

   `ref_block_prefix`

   `buf += struct.pack("<I", trx["ref_block_prefix"])`
4. Добавление в буфер параметра

   `expiration`

   . Сам параметр при этом преобразуется в целое число (uint32)

```
timeformat = '%Y-%m-%dT%H:%M:%S%Z'
buf += struct.pack("<I", timegm(time.strptime((trx["expiration"] + "UTC"), timeformat)))
```

1. Добавление в буфер количество операций в нашей транзакции

   `buf += bytes(varint(len(trx["operations"])))`
2. Добавление непосредственно полей операции. Первое что добавляем это код операции. Он определяется из массива начинающегося с 0.

   **Список операций из исходников**

```
                vote_operation,
                comment_operation,
                transfer_operation,
                transfer_to_vesting_operation,
                withdraw_vesting_operation,
                limit_order_create_operation,
                limit_order_cancel_operation,
                feed_publish_operation,
                convert_operation,
                account_create_operation,
                account_update_operation,
                witness_update_operation,
                account_witness_vote_operation,
                account_witness_proxy_operation,
                pow_operation,
                custom_operation,
                report_over_production_operation,
                delete_comment_operation,
                custom_json_operation,
                comment_options_operation,
                set_withdraw_vesting_route_operation,
                limit_order_create2_operation,
                challenge_authority_operation,
                prove_authority_operation,
                request_account_recovery_operation,
                recover_account_operation,
                change_recovery_account_operation,
                escrow_transfer_operation,
                escrow_dispute_operation,
                escrow_release_operation,
                pow2_operation,
                escrow_approve_operation,
                transfer_to_savings_operation,
                transfer_from_savings_operation,
                cancel_transfer_from_savings_operation,
                custom_binary_operation,
                decline_voting_rights_operation,
                reset_account_operation,
                set_reset_account_operation,

                /// virtual operations below this point
                fill_convert_request_operation,
                author_reward_operation,
                curation_reward_operation,
                comment_reward_operation,
                liquidity_reward_operation,
                interest_operation,
                fill_vesting_withdraw_operation,
                fill_order_operation,
                shutdown_witness_operation,
                fill_transfer_from_savings_operation,
                hardfork_operation,
                comment_payout_update_operation
```

Далее идут поля непосредственно из операции в определенном порядке. На данный момент я смог выявить порядок только для 3-х операций.

> Операция`vote`
>
> ```
> (voter)
> (author)
> (permlink)
> (weight)
> ```
>
> Операция`comment`(эта одна операция но может выполнять два действия. Непосредственно комментировать и создавать новую публикацию)
>
> ```
> (parent_author) // если этот параметр пустой то это считается созданием новой публикации
> (parent_permlink)
> (author)
> (permlink)
> (title)
> (body)
> (json_metadata)
> ```

В нашем случае это выглядит в таком виде :

```
if op[0] == "vote":
    opdata = op[1]
    buf += (varint(len(opdata["voter"])) + bytes(opdata["voter"], "utf-8"))
    buf += (varint(len(opdata["author"])) + bytes(opdata["author"], "utf-8"))
    buf += (varint(len(opdata["permlink"])) + bytes(opdata["permlink"], "utf-8"))
    buf += struct.pack("<h", int(opdata["weight"]))
```

#### Результат

Приблизительный разбор результата:\
Во- первых , параметр ref\_block\_num( 36029)\
`bd8c..............................................................`

и параметр ref\_block\_prefix( 1164960351)\
`....5fe26f45......................................................`

Затем мы добавим время истечения транзакции`expiration`2016-08-08T12:24:17\
`............f179a857..............................................`

После этого нам нужно добавить количество операций (01)\
`....................01............................................`

И непосредственно саму операцию:\
Идентификатор операции (00)\
`......................00..........................................`

Голосующий`voter`\
`........................057865726f63..............................`

Автор публикации`author`\
`....................................057865726f63..................`

Ссылка на публикацию`permlink`\
`................................................06706973746f6e....`

и вес голоса`10000`\
`..............................................................1027`

Результат сериализации предстает приблизительно в таком виде:\
`bd8c5fe26f45f179a8570100057865726f63057865726f6306706973746f6e1027`

### Подписание

И вот самая тяжелая часть всего процесса. Для меня это пока тоже темный лес, но попробую описать хоть как то.\
Для подписания транзакции нам понадобится:

* Сериализованный буфер
* Идентификатор цепи chainid (STEEM:

  `0000000000000000000000000000000000000000000000000000000000000000`

  ; GOLOS

  `782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12`

  )
* Секретный ключ (в нашем случае posting key)

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

```
message = unhexlify(chainid) + buf
digest = hashlib.sha256(message).digest()
```

Теперь мы используя секретные ключи подписываем нашу транзакцию. Каждый секретный ключ приведет к одной подписи , которая должна быть добавлена в параметр signatures первоначальной транзакции.\
В нашем случае, мы просто работаем с одним закрытым ключом, представленным в WIF. Получим фактический двоичный закрытый ключ от WIF (для простоты используется класс PrivateKey от steembase.account)

```
wifs = ["5JLw5dgQAx6rhZEgNN5C2ds1V47RweGshynFSWFbaMohsYsBvE8"]
sigs = []
for wif in wifs:
    p = bytes(PrivateKey(wif))  # binary representation of private key
    sk = ecdsa.SigningKey.from_string(p, curve=ecdsa.SECP256k1)
```

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

```
cnt = 0
i = 0
while 1 :
    cnt += 1
    # Deterministic k
    #
    k = ecdsa.rfc6979.generate_k(
        sk.curve.generator.order(),
        sk.privkey.secret_multiplier,
        hashlib.sha256,
        hashlib.sha256(digest + bytes([cnt])).digest())
```

Подпись генерируется с помощью соответствующего вызова подписи ECDSA:

```
# Sign message

sigder = sk.sign_digest(
    digest,
    sigencode=ecdsa.util.sigencode_der,
    k=k)
```

Теперь создаем подпись,и проверяем является ли она канонической. Если это так, то мы разрываем цикл и продолжаем:

```
# Reformating of signature

r, s = ecdsa.util.sigdecode_der(sigder, sk.curve.generator.order())
signature = ecdsa.util.sigencode_string(r, s, sk.curve.generator.order())

# Make sure signature is canonical!

lenR = sigder[3]
lenS = sigder[5 + lenR]
if lenR is 32 and lenS is 32 :
    # ........
```

После того, как мы обеспечили каноничность, мы добавляем дополнительные параметры. Это упрощает проверку подписи , так как она привязывает подпись к одному уникальному открытому ключу. Без этих параметров системе необходимо будет проверить несколько открытых ключей вместо одного. Мы добавляем 4 и 27 , чтобы осталась совместимость с другими протоколами и получаем нашу подпись.

```
# Derive the recovery parameter

i = recoverPubkeyParameter(digest, signature, sk.get_verifying_key())
i += 4   \# compressed
i += 27  \# compact
break
```

После получения канонической подписи, мы форматируем её в шестнадцатеричном представлении и добавляем к нашей транзакции в параметр`signatures`. Этот вид подписи , называется компактной подписью.

```
trx["signatures"].append(
    hexlify(
        struct.pack("<B", i) +
        signature
    ).decode("ascii")
)
```

### Отправка

После довольно сложной процедуры подписания, отправка кажется элементарным действием.\
Для того чтобы быть уверенными что проблем при отправке нету лучше всего использовать команду`broadcast_transaction_synchronous`(так как при её использовании система возвращает ответ), а параметр для команды будет являться непосредственно`trx`.\
В ответе будет вот такая структура:

```
    ID       string `json:"id"`
    BlockNum uint32 `json:"block_num"`
    TrxNum   uint32 `json:"trx_num"`
    Expired  bool   `json:"expired"`
```

Этим постом я завершаю цикл по разбору GOLOS API

**Историческая справка**

* [Статья № 1](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisanie-api-golos-chast-1)
  * Начало разбора команд из раздела Database\_Api
* [Статья № 2](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisani-golosapi-chast-2)
  * Окончание разбора команд из раздела Database\_Api
* [Статья № 3](https://golos.id/ru--otkrytyij-kod/@asuleymanov/opisanie-golosapi-chast-3)
  * Разбор команд из разделов Market\_History\_API и Follow\_API


# Cli-wallet API

***Страница содержит справочную информацию о методах в cli\_wallet API для блокчейна версии HF18. Для каждого метода приводится перечень используемых в нем параметров с кратким их описанием, а также функциональное назначение этого метода.***

## about()

```cpp
variant_object about()const
```

Возвращает информацию о времени компиляции и о клиенте, в том числе версию клиента, версию git graphene/fc, версии boost, openssl и зависимостей.

## add\_operation\_copy\_to\_builder\_transaction()

```cpp
void add_operation_copy_to_builder_transaction(
        transaction_handle_type src_handle,
        transaction_handle_type dst_handle,
        uint32_t op_index
)
```

Параметры:\
`src_handle` — уникальный номер конструктора, из которого копируется операция;\
`dst_handle` — уникальный номер конструктора, на который копируется операция;\
`op_index` — номер копируемой операции.

Используется для копирования операции между конструкторами транзакций.

## add\_operation\_to\_builder\_transaction()

```cpp
void add_operation_to_builder_transaction(transaction_handle_type handle, const operation& op)
```

Параметры:\
`handle` — уникальный номер конструктора;\
`op` — добавляемая операция.

Используется для добавления операции в список операций конструктора транзакций.

## approve\_proposal()

```cpp
signed_transaction approve_proposal(
        const std::string& author, const std::string& title, 
        const approval_delta& delta, 
        bool broadcast
)
```

Параметры:\
`author` — автор предложенной транзакции;\
`title` — заголовок предложенной на подпись транзакции;\
`delta` — список подписей, необходимых для одобрения (или удаления) транзакции.\
`broadcast` — “true”, если транзакция пересылается на демон; “false”, если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

Возвращает подписанную версию транзакции.

## begin\_builder\_transaction()

```cpp
transaction_handle_type wallet_api::begin_builder_transaction()
```

Метод вызывает операцию создания конструктора транзакций и возвращает уникальный номер созданного конструктора. Начальное значение уникального номера принимается равным «0» и увеличивается на единицу с каждым вызовом метода.

## cancel\_order()

```cpp
annotated_signed_transaction wallet_api::cancel_order(
        string owner,
        uint32_t orderid,
        bool broadcast
)
```

Параметры:\
`owner` — имя аккаунта, созданного заявку на отмену транзакции;\
`orderid` — идентификационный номер заявки на отмену транзакции;\
`broadcast` — "true", если транзакция пересылается на демон.

Возвращает транзакцию, выполнение которой отменяется.

## cancel\_transfer\_from\_savings()

```cpp
annotated_signed_transaction wallet_api::cancel_transfer_from_savings(
        string from,
        uint32_t request_id,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, инициировавшего отмену;\
`reques_id` — идентификационный номер заявки, используемый в вызове `transfer_from_savings()` для отмены или перевызова операции;\
`broadcast` — "true", если транзакция пересылается на демон.

Возвращает подписанную транзакцию, выполнение которой отменяется.

## change\_recovery\_account()

```cpp
annotated_signed_transaction wallet_api::change_recovery_account(
        string owner,
        string new_recovery_account,
        bool broadcast
)
```

Параметры:\
`owner` — имя аккаунта;\
`new_recovery_account` — новое имя, которое будет присвоено восстановленному аккаунту;\
`broadcast`— "true", если транзакция пересылается на демон.

Возвращает подписанную транзакцию на изменение данных аккаунта.

## convert\_sbd()

```cpp
annotated_signed_transaction wallet_api::convert_sbd(string from, asset amount, bool broadcast)
```

Параметры:\
`from` — имя аккаунта, запрашивающего конвертацию своей криптовалюты вида SBD;\
`amount` — сумма средств в виде SBD для конвертации;\
`broadcast` — "true", если транзакция пересылается на демон.

Используется для конвертации SBD в STEEM в соответствии с их отношением, приведенным в `current_median_history`, за неделю с момента выполнения операции.

## check\_memo()

```cpp
void wallet_api::check_memo(
        const string& memo,
        const golos::api::account_api_object& account
)const
```

Параметры:\
`memo` — поле, записи которого проверяются;\
`account` — имя аккаунта.

Проверяет записи из поля `memo`, относящиеся к личным ключам аккаунта и импортированные в кошелек.

## create\_account()

```cpp
annotated_signed_transaction wallet_api::create_account(
        string creator,
        string new_account_name,
        string json_meta,
        bool broadcast
)
```

Параметры:\
`creator` — пользователь, который создает новый аккаунт;\
`new_account_name` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`broadcast` — "true", если транзакция пересылается на демон; "false", если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

Используется для создания нового аккаунта и генерацией ключей `owner`, `active`, и `memo` для этого аккаунта. За создание аккаунта в качестве комиссионных отчислений с баланса кошелька создателя аккаунта (автора) снимается определенная сумма `fee`. Величина этих отчислений не может быть меньше значения параметра `account_creation_fee`, устанавливаемого по результатам голосования делегатов.

## create\_account\_delegated()

```cpp
annotated_signed_transaction wallet_api::create_account_delegated(
        string creator, asset steem_fee,
        asset delegated_vests,
        string new_account_name,
        string json_meta,
        bool broadcast
)
```

Параметры:\
`creator` — пользователь, который создает новый аккаунт;\
`steem_fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть возвращена обратно в кошелек создателя аккаунта;\
`delegated_vests` — сумма комиссионных отчислений в криптовалюте Сила Голоса, снимаемая с баланса кошелька пользователя за операцию делегирования и зачисляемая на баланс кошелька нового аккаунта в криптовалюте Сила Голоса. Эта сумма может быть возвращена обратно в кошелек создателя аккаунта по истечении определенного периода, устанавливаемого голосованием делегатов;\
`new_account_name` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`bool broadcast` — "true", если транзакция пересылается на демон; "false", если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

Используется для создания аккаунта с делегированием. Автоматически генерирует публичные ключи `owner`, `active`, `posting` и `memo` для нового аккаунта.

## create\_account\_with\_keys()

```cpp
annotated_signed_transaction wallet_api::create_account_with_keys(
        string creator, string newname,
        string json_meta, asset fee,
        public_key_type owner,
        public_key_type active,
        public_key_type posting,
        public_key_type memo,
        bool broadcast
)const
```

Параметры:\
`creator` — пользователь, который создает новый аккаунт;\
`newname` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть меньше значения `account_creation_fee`, устанавливаемого по результатам голосования делегатов;\
`owner` — значение публичного ключа `owner` нового аккаунта;\
`active` — значение публичного ключа `active` нового аккаунта;\
`posting` — значение публичного ключа `posting` нового аккаунта;\
`memo` — значение публичного ключа `memo` нового аккаунта;\
`broadcast` — "true", если транзакция пересылается на демон.

Используется для создания аккаунта, требуется явное задание ключей.

## create\_account\_with\_keys\_delegated()

```cpp
annotated_signed_transaction wallet_api::create_account_with_keys_delegated(
        string creator, asset steem_fee,
        asset delegated_vests,
        string new_account_name,
        string json_meta, public_key_type owner,
        public_key_type active,
        public_key_type posting,
        public_key_type memo,
        bool broadcast
)const
```

Параметры:\
`creator` — пользователь, который создает новый аккаунт;\
`steem_fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть возвращена обратно в кошелек создателя аккаунта;\
`delegated_vests` — сумма комиссионных отчислений в криптовалюте Сила Голоса, снимаемая с баланса кошелька пользователя за операцию делегирования и зачисляемая на баланс кошелька нового аккаунта в криптовалюте Сила Голоса. Эта сумма может быть возвращена обратно в кошелек создателя аккаунта по истечении определенного периода, устанавливаемого голосованием делегатов;\
`new_account_name` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`owner` — значение публичного ключа `owner` нового аккаунта;\
`active` — значение публичного ключа `active` нового аккаунта;\
`posting` — значение публичного ключа `posting` нового аккаунта;\
`memo` — значение публичного ключа `memo` нового аккаунта;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для создания нового аккаунта через вызов операции `account_create`. Требуется явное задание ключей `owner`, `active`, `posting` и `memo` для нового аккаунта.

## create\_order()

```cpp
annotated_signed_transaction wallet_api::create_order(
        string owner,
        uint32_t order_id,
        asset amount_to_sell,
        asset min_to_receive,
        bool fill_or_kill,
        uint32_t expiration,
        bool broadcast
)
```

Параметры:\
`owner` — имя аккаунта, создаваемого заказ;\
`order_id` — идентификационный номер заказа, присваиваемый аккаунтом, создающий этот заказ;\
`amount_to_sell` — сумма средств в виде SBD или STEAM, выставляемая на продажу;\
`min_to_receive` — минимальная сумма средств, предполагаемая к получению;\
`fill_or_kill` — “true”, если заказ следует отменить в случае его немедленного невыполнения;\
`expiration` — время отведенное на выполнение заказа, по истечении которого он будет отменен;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для создания заказа на продажу с кошелька ограниченной суммы средств в виде SBD или STEAM по цене в соответствии с отношением `amount_to_sell / min_to_receive`.\
Возвращает подписанную транзакцию.

## database\_info()

```cpp
variant_object database_info()const
```

Возвращает справочную информацию о текущем статусе разделяемой памяти, в том числе: общий объем разделяемой памяти, размер свободного и зарезервированного пространства для определенных нужд, а также список индексов, хранящихся в разделяемой памяти (название индекса, количество записей).

## decline\_voting\_rights()

```cpp
annotated_signed_transaction wallet_api::decline_voting_rights(
        string account,
        bool decline,
        bool broadcast
)
```

Параметры:\
`account` — имя аккаунта, который лишается права голоса;\
`decline` — “true”, если аккаунт лишается права голоса; `broadcast` — “true”, если транзакция пересылается на демон.

Используется для лишения права голоса аккаунта с указанным именем.\
Возвращает подписанную транзакцию.

## decrypt\_memo()

```cpp
string wallet_api::decrypt_memo( string encrypted_memo )
```

Параметр:\
`encrypted_memo` — запись, приведенная для прочтения.

Возвращает текст в расшифрованном виде (если это возможно), находящийся в кошельке и зашифрованный с помощью одного из известных личных ключей.

## delegate\_vesting\_shares()

```cpp
annotated_signed_transaction wallet_api::delegate_vesting_shares(
        string delegator,
        string delegatee,
        asset vesting_shares,
        bool broadcast
)
```

Параметры:\
`delegator` — имя аккаунта, который делегирует Силу Голоса;\
`delegatee` — имя аккаунта, на который делегируется Сила Голоса;\
`vesting_shares` — сумма делегирования;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для делегирования части криптовалюты Силы Голоса (значение в GESTS) с одного аккаунта на другой.

## encrypt\_keys()

```cpp
void encrypt_keys()
```

Используется для шифрования текста (примечания) с помощью одного из личных ключей.

## escrow\_approve()

```cpp
annotated_signed_transaction wallet_api::escrow_approve(
        string from,
        string to,
        string agent,
        string who,
        uint32_t escrow_id,
        bool approve,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, передающего средства на условное депонирование;\
`to` — имя аккаунта, принимающего средства на условное депонирование;\
`agent` — имя аккаунта, выступающего в качестве агента в случае возникновения спорных ситуаций;\
`who` — имя аккаунта, утверждающего сделку (`to` или `agent`);\
`escrow_id` — идентификационный номер операции;\
`approve` — “true”, если сделка утверждается. Иначе транзакция отменяется с возвратом средств аккаунту с именем `from`;\
`broadcast` — “true”, если транзакция пересылается на демон.

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

## escrow\_dispute()

```cpp
annotated_signed_transaction wallet_api::escrow_dispute(
        string from,
        string to,
        string agent,
        string who,
        uint32_t escrow_id,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, передавшего средства на условное депонирование;\
`to` — имя аккаунта, принявшего средства на условное депонирование;\
`agent` — имя аккаунта, выступающего в качестве агента в случае возникновения спорных ситуаций;\
`who` — имя аккаунта, открывшего спор (`from` или `to`);\
`escrow_id` — идентификационный номер операции;\
`broadcast` — “true”, если транзакция пересылается на демон.

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

## escrow\_release()

```cpp
annotated_signed_transaction wallet_api::escrow_release(
        string from,
        string to,
        string agent,
        string who,
        string receiver,
        uint32_t escrow_id,
        asset sbd_amount,
        asset steem_amount,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, передавшего средства на условное депонирование;\
`to` — имя аккаунта, изначально принявшего средства на условное депонирование;\
`agent` — имя аккаунта, выступающего в качестве агента в случае возникновения спорных ситуаций;\
`who` — имя аккаунта, утвердившего сделку;\
`receiver` — имя аккаунта, в кошелек которого поступят отпущенные средства;\
`escrow_id` — идентификационный номер операции;\
`sbd_amount` — сумма отпущенных средств в виде SBD;\
`steem_amount` — сумма отпущенных средств в виде STEEM;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для разблокирования (освобождение) средств, передаваемых на условное депонирование.\
Возвращает подписанную транзакцию.

## escrow\_transfer()

```cpp
annotated_signed_transaction wallet_api::escrow_transfer(
        string from,
        string to,
        string agent,
        uint32_t escrow_id,
        asset sbd_amount,
        asset steem_amount,
        asset fee,
        time_point_sec ratification_deadline,
        time_point_sec escrow_expiration,
        string json_meta,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, от которого передаются средства на условное депонирование;\
`to` — имя аккаунта, к которому передаются средства на условное депонирование;\
`agent` — имя аккаунта, выступающего в качестве агента в случае возникновения спорных ситуаций;\
`escrow_id` — идентификационный номер операции (значения `from` и `escrow_id` должны составлять уникальную пару);\
`sbd_amount` — сумма средств в виде SBD, передаваемых на условное депонирование;\
`steem_amount` — сумма средств в виде STEEM, передаваемых на условное депонирование;\
`fee` — комиссионные отчисления для агента;\
`ratification_deadline` — время, до наступления которого транзакция должна быть одобрена аккаунтами с именами `to` и `agent`;\
`escrow_expiration` — время, по истечении которого любая из сторон может потребовать возврат средств;\
`json_meta` — метаданные в кодировке JSON;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для передачи средств в виде STEEM или SBD на условное депонирование от одного аккаунта другому.\
Возвращает подписанную транзакцию.

## find\_first\_unused\_derived\_key\_index()

```cpp
int find_first_unused_derived_key_index(const fc::ecc::private_key& parent_key)
```

Параметр:\
`parent_key` — родительский ключ.

Используется для генерации ключей, производных от родительского. Генерация ключей начинается с индекса «0» с последующим приращением его на единицу. Если очередные индексы будут отсутствовать (обнаружение незарегистрированных ключей) в блокчейне, процесс прекращается. Алгоритм поиска зарегистрированного ключа в блокчейне по очередному индексу предусматривает возможное отсутствие нескольких номеров (наличие «дыр») в последовательности. Размер «дыры» не должен превышать более пяти подряд идущих номеров.

## follow()

```cpp
annotated_signed_transaction wallet_api::follow(
        string& follower,
        string& following,
        const set<string>& what,
        bool broadcast
)
```

Параметры:\
`follower` — имя аккаунта, являющегося последователем другого;\
`following` — имя аккаунта, от которого наследуется набор вещей;\
`what` — набор вещей, который наследуется (посты, комментарии, голоса, игнорирования);\
`broadcast` — “true”, если транзакция пересылается на демон.

Помечает одного аккаунта как последователь (наследник) другого. Требует для последователя авторизацию ключом `posting`.\
Возвращает подписанную транзакцию.

## get\_account()

```cpp
golos::api::account_api_object get_account(string account_name)const
```

Параметр:\
account\_name — имя аккаунта, информация о котором предоставляется.

Возвращает информацию об аккаунте с заданным именем, имеющемся в базе данных блокчейна.

## get\_account\_history()

```cpp
map< uint32_t, golos::plugins::operation_history::applied_operation >
wallet_api::get_account_history(
        string account,
        uint32_t from,
        uint32_t limit
)
```

Параметры:\
`account` — аккаунт, история которого запрашивается;\
`from` — порядковый номер операции. «-1» — означает последний номер операции;\
`limit` — максимальное количество запрашиваемых элементов. Принимает значение 0-1000.

Возвращает историю всех действий в виде транзакций пользователя в сети GOLOS.

## get\_active\_witnesses()

```cpp
vector< account_name_type > wallet_api::get_active_witnesses()const
```

Возвращает список всех активных делегатов, создавших блоки в текущем окружении (21 блок).

## get\_block ()

```cpp
optional<signed_block_with_info> wallet_api::get_block (uint32_t num)
```

Параметр:\
`num` — номер блока.

Возвращает расширенную информацию по блоку с номером `num`.

## get\_conversion\_requests()

```cpp
vector< database_api::convert_request_api_object > wallet_api::get_conversion_requests(
        string owner_account
)
```

Параметр:\
`owner_account` — имя аккаунта, создавшего запросы.

Возвращает текущие запросы на конвертацию указанным пользователем, в том числе все ожидающие запросы

## get\_encrypted\_memo()

```cpp
string wallet_api::get_encrypted_memo( string from, string to, string memo )
```

Параметры:\
`from` — имя аккаунта, с кошелька которого снимаются средства;\
`to` — имя аккаунта, в кошелек которого поступают средства;\
`memo` — текст заметки (примечания).

Возвращает заметку в зашифрованном виде, если ее текст начинается с символа «#». В противном случае возвращает заметку в ее оригинальном виде.

## get\_feed\_history()

```cpp
witness_api::feed_history_api_object wallet_api::get_feed_history()const
```

Возвращает историю конверсий GBG / GOLOS на блокчейне.

## get\_inbox()

```cpp
vector<extended_message_object> wallet_api::get_inbox(
        const std::string& to,
        time_point newest,
        uint16_t limit,
        std::uint64_t offset
)
```

Параметры:\
`to` — имя аккаунта, для которого запрашиваются входящие к нему сообщения;\
`newest` — время, с момента которого запрашиваются сообщения;\
`limit` — пороговое значение на количество запрашиваемых сообщений;\
`offset` — смещение (в секундах) к заданному времени `newest`.

Используется для просмотра входящих личных сообщений для аккаунта с именем `to`, хранящихся в блокчейне.

## get\_miner\_queue()

```cpp
vector<account_name_type> wallet_api::get_miner_queue()const
```

Возвращает список майнеров, ожидающих создание блоков.

## get\_open\_orders()

```cpp
vector< database_api::extended_limit_order > wallet_api::get_open_orders( string owner )
```

Параметр:\
`owner` — пользователь, для которого отображается список заявок.

Возвращает список заявок на внутренней бирже на покупку и продажу в сети GOLOS для указанного пользователя.

## get\_ops\_in\_block()

```cpp
vector< golos::plugins::operation_history::applied_operation > wallet_api::get_ops_in_block(
        uint32_t block_num,
        bool only_virtual
)
```

Параметры:\
`num` — номер (позиция) блока;\
`only_virtual` — только виртуальные операции.

Возвращает виртуальные операции в заданном блоке.

## get\_order\_book()

```cpp
market_history::order_book wallet_api::get_order_book(uint32_t limit)
```

Параметр:\
`limit` — максимальное количество заказов для возврата заявок и запросов (максимальное значение — 1000).

Возвращает список заявок на внутренней бирже на покупку и продажу в сети GOLOS.

## get\_outbox()

```cpp
vector<extended_message_object> wallet_api::get_outbox(
        const std::string& from,
        time_point newest,
        uint16_t limit,
        std::uint64_t offset
)
```

Параметры:\
`from` — имя аккаунта, для которого запрашиваются исходящие от него сообщения;\
`newest` — время, с момента которого запрашиваются сообщения;\
`limit` — пороговое значение на количество запрашиваемых сообщений;\
`offset` — смещение (в секундах) к заданному времени `newest`.

Используется для просмотра исходящих личных сообщений для аккаунта с именем `from`, хранящихся в блокчейне.

## get\_owner\_history()

```cpp
vector< database_api::owner_authority_history_api_object > wallet_api::get_owner_history(
        string account
)const
```

Параметры:\
`account` — пользователь, история которого отображается.

Возвращает историю полномочий (прав собственности) пользователя в блокчейне.

## get\_private\_key()

```cpp
fc::ecc::private_key get_private_key(const public_key_type pubkey)const
```

Параметр:\
`pubkey` — тип публичного ключа.

Используется для получения личного ключа в формате WIF, соответствующего публичному ключу. Личный ключ к этому моменту должен быть в кошельке.\
Возвращает подтверждение о наличие ключа или его отсутствие.

## get\_private\_key\_for\_account()

```cpp
fc::ecc::private_key get_private_key_for_account(
        const golos::api::account_api_object& account
)const
```

Параметр:\
`account` — имя аккаунта, получающего ключ.

Возвращает данные ключа `active` в формате WIF.

## get\_private\_key\_from\_password()

```cpp
pair<public_key_type,string> wallet_api::get_private_key_from_password(
        string account,
        string role,
        string password
)const
```

Параметры:\
`account` — имя аккаунта, который получает ключ;\
`role` — тип ключа (`active` | `owner` | `posting` | `memo`);\
`password` — пароль, который будет использоваться во время генерации ключа.

Возвращает публичный ключ, соответствующий сгенерированному личному ключу, а также личный ключ в формате WIF.

## get\_proposed\_transactions()

```cpp
std::vector<database_api::proposal_api_object> get_proposed_transactions(
        std::string account,
        uint32_t from,
        uint32_t limit
)
```

Параметры:\
`account` — аккаунт, информацию о предложенных транзакциях которого необходимо получить;\
`from` — начальный номер транзакции;\
`limit` — пороговое значение количества транзакций.

Используется для получения информации о всех предложенных транзакциях применительно к одному и тому же аккаунту. Для получения информации об ограниченном количестве транзакций, необходимо задать начальный номер транзакции `from` и пороговое значение `limit`.

## get\_prototype\_operation()

```cpp
operation get_prototype_operation(string operation_type)
```

Параметр:\
`operation_type` — тип операции. Операция должна быть определена в файле `steem/chain/operations.hpp`.

Используется для получения и заполнения шаблона для операции, создаваемой с помощью вызова `add_operation_to_builder_transaction()`. Возвращает неинициализированный объект в виде заданной последовательности операций. Созданный объект может быть дополнен любой операцией с помощью вызова `add_operation_to_builder_transaction()`.

## get\_transaction()

```cpp
annotated_signed_transaction wallet_api::get_transaction(transaction_id_type id)const
```

Параметр:\
id — идентификатор транзакции.

Возвращает информацию о транзакции с указанном идентификатором.

## get\_wallet\_filename()

```cpp
string get_wallet_filename()
```

Возвращает текущее имя файла кошелька. Данное имя файла используется при автоматическом сохранении кошелька.

## get\_withdraw\_routes()

```cpp
vector< database_api::withdraw_vesting_route_api_object > wallet_api::get_withdraw_routes(
        string account,
        database_api::withdraw_route_type type
)const
```

Параметры:\
`account` — пользователь, для которого запрашивается возврат;\
`type` — тип возврата (задается строкой вида `incoming`, `outgoing` или `all`).

Возвращает перечень переводов, осуществляющих на счет пользователя в зависимости от задаваемого типа возврата (входящий, исходящий или все).

## get\_witness()

```cpp
optional < witness_api::witness_api_object > get_witness(string owner_account)
```

Параметр:\
`owner_account` — имя или идентификатор делегата.

Возвращает информацию о заданном делегате, хранимую в блокчейне.

## gethelp()

```cpp
string wallet_api::gethelp(const string & method)const
```

Параметр:\
`method` — имя API команды, информация о которой запрашивается.

Возвращает справочную информацию по отдельной команде API.

## help()

```cpp
string wallet_api::help()const
```

Возвращает на терминал справочный перечень всех команд, поддерживаемых приложением wallet API.\
Информация содержит команды, их аргументы и возвращаемые типы. Для получения более подробной информации по отдельной команде следует использовать `get_help()`.

## get\_withdraw\_routes()

```cpp
vector< database_api::withdraw_vesting_route_api_object > wallet_api::get_withdraw_routes(
        string account,
        database_api::withdraw_route_type type
)const
```

Параметры:\
`account` — имя аккаунта, запрашивающего маршруты;\
`type` — тип вывода (входящий, исходящий или все).

Возвращает маршруты вывода средств для аккаунта.

## import\_key()

```cpp
bool import_key(string wif_key)
```

Параметр:\
`wif_key` — личный ключ в формате WIF.

Используется для импорта личного ключа в формате WIF в кошелек для его дальнейшего использования аккаунтом при подписании транзакций.\
Пример использования команды:

```
import_key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
```

## info()

```cpp
variant wallet_api::info()const
```

Возвращает актуальную информацию о блокчейне, в том числе:\
`witness_majority_version` — актуальное состояние делегирования;\
`hardfork_version` — версию HF Golos;\
`head_block_num` — актуальный номер блока;\
`head_block_id` — идентификатор блока;\
`head_block_age` — время жизни блока (в секундах);\
`median_sbd_price` — медианное значение SBD;\
`account_creation_fee` — размер комиссионных отчислений, требуемых на создание аккаунта без делегирования;\
`create_account_min_golos_fee` — минимальный размер комиссионных отчислений в криптовалюте Голос, требуемых на создание аккаунта с делегированием;\
`create_account_min_delegation` — минимально возможное количество Силы Голоса при создании аккаунта с делегированием;\
`create_account_delegation_time` — минимально возможное время (в секундах) «заморозки» делегированной Силы Голоса при создании аккаунта с делегированием;\
`min_delegation` — минимально возможное количество Силы Голоса для делегирования на аккаунт.

## is\_locked()

```cpp
bool wallet_api::is_locked()const
```

Проверяет состояние кошелька: заблокирован или нет. Если кошелек находится в заблокированном состоянии, находящиеся в нем личные ключи использованы быть не могут. Состояние ключа изменяется вызовами `lock()` или `unlock()`.\
Возвращает “true”, если кошелек заблокирован.

## is\_new()

```cpp
bool wallet_api::is_new()const
```

Проверяет состояние кошелька: новый (пароль еще не установлен) или нет. Установка пароля осуществляется с помощью вызова `set_password()`. Во время выполнении этой команды кошелек переводится в заблокированное состояние.\
Возвращает “true”, если кошелек новый.

## list\_accounts()

```cpp
vector< account_name_type > wallet_api::list_accounts(const string& lowerbound, uint32_t limit)
```

Параметры:\
`lowerbound` — имя первого возвращаемого аккаунта. Если такое имя отсутствует, список будет начинаться с имени, непосредственно следующего за `lowerbound`;\
`limit` — значение, ограничивающее количество выводимых на монитор имен аккаунтов. Максимальное значение — 1000.

Используется для получения списка всех аккаунтов, зарегистрированных в блокчейне. Задание параметров `lowerbound` и `limit` позволяет формировать страницу в удобной для просмотра форме. Для просмотра всего списка имен аккаунтов рекомендуется вначале значение `lowerbound` устанавливать в виде пустой строки (“”). Затем на каждой итерации параметру `lowerbound` передавать последнее возвращаемое имя аккаунта для следующего вызова `list_accaunt()`.\
Возвращает список всех зарегистрированных в блокчейне имен аккаунтов с соответствующими им идентификаторами, отсортированный по именам в алфавитном порядке.

## list\_keys()

```cpp
map<public_key_type, string> wallet_api::list_keys()
```

Используется для выдачи (распечатки) всех личных ключей, принадлежащих кошельку. Данные ключей выдаются в формате WIF. Ключи могут быть импортированы в другой кошелек вызовом `import_key`.\
Возвращает карту, содержащую личные ключи, индексированные по их публичному ключу.

## list\_my\_accounts()

```cpp
vector< golos::api::account_api_object > wallet_api::list_my_accounts()
```

Используется для получения информации об аккаунтах с помощью личного ключа, имеющегося в кошельке. Кошелек должен быть предварительно разблокирован. Метод использует вызов `get_account()`.

## list\_witnesses()

```cpp
vector< account_name_type > wallet_api::ist_witnesses(const string& lowerbound, uint32_t limit)
```

Параметры:\
`lowerbound` — имя первого возвращаемого делегата. Если такое имя отсутствует, список будет начинаться с имени, непосредственно следующего за `lowerbound`;\
`limit` — значение, ограничивающее количество выводимых на монитор имен делегатов. Максимальное значение — 1000.

Используется для получения списка всех имен делегатов, зарегистрированных в блокчейне. В списке также выделяются имена делегатов, голосующих на данный момент. Задание параметров `lowerbound` и `limit` позволяет формировать страницу в удобной для просмотра форме. Для просмотра всего списка имен делегатов рекомендуется вначале значение `lowerbound` устанавливать в виде пустой строки (“”). Затем на каждой итерации параметру `lowerbound` передавать последнее возвращаемое имя делегата для следующего вызова `list_witnesses()`.\
Возвращает список всех зарегистрированных в блокчейне имен делегатов с соответствующими им идентификаторами, отсортированный по именам в алфавитном порядке.

## load\_wallet\_file()

```cpp
bool wallet_api::load_wallet_file(string wallet_filename)
```

Параметр:\
`wallet_filename` — имя файла кошелька в формате JSON, который загружается.

Используется для загрузки заданного кошелька платформы Graphene. Перед тем, как новый кошелек будет загружен, текущий кошелек закрывается. Если поле `wallet_filename` задано пустым, выполнится перезагрузка существующего файла кошелька.\
Возвращает “true”, если заданный кошелек успешно загружен.

## lock()

```cpp
void wallet_api::lock()
```

Используется для немедленного блокирования кошелька.

## normalize\_brain\_key()

```cpp
string normalize_brain_key(string s)
```

Параметр:\
`s` — brain-ключ в оригинальном формате.

Используется для преобразования формата brain-ключа с целью снижения риска возникновения ошибок при повторных вводах-выводах ключа из памяти.\
Оригинальный формат brain-ключа преобразуется в формат, используемый для генерации личных ключей. Новый формат содержит верхние регистры всех символов ASCII, а также упакованные последовательно идущие пробелы в один.\
Возвращает brain-ключ в нормализованном виде.

## post\_comment()

```cpp
annotated_signed_transaction wallet_api::post_comment(
        string author,
        string permlink,
        string parent_author,
        string parent_permlink,
        string title, string body,
        string json,
        bool broadcast
)
```

Параметры:\
`author` — имя аккаунта, являющего автором комментария;\
`permlink` — ссылка на комментарий;\
`parent_author` — имя аккаунта комментария верхнего уровня. Пустая строка означает верхний уровень комментария;\
`parent_permlink` — категория ссылки (для случая, если `parent_author` — пустая строка);\
`title` — заголовок комментария;\
`body` — тело комментария;\
`json` — метаданные комментария в формате JSON;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для публикации или обновления комментария.\
Возвращает подписанную транзакцию.

## preview\_builder\_transaction()

```cpp
transaction preview_builder_transaction(transaction_handle_type handle)
```

Параметр:\
`handle` — уникальный номер получаемого конструктора.

Возвращает уникальный номер для очередного создаваемого конструктора транзакций.

## propose\_builder\_transaction()

```cpp
signed_transaction propose_builder_transaction(
        transaction_handle_type handle,
        std::string author,
        std::string title,
        std::string memo,
        time_point_sec expiration,
        time_point_sec review_period_time,
        bool broadcast
)
```

Параметры:\
`handle` — уникальный номер создаваемого конструктора транзакций;\
`author` — автор предлагаемой транзакции;\
`title` — заголовок предлагаемой транзакции;\
`memo` — примечание, текст которого дополняет смысловое значение заголовка;\
`expiration` — время, по истечении которого прекращается подписание транзакции;\
`review_period_time` — период, выделенный для подписания транзакции;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для создания конструктора предлагаемых транзакций. Возвращает созданный конструктор транзакций под номером `handle`.

## publish\_feed()

```cpp
annotated_signed_transaction wallet_api::publish_feed(
        string witness,
        price exchange_rate,
        bool broadcast
)
```

Параметры:\
`witness` — делегат, публикующий ценовой тариф (потолок котировок);\
`exchange_rate` — предлагаемый курс обмена;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для публикации потолка котировок криптовалют.\
Делегат может публиковать потолок котировок криптовалют STEEM:SBD на бирже. Медианное значение этих котировок используется для обработки запросов на конвертацию SBD в STEEM.\
Возвращает подписанную транзакцию.

## quit()

```cpp
void wallet_api::quit()
```

Ипользуется для выхода из кошелька.

## recover\_account()

```cpp
annotated_signed_transaction wallet_api::recover_account(
        string account_to_recover,
        authority recent_authority,
        authority new_authority,
        bool broadcast
)
```

Параметры:\
`account_to_recover` — имя аккаунта; у которого восстанавливаются полномочия; `recent_authority` — недавние полномочия аккаунта; `new_authority` — новые полномочия, которые задаются в запросе на восстановление;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для восстановления полномочий (авторизацию) аккаунта с использованием запроса на восстановление, созданного самим аккаунтом. Синтаксис этой команды содержит сериализованный объект авторизации. Пример авторизации объекта показан в следующей строке:

```cpp
recover_account "account_to_recover"
    { " weight_threshold": 1,"account_auths": [], "key_auths": [["old_public_key",1]] }
    {"weight_threshold": 1,"account_auths": [], "key_auths": [["new_public_key",1]]} true
```

## remove\_builder\_transaction()

```cpp
void remove_builder_transaction(transaction_handle_type handle)
```

Параметр:\
`handle` — уникальный номер конструктора транзакций. Этот номер уменьшается на единицу после каждого вызова метода.

Используется для удаления конструктора транзакций по заданному идентификационному номеру.

## replace\_operation\_in\_builder\_transaction()

```cpp
void replace_operation_in_builder_transaction(
        transaction_handle_type handle,
        unsigned op_index,
        const operation& new_op
)
```

Параметры:\
`handle` — уникальный номер конструктора;\
`op_index` — номер операции в конструкторе транзакций, которую необходимо заменить;\
`op` — заменяющая операция.

Используется для замены операции под номером `op_index` в конструкторе транзакций на операцию `op`.

## request\_account\_recovery()

```cpp
annotated_signed_transaction wallet_api::request_account_recovery(
        string recovery_account,
        string account_to_recover,
        authority new_authority,
        bool broadcast
)
```

Параметры:\
`recovery_account` — имя аккаунта, создающего запрос на восстановление;\
`account_to_recover` — имя аккаунта, который необходимо восстановить;\
`new_authority` — новая авторизация “owner” для восстанавливаемого аккаунта;\
`broadcast` — “true”, если транзакция пересылается на демон.

Создает запрос на восстановление аккаунта. Синтаксис этой команды содержит сериализованный объект авторизации. Передача авторизации приведена в следующем примере:

```cpp
request_account_recovery "recovery_account" "account_to_recover" 
{"weight_threshold": 1,"account_auths": [],  "key_auths": [["new_public_key",1]]} true
```

## save\_wallet\_file()

```cpp
void wallet_api::save_wallet_file(string wallet_filename)
```

Параметр:\
`wallet_filename` — имя нового файла формата JSON, в который сохраняется кошелек.

Используется для сохранения кошелька в файл с заданным именем. Если поле `wallet_filename` задается пустым, кошелек сохраняется в старый файл. Для выполнения операции «Сохранить как …» следует использовать вызов `set_wallet_filename()`.

## serialize\_transaction()

```cpp
string wallet_api::serialize_transaction(signed_transaction tx)const
```

Параметр:\
`tx` — подписанная транзакция для сериализации.

Конвертирует подписанную транзакцию в формате JSON в ее бинарное представление.\
Возвращает подписанную транзакцию в бинарном представлении, имеющую вид неструктурированной (бесформенной) строки, в которой могут содержаться нулевые символы.

## set\_password()

```cpp
void wallet_api::set_password(string password)
```

Параметр:\
`password`— новый пароль.

Используется для установки нового пароля для кошелька. Кошелек должен быть либо новым, либо предварительно открытым командой `unlocked()`.

## set\_transaction\_expiration()

```cpp
void set_transaction_expiration(uint32_t seconds)
```

Параметр:\
`seconds` — период времени в секундах.

Возвращает заданный период времени (в секундах) в будущем, обозначающим срок действия транзакции.

## set\_voting\_proxy()

```cpp
signed_transaction set_voting_proxy(
        string account_to_modify,
        string voting_account,
        bool broadcast
)
```

Параметры:\
`account_to_modify`— имя или идентификационный номер аккаунта, чьи полномочия в голосовании изменяются;\
`voting_account` — имя аккаунта (заместитель), который наделяется полномочиями в голосовании. Пустая строка означает отсутствие заместителя;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для установки полномочий в голосовании для аккаунта. Если пользователь не желает принимать активное участие в голосовании, он может разрешить другому аккаунту (заместителю) использовать его долю голоса при голосовании. Наделение полномочиями заместителя в голосовании не удаляет предыдущие голоса аккаунта из блокчейна, они будут сохранены, но игнорированы. Если аккаунт позже аннулирует полномочия заместителя в голосовании, его предыдущие голоса снова вступят в силу.

## set\_withdraw\_vesting\_route()

```cpp
annotated_signed_transaction wallet_api::set_withdraw_vesting_route(
        string from,
        string to,
        uint16_t percent,
        bool auto_vest,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, с кошелька которого снимаются средства в виде VESTS;\
`to` — имя аккаунта, в кошелек которого возвращаются средства в виде VESTS или STEEM;\
`percent` — процент отчисления от суммы возвращаемых средств аккаунту с именем “to”. Это значение должно устанавливаться в пределах от 1 до 100000 включительно (например, 100 составляет 1 %, 10000 составляет 100 %);\
`auto_vest` — “true”, если аккаунт с именем “from” должен получить средства в виде VESTS, и “false”, если в виде STEEM;\
`broadcast` — “true”, если подписанную транзакцию необходимо переслать на демон.

Используется для настройки маршрута вывода средств, полученных по наделенным акциям. При возврате наделенных акций получаемые средства будут перенаправлены к аккаунтам с именами “from” и “to” в соответствии с указанными весовыми долями.

## sign\_builder\_transaction()

```cpp
signed_transaction wallet_api::sign_builder_transaction(
        transaction_handle_type handle,
        bool broadcast
)
```

Параметры:\
`handle` — уникальный номер конструктора транзакций;\
`broadcast` — “true”, если подписанные транзакции необходимо переслать на демон.

Используется для подписания всех транзакций в конструкторе транзакций. Возвращает подписанные транзакции в конструкторе транзакций под номером `handle`.

## sign\_transaction()

```cpp
annotated_signed_transaction wallet_api::sign_transaction(signed_transaction tx, bool broadcast)
```

Параметры:\
`tx` — транзакция; предоставленная на подпись;\
`broadcast` — “true”, если подписанную транзакцию необходимо переслать на демон.

Используется для предоставления на подпись полностью сформированную транзакцию. Транзакция подписывается необходимыми ключами и пересылается при необходимости на демон.\
Возвращает подписанную версию транзакции.

## suggest\_brain\_key()

```cpp
brain_key_info wallet_api::suggest_brain_key()const
```

Предлагает вариант безопасного brain-ключа для создания аккаунта. Используется для вызова метода `create_account_with_brain_key()`, который требует задания brain-ключа, а также длинную кодовую фразу, которая обеспечивает достаточную энтропию для генерации кипптографических ключей. Данный метод предложит сгенерированную случайным образом строку, которую следует сохранить.\
Возвращает предложенный вариант brain-ключа.

## transfer()

```cpp
annotated_signed_transaction wallet_api::transfer(
        string from,
        string to,
        asset amount,
        string memo,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, с кошелька которого будут переводиться средства;\
`to` — имя аккаунта, в кошелек которого будут переводиться средства;\
`amount` — сумма переводимых средств (например, 100.000 STEEM);\
`memo` — запись в транзакции, зашифрованная публичным ключом “memo”;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для перевода средств в виде STEEM или SBD с кошелька одного аккаунта в кошелек другого.

## transfer\_from\_savings()

```cpp
annotated_signed_transaction wallet_api::transfer_from_savings(
        string from,
        uint32_t request_id,
        string to,
        asset amount,
        string memo,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, инициировавшего передачу средств из сбережений;\
`request_id` — идентификационный номер операции, созданный аккаунтом `from`, который может быть использован для отмены операции, а также для ее повторного использования по завершении передачи;\
`to` — имя аккаунта, которому передаются средства;\
`amount` — сумма средств, подлежащих передачи;\
`memo` — текст примечания в транзакции, зашифрованный с помощью ключа `memo`;\
`broadcast` — "true", если транзакция пересылается на демон.

Возвращает подписанную транзакцию.

## transfer\_to\_savings()

```cpp
annotated_signed_transaction wallet_api::transfer_to_savings(
        string from,
        string to,
        asset amount,
        string memo,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, инициировавшего перевод;\
`to` — имя аккаунта, получающего перевод;\
`amount` — сумма переводимых средств;\
`memo` — запись в транзакции, зашифрованная ключом “memo” и оставленная аккаунтом, инициировавшим перевод;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для сбережения средств. Операция перевода средств на сбережение выполняется немедленно. Обратная операция (снятие сбережений) выполняется в течение 72 часов.\
Возвращает подписанную транзакцию.

## transfer\_to\_vesting()

```cpp
annotated_signed_transaction wallet_api::transfer_to_vesting(
        string from,
        string to,
        asset amount,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, от которого поступают средства в виде STEEM;\
`to` — имя аккаунта, к которому поступают средства в виде VESTS;\
`amount` — сумма средств в виде STEEM, выделяемая в инвестиционный фонд;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для передачи средств в виде STEEM в инвестиционный фонд, представленный наделяющими акциями (VESTS). VESTS обязаны облагаться отчислениями в размере не менее одного “coin” в год и еженедельным снятием средств в течение последующих двух лет.\
Возвращает подписанную транзакцию.

## try\_decrypt\_message()

```cpp
 message_body wallet_api::try_decrypt_message(const message_api_obj& mo )
```

Параметр:\
`mo` — объект API сообщения для расшифровки.

Используется для получения текстовых сообщений, зашифрованных с помощью личного ключа “memo”. Выполняет проверку текстового сообщения на контрольную сумму.\
Возвращает расшифрованный текст в случае соответствия ключа.

## try\_get\_private\_key()

```cpp
optional<fc::ecc::private_key> try_get_private_key(const public_key_type& id)const
```

Параметр:\
`id` — идентификационный номер публичного ключа.

Возвращает личный ключ в формате WIF, соответствующий публичному с заданным идентификационным номером, если публичный ключ имеется.

## unlock(string password)

```cpp
void wallet_api::unlock(string password)
```

Параметр:\
`password` — пароль, который ранее был установлен с помощью вызова `set_password()`.

Используется для разблокирования кошелька. Кошелек остается открытым до завершения работы программы либо до появления команды `lock()`.

## update\_account()

```cpp
annotated_signed_transaction wallet_api::update_account(
        string accountname,
        string json_meta,
        public_key_type owner,
        public_key_type active,
        public_key_type posting,
        public_key_type memo,
        bool broadcast
)const
```

Параметры:\
`accountname` — имя аккаунта;\
`json_meta` — новые метаданные поля “json\_meta”, относящиеся к аккаунту;\
`owner` — новый публичный ключ типа `owner` для аккаунта;\
`active` — новый публичный ключ типа `active` для аккаунта;\
`posting` — новый публичный ключ типа `posting` для аккаунта;\
`memo` — новый публичный ключ типа `memo` для аккаунта;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления метаданных и ключей существующего аккаунта.\
Возвращает подписанную транзакцию.

## update\_account\_auth\_account()

```cpp
annotated_signed_transaction wallet_api::update_account_auth_account(
        string account_name,
        authority_type type,
        string auth_account,
        weight_type weight,
        bool broadcast
)
```

Параметры:\
`account_name` — имя аккаунта, чьи полномочия (тип авторизации) следует обновить;\
`type` — тип авторизации (`owner`, `active` или `posting`);\
`auth_account` — имя аккаунта, чьими полномочиями наделяется аккаунт с именем `account_name`;\
`weight` — вес, который должен иметь `auth_account` для авторизации. Вес «0» означает удаление `auth_account`;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления полномочий существующего аккаунта в соответствии с полномочиями указанного аккаунта.\
Возвращает подписанную транзакцию.

## update\_account\_auth\_key()

```cpp
annotated_signed_transaction wallet_api::update_account_auth_key(
        string account_name,
        authority_type type,
        public_key_type key,
        weight_type weight,
        bool broadcast
)
```

Параметры:\
`account_name` — имя аккаунта, чьи полномочия (тип авторизации) следует обновить;\
`type` — тип авторизации (`owner`, `active` или `posting`);\
`key` — публичный ключ, который добавляется к авторизации аккаунта;\
`weight` — вес, который должен иметь публичный ключ в авторизации. Вес «0» означает удаление ключа;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления ключа авторизации для существующего аккаунта.\
Возвращает подписанную транзакцию.

## update\_account\_auth\_threshold()

```cpp
annotated_signed_transaction wallet_api::update_account_auth_threshold(
        string account_name,
        authority_type type,
        uint32_t threshold,
        bool broadcast
)
```

Параметры:\
`account_name` — имя аккаунта, чьи полномочия (тип авторизации) следует обновить;\
`type` — тип авторизации (`owner`, `active` или `posting`);\
`threshold` — пороговое значение веса, необходимое для авторизации;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления порогового значения веса авторизации для существующего аккаунта.\
Возвращает подписанную транзакцию.

## update\_account\_memo\_key()

```cpp
 annotated_signed_transaction wallet_api::update_account_memo_key(
         string account_name,
         public_key_type key,
         bool broadcast
 )
```

Параметры:\
`account_name` — имя аккаунта, чей ключ будет обновлен;\
`key` — новый публичный ключ `memo`;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления публичного ключа `memo` для существующего аккаунта.\
Возвращает подписанную транзакцию.

## update\_account\_meta()

```cpp
        annotated_signed_transaction wallet_api::update_account_meta(
        string account_name,
        string json_meta,
        bool broadcast
)
```

Параметры:\
`account_name` — имя аккаунта, чьи метаданные будут обновлены;\
`json_meta` — новые метаданные JSON для аккаунта;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления метаданных JSON для существующего аккаунта.\
Возвращает подписанную транзакцию.

## update\_chain\_properties()

```cpp
annotated_signed_transaction wallet_api::update_chain_properties(
        string witness_account_name,
        const optional_chain_props& props,
        bool broadcast
)
```

Параметры:\
`witness_account_name` — имя делегата;\
`props` — перечень новых возможностей блокчейна, за которые голосует делегат;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для принятия новых возможностей блокчейна голосованием отдельного делегата.\
Возвращает подписанную транзакцию.

## update\_witness()

```cpp
annotated_signed_transaction wallet_api::update_witness(
        string witness_name,
        string url,
        public_key_type block_signing_key,
        optional<chain_properties> props,
        bool broadcast
)
```

Параметры:\
`witness_name` — имя делегата;\
`url` — адрес URL, содержащий некоторую информацию о делегате. Пустая строка означает, что старая информация о делегате является актуальной;\
`block_signing_key` — публичный ключ для подписи нового блока. Значение в виде пустой строки блокирует блок;\
`props` — перечень новых возможностей блокчейна, за которые голосует делегат;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для обновления объекта, принадлежащего делегату с именем `witness_name`. Возвращает подписанную транзакцию.

## vote()

```cpp
annotated_signed_transaction wallet_api::vote(
        string voter,
        string author,
        string permlink,
        int16_t weight,
        bool broadcast
)
```

Параметры:\
`voter` — имя голосующего аккаунта;\
`author` — автор комментария, за который нужно проголосовать;\
`permlink` — ссылка на комментарий, за который нужно проголосовать;\
`weight` — вес голоса. Значение должно быть отличным от нуля и находиться в пределах от -100 до 100 включительно;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для голосования за комментарий, оплачиваемый в STEEM.\
Возвращает подписанную транзакцию.

## vote\_for\_witness()

```cpp
 annotated_signed_transaction wallet_api::vote_for_witness(
        string account_to_vote_with,
        string witness_to_vote_for,
        bool approve,
        bool broadcast
)
```

Параметры:\
`account_to_vote_with` — имя аккаунта, голосующего за делегата;\
`witness_to_vote_for` — делегат, за которого идет голосование;\
`approve` — “true”, если аккаунт голосует за делегата;\
`broadcast` — “true”, если транзакция пересылается на демон.

Используется для голосования за конкретного делегата. По умолчанию считается, что аккаунт не отдал ни позитивный, ни негативный голос за делегата. Аккаунту предоставляется возможность отдать либо позитивный, либо негативный голос. Голосование продолжается до тех пор, пока не будет предложено новое голосование.\
Возвращает подписанную транзакцию.

## withdraw\_vesting()

```cpp
annotated_signed_transaction wallet_api::withdraw_vesting(
        string from, asset vesting_shares,
        bool broadcast
)
```

Параметры:\
`from` — имя аккаунта, с кошелька которого снимаются средства в виде VESTS;\
`vesting_shares` — сумма средств в виде VESTS, которая будет еженедельно сниматься с кошелька аккаунта в течение следующих двух лет (сумма / 104 акции) и зачисляться на депозит в виде VESTS;\
`broadcast` — “true”, если транзакция пересылается на демон.

Настраивает запрос на вывод средств. Запрос выполняется один раз в неделю в течение последующих двух лет. Возвращает подписанную транзакцию.


# Обновления (HardForks)

* [HF18: Руководство по установке](/developers/hardforks/hf18_instruction)
* [HF18: Новые возможности](/developers/hardforks/hf18_release)
* [HF18: Изменения в API](/developers/hardforks/hf18_api_changes)
* [HF18: Изменения в cli\_wallet](/developers/hardforks/hf18_cli_wallet_changes)
* [SF18.4: Новые возможности](/developers/hardforks/sf18.4_release)
* [HF19: Новые возможности](/developers/hardforks/hf19_release)
* [HF20: Устранение критического бага](/developers/hardforks/hf20_release)
* [HF22: Новые возможности](/developers/hardforks/hf22_release)
* [HF23: Новые возможности](/developers/hardforks/hf23_release)
* [HF24: Новые возможности](/developers/hardforks/hf24-novye-vozmozhnosti)
* [HF25: Новые возможности](/developers/hardforks/hf25_release)
* [HF26: Новые возможности](/developers/hardforks/hf26_release)
* [HF27: Новые возможности](/developers/hardforks/hf27-novye-vozmozhnosti)
* [HF28: Новые возможности](/developers/hardforks/hf28-novye-vozmozhnosti)

  <br>


# HF18: Данные по установке

Документ содержит инструкцию по начальной установке и запуску, а также обновлению программного продукта GolosChain на сервере под управлением операционной системы Ubuntu 16.04 либо иной системы семейства Linux с помощью программного обеспечения Docker.

### Способы установки HF•18

Установку HF•18 на сервер можно выполнить в одном из следующих вариантов:\
1\. установка с использованием доступной платформы [Docker](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_412);\
2\. изначальное построение непосредственно из исходников golosd под управлением операционной системы Ubuntu;\
3\. обновление GolosChain до версии HF•18 из исходников golosd под управлением операционной системы Ubuntu.

Инструкции по установке HF•18 в вариантах 1-3 изложены в разделах [2](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_2), [3](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_3) и [4](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_4) соответственно.

Рекомендуется установку HF•18 выполнять в варианте 1, поскольку использование платформы Docker обеспечивает:

* создание необходимого программного окружения, в том числе необходимого перечня библиотек, независимо от версии операционной системы; &#x20;
* создание среды, изолированной от ненужных временных файлов, сохраняемых системой в строящемся пространстве. &#x20;

### Рекомендации к характеристикам аппаратных и программных средств

Сервер, на который устанавливается HF•18, должен иметь характеристики не хуже:

* объем оперативной памяти: &#x20;
  * 16 ГБ для [делегатского Узла](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_410) в варианте конфигурации LOWMEM; &#x20;
  * 64 ГБ для [API Узла](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_411) в полной конфигурации; &#x20;
* объем дисковой памяти: 80 ГБ для API Узла в полной конфигурации; &#x20;
* операционная система: &#x20;
  * Ubuntu версии 16.04 (или более поздней); &#x20;
  * Linux-система (для установки HF•18 с использованием платформы Docker). &#x20;

Программный код golosd поддерживает следующие программные обеспечения:

* базовая библиотека: boost версии 1.58; &#x20;
* компилятор GCC версии 5.х (с поддержкой стандарта С++14).

### Иные рекомендации

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

* сохранить код личного ключа; &#x20;
* отключить функцию подписания блоков отключением [плагина](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_48) witness; &#x20;
* остановить и удалить предыдущую версию GolosChain (только для обновления версии), используя следующие команды:

  ```
  docker stop golos-default
  docker rm golos-default
  ```

## Раздел\_2 Установка HF•18 с использованием платформы Docker

Для построения HF•18 требуется сервер с операционной системой Ubuntu 16.04 и определенным набором библиотек. В случае отсутствия сервера с требуемой операционной системой следует воспользоваться сервером с операционной системой семейства Linux. Имеется возможность установки HF•18 на такой сервер с помощью платформы Docker, обеспечивающий создание необходимого окружения, независимо от версии системы Linux.

Установка и функционирование HF•18 на сервер под управлением каких-либо иных классов систем не поддерживается.

Для установки HF•18 на сервер с использованием платформы Docker необходимо выполнить следующие операции:\
1\. сконфигурировать [Docker-образ](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_413) в отдельном пространстве;\
2\. создать [контейнер](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_46) с использованием Docker-образа. Контейнер можно размещать как на локальном компьютере, так и на удаленном или виртуальном;\
3\. [воспроизвести блокчейн](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_43).

### Конфигурирование Docker-образа

**1.** Создать репозиторий `golosd` в отдельном пространстве и установить значения переменных в конфигурационных файлах.

**2.** В командном окне войти в директорию, в которой будет создан Docker-образ, и исполнить:

```
git clone https://github.com/golos-blockchain/golos.git
```

В пространство, из которого была исполнена команда, должен скопироваться каталог `golos` с его содержимым. В процессе копирования не должны появляться сообщения об ошибках.

**3.** Создать отдельную директорию для конфигурационных файлов, исполнив:

```
sudo mkdir -p /etc/golosd
```

**4.** В созданную директорию `/etc/golosd` скопировать конфигурационные файлы. Используемые для копирования команды:

```
cd golos
sudo cp share/golosd/seednodes /etc/golosd/
sudo cp share/golosd/config/config.ini /etc/golosd/
```

В директории `golosd` находятся несколько конфигурационных файлов, данные которых можно использовать в качестве базовых для создания необходимого окружения. В следующей таблице приведен перечень основных конфигурационных файлов и их назначение.

| Конфигурационный файл                           | Назначение                                                                                                                          |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| share/golosd/config/config.ini                  | Содержит набор переменных для создания API Узла в полной его конфигурации со всеми включенными плагинами                            |
| share/golosd/config/config\_witness.ini         | Содержит набор переменных для создания делегатского Узла в конфигурации по умолчанию. Используется делегатами для подписания блоков |
| share/golosd/config/config\_stock\_exchange.ini | Содержит набор переменных для создания Узла для биржевых операций в конфигурации по умолчанию                                       |

Поскольку golosd обрабатывает конфигурационный файл только с именем `config.ini`, то в зависимости от решаемой задачи следует выбрать необходимый конфигурационный файл и скопировать значения его переменных окружения в `share/golosd/config/config.ini`.

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

| Переменная окружения | Назначение                                                                                                                                                                                                     |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| witness              | Устанавливает имя [аккаунта](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_41) делегата (для делегатского Узла) |
| private-key          | Задает код личного ключа `active` (для делегатского Узла). Тип ключа может быть отличным от `active`                                                                                                           |
| plugin               | Определяет перечень плагинов. Неиспользуемые плагины могут быть удалены                                                                                                                                        |

Количество задаваемых плагинов в переменной `plugin` влияет на объем используемой памяти, а также быстродействие Узла. Минимальный набор плагинов приведен в файле `config_witness.ini`.

**5.** Создать директорию для размещения в ней блокчейна, исполнив:

```
sudo mkdir -p /var/lib/golosd/
```

**6.** В созданную директорию скопировать исходный genesis-файл, исполнив:

```
sudo cp share/golosd/snapshot5392323.json /var/lib/golosd/
```

### Запуск Docker-образа из GolosCore

Docker-образ размещается на общедоступном реестре Docker Hub либо создается локально из исходников GolosCore. Из Docker-образа можно создать контейнер на физическом устройстве, на котором установлен Docker. Docker-образ представляет собой тиражируемый образ некоторого объекта, а создаваемый контейнер является самим объектом, который можно запускать и останавливать. Контейнер является изолированным от внешней среды со своими переменными окружения и параметрами запуска. В среде контейнера исполняется [Узел](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_49). Для запуска одного и того же Узла требуется создание другого контейнера.

Для запуска Docker-образа из GolosCore и создания контейнера исполнить следующую командную строку:

```
sudo docker run -d \
    -p 4243:4243 \
    -p 8090:8090 \
    -p 8091:8091 \
    -v /etc/golosd:/etc/golosd \
    -v /var/lib/golosd:/var/lib/golosd \
    --name golos-default  golosblockchain/golos:latest
```

где:\
`-d` — устанавливает запуск контейнера в фоновом режиме;\
`-p` — устанавливает привязку конкретных портов хоста к портам контейнера;\
`--name` — задает имя контейнера (`golos-default`);\
`latest` — задает последнюю официальную версию golosd.

Для проверки успешного запуска контейнера исполнить команду

```
sudo docker ps
```

Создание контейнера считается успешным, если в тексте лог-файла не было сообщений об ошибках и в выдаче этой команды появится имя контейнера golos-default с соответствующими портами.

### Воспроизведение блокчейна

Перед тем, как приступить к непосредственному воспроизведению блокчейна, убедиться в наличии файлов `/var/lib/golosd/blockchain/block_log` и `/var/lib/blockchain/block_log.index`.

В файле `block_log` хранится список подписанных блоков с транзакциями. В каждой из транзакций содержится перечень операций, которые необходимо выполнить для восстановления состояния системы. Все блоки взаимосвязаны между собой. В процессе появления новых блоков они считываются по сети, добавляются в этот файл и могут быть использованы в дальнейшем. Файл представляет собой протокол всех операций, как ранее совершенных системой,так и последующих.

В файле `shared_memory.bin` хранятся данные о состоянии системы, а также непосредственно база данных, в том числе таблицы с записями и индексы, по которым происходит обращение к ячейкам таблицы.

В каждом из плагинов, подобно структуре файла `shared_memory.bin`, содержатся таблицы и индексы, требующие из наполнения с самого начала истории. Во время включения дополнительного плагина его поля остаются пустыми и для их заполнения требуется воспроизведение всех операций из `block_log` с самого начала. Этот процесс состоит из множества операций, требующий обработку каждого блока.

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

Для воспроизведения блокчейна необходимо следовать следующим указаниям.

**1.** Убедиться, что процессы контейнера golos-default завершены, используя следующую командную строку:

```
sudo docker ps | grep golos-default
```

Если имеется незавершенный процесс, его необходимо остановить, исполнив:

```
sudo docker stop golos-default
```

**2.** Запустить контейнер, используя в качестве основы образ, исполнив:

```
sudo docker run -d \
    -p 4243:4243 \
    -p 8090:8090 \
    -p 8091:8091 \
     -v /etc/golosd:/etc/golosd \
    -v /var/lib/golosd:/var/lib/golosd \
    --name golos-default  golosblockchain/golos:latest
```

где:\
`golos-default` — имя контейнера;\
`latest` — задает последнюю официальную версию golosd.

**3.** Воспроизвести блокчейн посредством запуска скрипта `golosdctl` внутри запущенного контейнера `golos-default`:

```
sudo docker exec golos-default /usr/local/bin/golosdctl replay
```

**4.** Выполнить проверку успешной установки Узла.

* Открыть лог-файл и убедиться в следующих фактах: &#x20;
  * в файл прекращено поступление новой информации; &#x20;
  * текст файла не содержит сообщения об ошибках. &#x20;
* Подключиться к Узлу через `cli_wallet` по порту 8091, исполнив:

  ```
  sudo docker exec -ti golos-default \
    /usr/local/bin/cli_wallet \
    --wallet="/var/lib/golosd/wallet.json" \
    --server-rpc-endpoint="ws://127.0.0.1:8091"
  ```

  Успешное подключение будет означать успешную установку Узла.

### Построение Docker-образа с использованием Docker-файла

В этом разделе приведена инструкция по построению Docker-образа с использованием различных [Docker-файлов](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_414).

Docker-файл представляет собой текстовый файл с инструкциями, необходимыми для создания образа контейнера. Образ строится автоматически последовательным выполнением команд, приведенных в файле.

Docker-образ образует многоуровневую последовательность операций, каждый уровень которой представляет собой инструкции Docker-файла. Каждая инструкция создает отдельный уровень Docker-образа. При запуске Docker-образа и создании контейнера добавляется очередной уровень для записи изменений поверх нижнего уровня.

В зависимости от решаемой задачи можно построить Узел с соответствующими для этой задачи параметрами. В этом случае Docker-образ может быть построен с использованием одного из Docker-файлов, размещенных в каталоге `share/golosd/docker/`. Пользователю также предоставляется возможность самостоятельно создавать Docker-файл с необходимыми для его нужд параметрами для построения соответствующего контейнера.

В следующей таблице приведен перечень основных Docker-файлов и их назначение.

| Docker-файл                                 | Назначение                                                                                                                                                        |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Dockerfile                                  | Содержит набор инструкций и переменных для создания Docker-образа по умолчанию                                                                                    |
| share/golosd/docker/Dockerfile-small        | Docker-файл с инструкциями одного уровня. Позволяет создать Docker-образ меньшего размера относительно Docker-образа, построенного по умолчанию                   |
| share/golosd/docker/Dockerfile-lowmem       | Содержит набор переменных, направленных на экономию ресурсов, в том числе потребление памяти. Позволяют сконфигурировать Узел, не сохраняющий посты и комментарии |
| share/golosd/docker/Dockerfile-lowmem-small | Docker-файл с инструкциями одного уровня. Содержит набор переменных, позволяющих снизить потребление памяти                                                       |

Для построения Docker-образа необходимо следовать следующим указаниям.

**1.** Удалить ранее установленный образ, исполнив:

```
sudo docker image rm local/golos
```

**2.** Выбрать из размещенного в каталоге `share/golosd/docker/` набора нужный Docker-файл и построить Docker-образ, используя следующую команду:

```
sudo docker build -t local/golos -f Dockerfile
```

**3.** Запустить контейнер, исполнив:

```
sudo docker run -d \
    -p 4243:4243 \
    -p 8090:8090 \
    -p 8091:8091 \
    -v /etc/golosd:/etc/golosd \
    -v /var/lib/golosd:/var/lib/golosd \
    --name golos-default  local/golos
```

где:\
`golos-default` — имя запущенного контейнера;\
`local/golos` — показывает, что построение Docker-образа выполняется с использованием сети.

### Перечень команд, применяемых к любому виду контейнера

**1.** Доступ к контейнеру:

```
sudo docker exec -ti golos-default /bin/bash
```

**2.** Получение текста лог-файла о контейнере:

```
sudo docker logs --tail 10 -f golos-default
```

**3.** Воспроизведение контейнера:

```
sudo docker exec golos-default /usr/local/bin/golosdctl replay
```

**4.** Подключение через cli\_wallet к Узлу для проверки его функционирования:

```
sudo docker exec -ti golos-default \
    /usr/local/bin/cli_wallet \
    --wallet="/var/lib/golosd/wallet.json" \
    --server-rpc-endpoint="ws://127.0.0.1:8091"
```

**5.** Запуск контейнера:

```
sudo docker start golos-default
```

**6.** Останов контейнера:

```
sudo docker stop golos-default
```

## Раздел\_3 Обновление до новой версии

В этом разделе приведена инструкция по обновлению ранее установленного GolosChain до его новой версии HF•18.&#x20;

Для обновления GolosChain необходимо следовать следующим указаниям.

**1.** Обновить исходные файлы, исполнив:

```
git clone https://github.com/golos-blockchain/golos.git
cd golos
git submodule update --init --recursive -f
```

**2.** Задать значения макро-переменных и сконфигурировать проект, исполнив:

```
mkdir build
cd build
cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_GOLOS_TESTNET=FALSE \
    -DBUILD_SHARED_LIBRARIES=FALSE \
    -DLOW_MEMORY_NODE=FALSE \
    -DCHAINBASE_CHECK_LOCKING=FALSE \
    ..
```

**3.** Построить проект с установкой [демона](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_buildinstruction-rus.md#bld_45) в `/usr/local/`, исполнив:

```
make -j $(nproc)
sudo make install
```

**4.** Открыть конфигурационный файл `share/golosd/config/config.ini` и установить в нем значения переменных окружения. В зависимости от решаемых задач можно установить значения переменных окружения, обеспечивающих создание Узлов следующих типов:

* API Узел в полной конфигурации со всеми включенными плагинами; &#x20;
* Узел делегатский, содержащий минимальный набор включенных плагинов; &#x20;
* Узел в произвольной конфигурации с произвольным набором включенных плагинов. &#x20;

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

| Переменная окружения | Назначение                                                                                           |
| -------------------- | ---------------------------------------------------------------------------------------------------- |
| witness              | Устанавливает имя аккаунта делегата (для делегатского Узла)                                          |
| private-key          | Задает код личного ключа `active` (для делегатского Узла). Тип ключа может быть отличным от `active` |
| plugin               | Определяет перечень плагинов. Неиспользуемые плагины могут быть удалены                              |

Количество задаваемых плагинов в переменной `plugin` влияет на объем используемой памяти, а также быстродействие Узла. Минимальный набор плагинов приведен в файле `config_witness.ini`.

**5.** Остановить незавершенные процессы старой версии на демоне. В зависимости от конфигурации останов может быть выполнен различными способами, например, с помощью следующих команд:

```
pkill -15 golosd
sudo sv stop golosd
```

**6.** Воспроизвести блокчейн. Предварительно убедиться в наличии файлов `/var/lib/golosd/blockchain/block_log` и `/var/lib/blockchain/block_log.index`, в которых хранятся блоки и данные о состоянии системы и плагинов. Использование данных этих файлов избавляет от выполнения длительной операции синхронизации блоков по сети и, следовательно, сокращает время воспроизведения блокчейна.

Исполнить:

```
/usr/local/bin/golosd --replay-blockchain
```

**7.** Выполнить проверку успешного обновления GolosChain

* Открыть лог-файл и убедиться в следующих фактах: &#x20;
  * в файл прекращено поступление новой информации; &#x20;
  * текст файла не содержит сообщения об ошибках. &#x20;
* Подключиться к Узлу через cli\_wallet по порту 8091, исполнив:

  ```
  /usr/local/bin/cli_wallet \
    --wallet="/var/lib/golosd/wallet.json" \
    --server-rpc-endpoint="ws://127.0.0.1:8091"
  ```

  Успешное подключение к Узлу будет означать успешное обновление.

## Раздел\_4 Изначальная установка блокчейна

Для установки обновленной версии GolosChain необходимо следовать следующим указаниям.

**1.** Создать на сервере пространство для размещения в нем репозитория golosd.

**2.** Установить необходимые пакеты. Система Ubuntu 16.04 обеспечивает автоматический поиск в сети требуемого набора пакетов и загрузку их в соответствующие им директории. Для этого необходимо исполнить:

```
sudo apt-get update
```

```
sudo apt-get install -y \
        autoconf \
        automake \
        autotools-dev \
        bsdmainutils \
        build-essential \
        cmake \
        doxygen \
        git \
        ccache \
        libboost-all-dev \
        libreadline-dev \
        libssl-dev \
        libtool \
        ncurses-dev \
        pbzip2 \
        pkg-config \
        python3 \
        python3-dev \
        python3-pip \
        runit
```

```
sudo pip3 install gcovr
```

**3.** В отведенное для репозитория место скопировать исходные файлы из github, используя следующие команды:

```
git clone https://github.com/golos-blockchain/golos.git && cd golos
```

```
git submodule update --init --recursive -f
```

В процессе копирования не должны появляться сообщения об ошибках.

**4.** Задать значения макро-переменных и сконфигурировать проект, используя следующие команды:

```
mkdir build && cd build
```

```
cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_GOLOS_TESTNET=FALSE \
    -DBUILD_SHARED_LIBRARIES=FALSE \
    -DLOW_MEMORY_NODE=FALSE \
    -DCHAINBASE_CHECK_LOCKING=FALSE \
    ..
```

**5.** Построить проект с установкой демона в `/usr/local/`, исполнив:

```
make -j $(nproc) && sudo make install
```

{% hint style="info" %}
Если была нужна сборка **cli\_wallet**, последующие шаги не требуются, достаточно [запустить приложение](/witnesses/node/guide-exchange#samostoyatelnaya-sborka-cli_wallet).
{% endhint %}

**6.** Создать пользователя с именем golosd для демона:

```
sudo useradd -s /bin/bash -m -d /var/lib/golosd golosd
```

**7.** Скопировать исходный файл genesis формата JSON для блокчейна, исполнив:

```
sudo cp ../share/golosd/snapshot5392323.json /var/lib/golosd/
```

**8.** Создать директорию golosd в `/etc/` и скопировать в нее конфигурационные файлы:

```
sudo mkdir -p /etc/golosd
sudo cp ../share/golosd/seednodes /etc/golosd/
sudo cp ../share/golosd/config/config.ini /etc/golosd/
```

**9.** Сменить имя владельца скопированным конфигурационным файлам:

```
sudo chown golosd:golosd -R /etc/golosd/
```

**10.** Создать сервисный файл для демона:

```
sudo mkdir -p /etc/service/golosd
sudo cp ../share/golosd/golosd.sh /etc/service/golosd/run
sudo chmod +x /etc/service/golosd/run
```

**11.** Запустить функционирование GolosChain, исполнив:

```
sudo sv start golosd
```

**12.** Выполнить проверку успешной установки.

* Открыть лог-файл и убедиться в следующих фактах: &#x20;
  * в файл прекращено поступление новой информации; &#x20;
  * текст файла не содержит сообщения об ошибках. &#x20;
* Подключиться к Узлу через cli\_wallet по порту 8091, исполнив:

  ```
  /usr/local/bin/cli_wallet \
    --wallet="/var/lib/golosd/wallet.json" \
    --server-rpc-endpoint="ws://127.0.0.1:8091"
  ```

Успешное подключение к Узлу будет означать успешную установку GolosChain.


# HF18: Новые возможности

* [1. Делегирование Силы Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#1-делегирование-силы-голоса) &#x20;
  * [1.1. Операция делегирования Силы Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#11-операция-делегирования-силы-голоса) &#x20;
  * [1.2. Изменение или возврат делегированной Силы Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#12-изменение-или-возврат-делегированной-силы-голоса) &#x20;
  * [1.3. Создание аккаунта с делегированной Силой Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#13-создание-аккаунта-с-делегированной-силой-голоса) &#x20;
* [2. Предотвращение злоупотреблений делегированием Силы Голоса с целью обогащения](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#2-предотвращение-злоупотреблений-делегированием-силы-голоса-с-целью-обогащения) &#x20;
* [3. Улучшение способа определения биржевого курса и соотношения криптовалют](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#3-улучшение-способа-определения-биржевого-курса-и-соотношения-криптовалют) &#x20;
* [4. Редактирование профиля пользователя с использованием ключа posting](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#4-редактирование-профиля-пользователя-с-использованием-ключа-posting) &#x20;
* [5. Предложение на транзакцию, состоящей из нескольких операций](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#5-предложение-на-транзакцию-состоящей-из-нескольких-операций) &#x20;
  * [5.1. Предложение на транзакцию](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#51-предложение-на-транзакцию) &#x20;
  * [5.2. Обновление предложенной транзакции](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#52-обновление-предложенной-транзакции) &#x20;
  * [5.3. Удаление предложенной транзакции](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#53-удаление-предложенной-транзакции) &#x20;
  * [5.4. Эффективность предложенной транзакции](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#54-эффективность-предложенной-транзакции) &#x20;
* [6. Редактирование постов и комментариев к ним независимо от времени их публикации](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#6-редактирование-постов-и-комментариев-к-ним-независимо-от-времени-их-публикации) &#x20;
* [7. Расширение перечня параметров блокчейна, значения которых определяются голосованием](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#7-расширение-перечня-параметров-блокчейна-значения-которых-определяются-голосованием) &#x20;
* [8. Повышение быстродействия системы за счет размещения в разных объектах полей с часто и редко используемыми данными](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#8-повышение-быстродействия-системы-за-счет-размещения-в-разных-объектах-полей-с-часто-и-редко-используемыми-данными) &#x20;
* [9. Повышение производительности API протокола за счет удаления неиспользуемых полей из методов плагинов, а также за счет перераспределения методов между плагинами для более эффективного их использования](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#9-повышение-производительности-api-протокола-за-счет-удаления-неиспользуемых-полей-из-методов-плагинов-а-также-за-счет-перераспределения-методов-между-плагинами-для-более-эффективного-их-использования) &#x20;
  * [9.1. Удаление неиспользуемых полей из методов плагинов](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#91-удаление-неиспользуемых-полей-из-методов-плагинов) &#x20;
  * [9.2. Размещение индексных операций по блокам и аккаунтам в отдельных плагинах](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#92-размещение-индексных-операций-по-блокам-и-аккаунтам-в-отдельных-плагинах) &#x20;
* [10. Использование тэгов при формировании запросов на получение необходимой информации](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#10-использование-тэгов-при-формировании-запросов-на-получение-необходимой-информации) &#x20;
* [11. Получение информации о текущем статусе разделяемой памяти](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#11-получение-информации-о-текущем-статусе-разделяемой-памяти) &#x20;
* [12. Постраничный просмотр личных сообщений пользователя](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#12-постраничный-просмотр-личных-сообщений-пользователя) &#x20;
* [13. Улучшения в подсистеме хранения блоков цепочки](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/hf18_releasenotice-rus.md#13-улучшения-в-подсистеме-хранения-блоков-цепочки) &#x20;

## 1. Делегирование Силы Голоса

### 1.1. Операция делегирования Силы Голоса

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

Пользователь (кредитор) может неиспользуемую часть Силы Голоса кредитовать на время (делегировать) другому пользователю, который также может ее использовать по своему усмотрению. Кредитор Силы Голоса при этом получает дополнительную возможность голосования за пост и, следовательно, возможность получения дополнительного бонуса.

Для выполнения операции делегирования кредитору Силы Голоса необходимо сформировать массив значений — блок делегирования с указанием типа операции, отправителя, получателя, сумма делегирования и пр.

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

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

### 1.2. Изменение или возврат делегированной Силы Голоса

Кредитор Силы Голоса в случае каких-либо обстоятельств может изменить количество делегированного как в сторону его увеличения, так и уменьшения, а также осуществить возврат делегированного в полном объеме.

Для выполнения этой операции в сформированном блоке делегирования необходимо задать новое значение количества делегированной Силы Голоса. В случае полного ее возврата следует задать значение вида “0.000000 GESTS”. При изменении значения в сторону уменьшения делегированная Сила Голоса сразу снимается с аккаунта-получателя и переходит в «замороженное» состояние сроком на 7 дней.

Для выполнения этой операции требуется авторизация с помощью ключа `active`.

### 1.3. Создание аккаунта с делегированной Силой Голоса

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

Для того, чтобы пользователь нового аккаунта мог создавать посты, комментарии, а также участвовать в голосовании, необходимо, чтобы на балансе кошелька нового аккаунта появилась криптовалюта Сила Голоса в количестве не менее базового значения `fee`. Для этого с баланса кошелька создателя аккаунта снимается криптовалюта в виде Голоса и зачисляется на баланс кошелька нового аккаунта в виде Силы Голоса.

Вводится параметр `bandwidth`, устанавливающий пропускную способность аккаунта — количество операций, выполняемых пользователем за определенный период времени. Этот параметр зависит только от баланса Силы Голоса. Наличие в кошельке других видов криптовалюты (Голоса и Золотого) не оказывает на него влияния. Этот параметр ограничивает активность пользователя и не позволяет ему слишком часто создавать комментарии, принимать участие в голосовании или выполнять какие-либо другие операции.

Для операции создания аккаунта с делегированием необходима подпись ключом `active`. Созданный аккаунт может иметь ключи owner, `active`, `posting` и `memo`.

**Примечания:**\
1\. Затрачиваемое на создание аккаунта количество криптовалюты не может быть возвращено обратно в кошелек создателя.

1. Создатель аккаунта может делегировать часть Силы Голоса на новый аккаунт. В этом случае делегированная часть будет также списана с баланса Силы Голоса его кошелька и зачислена на баланс Силы Голоса нового аккаунта. Делегированная Сила Голоса может быть возвращена в кошелек создателя через определенный период, длительность которого определяется голосованием. &#x20;

## 2. Предотвращение злоупотреблений делегированием Силы Голоса с целью обогащения

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

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

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

## 3. Улучшение способа определения биржевого курса и соотношения криптовалют

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

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

В версии HF•18 старые значения курса удаляются из базы данных блокчейна и не участвуют в определении текущего курса криптовалют. Данная реализация обеспечивает более правильную ценовую политику Голоса и Золотого на биржевых торгах.

## 4. Редактирование профиля пользователя с использованием ключа posting

В предыдущих версиях блокчейна редактирование любого поля профиля пользователя возможно было только с использованием ключа `active`. Поскольку этот ключ предназначен для выполнения наиболее ответственных операций, его использование для редактирования часто используемых полей профиля не всегда было приемлемым.

Для устранения этого недостатка в версии HF•18 принято решение разделить поля профиля на две группы. В состав первой группы вошли поля с наиболее значимыми данными профиля (ключи: `posting`, `active`, `owner` и `memo`), а в другую — с менее значимыми, но часто используемыми (аватар, пол, местонахождение и пр.). Процедура изменения полей первой группы сохранена и возможна только с использованием ключа `active`. Процедура редактирования полей второй группы изменена и возможна с использованием ключа `posting`, что является наиболее приемлемым для пользователя.

## 5. Предложение на транзакцию, состоящей из нескольких операций

### 5.1. Предложение на транзакцию

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

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

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

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

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

### 5.2. Обновление предложенной транзакции

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

Время на принятие решения участников транзакции ограничено и не может превышать максимально отведенное время на выполнение транзакции. Если транзакция не получает одобрения на выполнение какой-либо из операций, эта транзакция не отменяется и ее актуальность будет сохраняться до отведенного на ее выполнение времени. Как только все необходимые подписи будут получены, транзакция незамедлительно будет выполняться и, независимо от дальнейших решений участников транзакции, все последующие обновления будут считаться недействительными.

### 5.3. Удаление предложенной транзакции

В случае отказа кого-либо из участников транзакции на выполнение операции он может сформировать на блокчейне запрос на удаление предложенной транзакции. Удалить предложенную транзакцию может как ее автор, так и любой ее участник, имеющий право на подпись. Если хотя бы один из участников транзакции формирует запрос на ее удаление, то, независимо от подписей остальных участников, данная транзакция будет удалена.

### 5.4. Эффективность предложенной транзакции

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

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

## 6. Редактирование постов и комментариев к ним независимо от времени их публикации

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

В версии HF•18 этот недостаток устранен. Ограничение на выделенное для редактирования время не действует и, следовательно, в комментарии и посты всегда можно вносить свежую информацию и содержать их в актуальном состоянии.

## 7. Расширение перечня параметров блокчейна, значения которых определяются голосованием

Предыдущие версии блокчейна обеспечивали поддержку операции `witness_update`, с помощью которой определялись значения некоторых параметров делегатами Голоса по результатам голосования. В этот перечень входили следующие параметры:\
1\. `account_creation_fee` — размер комиссионных отчислений, требуемых на создание аккаунта без делегирования;\
2\. `maximum_block_size` — максимальный размер блока блокчейна;\
3\. `sbd_interest_rate` — процент, начисляемый на SBD.

Недостаток заключался в том, что использование операции `witness_update` не позволяло расширить перечень таких параметров.

В версии HF•18 реализована новая операция `chain_properties_update`, которая поддерживает более расширенный перечень параметров, значения которых определяются голосованием делегатов Голоса, и позволяет наращивать его в будущем. В новый перечень входят следующие параметры:\
1\. `account_creation_fee` — размер комиссионных отчислений, требуемых на создание аккаунта без делегирования;\
2\. `maximum_block_size` — максимальный размер блока блокчейна;\
3\. `sbd_interest_rate` — процент, начисляемый на SBD;\
4\. `create_account_min_golos_fee` — минимальный размер комиссионных отчислений в криптовалюте Голос, требуемых на создание аккаунта с делегированием;\
5\. `create_account_min_delegation` — устанавливает минимально возможное количество Силы Голоса при создании аккаунта с делегированием;\
6\. `min_delegation` — устанавливает минимально возможное количество Силы Голоса для делегирования на аккаунт;\
7\. `create_account_delegation_time` — устанавливает минимально возможное время «заморозки» (в секундах) делегированной Силы Голоса при создании аккаунта с делегированием.

Параметры устанавливаются голосованием в абсолютных значениях. Изначально каждый из параметров принимает установленное для него значение по умолчанию.

Для выполнения этой операции требуется подпись ключом `active`.

## 8. Повышение быстродействия системы за счет размещения в разных объектах полей с часто и редко используемыми данными

Каждый создаваемый пользователем пост и комментарии к нему размещаются в отдельном блоке памяти. Физически такие блоки хранятся на дисках распределенной системы.

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

В случае обработки большого объекта, когда его объем превышает объем выделенной оперативной памяти, происходит поэтапное считывание (загрузка в память) отдельных частей объекта, требующее дополнительных системных ресурсов. По этой причине на обработку объектов большого объема затрачивается значительно больше времени в отличие от времени обработки небольших объектов, полностью размещаемых в оперативной памяти. Интенсивное голосование за пост вызывает частое перемещение объекта, в котором этот пост размещен, и, следовательно, снижение производительности системы.

С целью уменьшения времени, затрачиваемого на считывание объекта в память и сохранение его на диск, в HF•18 принято решение, разделить объект на две части, в одной из которых размещаются редко изменяемые данные объекта (метаданные и тело поста), в другой — счетчики, требующие обновления показателей с поступлением каждого голоса. Такая структура объекта позволила во время голосования перемещать в оперативную память на обработку только его изменяемую часть, в которой находятся счетчики, без риска потери какой-либо информации. Это сократило количество операций, выполняющих непосредственно перемещение объекта между диском и оперативной памятью, и, соответственно, положительно отразилось на производительности системы.

## 9. Повышение производительности API протокола за счет удаления неиспользуемых полей из методов плагинов, а также за счет перераспределения методов между плагинами для более эффективного их использования

### 9.1. Удаление неиспользуемых полей из методов плагинов

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

В версии HF•18 было выполнено перемещение методов между плагинами с целью высвобождения из методов части неиспользуемых полей с последующим их удалением. Это позволило снизить нагрузку на используемую память.

### 9.2. Размещение индексных операций по блокам и аккаунтам в отдельных плагинах

В состав индексных операций блокчейна входят в основном три вида операций, выполняемых по сформированному запросу на сервер:\
1\. получение списка операций, находящихся в блоках;\
2\. получение списка операций, находящихся в транзакциях;\
3\. получение списка операций, выполняемых каким-либо конкретным аккаунтом или связанных с ним.

В предыдущих версиях блокчейна для получения информации об операциях третьего вида необходимо было включить плагин `account_history`. Недостаток заключался в том, что метод, непосредственно выполнявший данную функциональность, размещался в другом плагине `database_api`. Методы, выполнявшие операции видов 1 и 2 также размещались в плагине `database_api`. Для вызова каждого их трех методов необходимо было включать плагин `account_history`, что создавало дополнительную нагрузку на сервер и на потребляемую память, и, следовательно, отрицательно влияло на быстродействие системы.

Кроме этого, возникали затруднения с настройкой сервера для включения какой-либо одной операции (например, только индексирование операции по блоку и исключение других).

В версии HF•18 принято решение переместить модули, выполняющие индексные операции, из плагина `database_api` в плагины в соответствии с их функциональностью.

Метод, возвращающий список операций по аккаунту, был перемещен в плагин `account_history`, обеспечивающий данную функциональность. Методы, используемые для индексирования операций в блоках и транзакциях были перемещены в новый плагин `operation_history`. Это позволило логически сконцентрировать компоненты, обеспечивающие включение индексов и самих операций, по которым могут отдельно быть получены списки операций по блокам, транзакциям или по аккаунту. Теперь для получения списка операций в блоках и транзакциях достаточно будет включить плагин `operation_history`. Для получения более расширенной информации по аккаунтам необходимо подключить `account_history`. Исключение лишних операций индексирования позволило снизить нагрузку на сервер и память и, соответственно, повысить производительность системы.

## 10. Использование тэгов при формировании запросов на получение необходимой информации

В предыдущих версиях блокчейна поиск интересующей пользователя информации инициировал операции индексирования. Для поиска корневого элемента (например, поста или комментария) необходимо было подключиться к плагину `SocialNetwork`, где также инициировался поиск по дополнительным индексам. Последнее приводило к тому, что пользователю наряду с полезной также выдавалась не представляющая ему интерес информация. Из-за наличия в выдаче большого объема ненужной информации увеличивался размер файла разделяемой памяти, что негативно отражалось на производительности системы.

В версии HF•18 методы, обеспечивающие поиск информации по индексам, размещены в двух отдельных плагинах. Часть методов, обрабатывающие теги (например, получение наиболее популярных тэгов, получение списка языков, получение используемых автором списка тэгов и др.) была перемещена из плагина `SocialNetwork` в отдельный плагин `Tag`. Дополнительные индексы для сортировки по тэгам создавались только в этом плагине.

В плагине `SocialNetwork` сохранились методы, обеспечивающие обращение к корневым элементам для получения, например, контента, целиком вложенного дерева, списка активных голосов и др.

Такое разделение методов позволяет пользователю формировать запрос на получение только необходимой ему информации. Чтобы избежать получения контента целиком, пользователю достаточно указать параметры, по которым идентифицируется часть контента (ограничения, набор тэгов).

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

Введен параметр `vote_limit`, с помощью которого пользователь может ограничить получаемый список проголосовавших. Этот параметр позволяет уменьшить размер отправляемого от сервера ответа. При этом в ответе добавляется дополнительное поле `active_votes_count`, информирующее об общем количестве проголосовавших без получения списка целиком.

## 11. Получение информации о текущем статусе разделяемой памяти

В версии HF•18 реализована возможность пользователю получать информацию о текущем статусе разделяемой памяти. Для этого пользователю достаточно сформировать запрос в блокчейн. В состав получаемой информации о текущем статусе разделяемой памяти входят следующие данные: общий объем разделяемой памяти, размер свободного и зарезервированного пространства для определенных нужд, а также список индексов, хранящихся в разделяемой памяти (название индекса, количество записей).

## 12. Постраничный просмотр личных сообщений пользователя

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

Для устранения этого недостатка были модифицированы методы в плагине `private_message`. Данная доработка обеспечивает следующие возможности:\
1\. выделять интересующие пользователя личные сообщения из общего потока исходящих или входящих сообщений с указанием даты их поступления;\
2\. просматривать личные сообщения в режиме постраничного вывода на экран;\
3\. ограничить количество поступающих сообщений.

## 13. Улучшения в подсистеме хранения блоков цепочки

В блокчейне имеются два вида хранилищ:\
1\. разделяемая память, размещенная в файле `shared_memory.bin` и предназначенная для хранения актуальных данных состояния системы;\
2\. цепочка из упакованных в определенном порядке подписанных блоков, размещенных в файле `block_log`.

Обращения к цепочке блоков происходят редко. Обычно это происходит по точечным запросам через API-вызовы для получения тела подписанного блока, синхронизации данных между серверами и ряда других операций. Каждое обращение к файлу `block_log` инициирует значительное количество системных вызовов, в том числе: открытие файла, поиск необходимой позиции и считывание данных из файла. Одновременно с этими операциями может выполняться запись информации в конец файла, требующая от системы подобных действий — переоткрытие файла, поиск конечной позиции в файле и запись в файл.

В предыдущих версиях блокчейна одновременные обращения к файлу `block_log` как по чтению, так и по записи вызывали блокирование доступа к файлу, что негативно влияло на производительность сервера. С целью устранения такого недостатка в HF-18 была реализована новая технология, обеспечивающая одновременный доступ к файлу `block_log` по чтению без замедления работы сервера. Блокирование доступа к файлу `block_log` происходит только во время выполнения операции записи.


# HF18: Изменения в API

В версии HF•18 реализованы новые функциональные и технические возможности, предоставляющие пользователям более удобное взаимодействие с системой, повышенную защиту от злоупотребления голосованием, а также повышающие быстродействие системы за счет более оптимального перераспределения методов между плагинами API.

* [Новые функциональные возможности в HF•18](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#перечень-новых-функциональных-возможностей-в-hf18)
* [Новые технические возможности в HF•18](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#перечень-новых-технических-возможностей-в-hf18)
* [Измененные и новые плагины API в HF•18](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#измененные-и-новые-плагины-в-hf18):
  * [private\_message](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#изменения-в-плагине-privatemessage)
  * [witness\_api](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-плагин-witnessapi)
  * [account\_history](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#изменения-в-плагине-accounthistory)
  * [operation\_history](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-плагин-operationhistory)
  * [social\_network](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#изменения-в-плагине-socialnetwork)
  * [tags](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-плагин-tags)
  * [follow](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#изменения-в-плагине-follow)
  * [database\_api](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#изменения-в-плагине-databaseapi)

## Перечень новых функциональных возможностей в HF•18

* Блокирование различного вида злоупотреблений делегированием Силы Голоса.
* Обеспечение более гибкой ценовой политики на бирже за счет удаления старых данных и использования актуальных в определении курса и соотношения крипто-валют.
* Возможность пользователям вносить изменения в профиль с использованием ключа posting.
* Возможность пользователям предлагать транзакцию на подписание, состоящей из нескольких операций.&#x20;
* Возможность пользователям вносить изменения в посты и комментарии независимо от срока их публикации и придавать им актуальность.

## Перечень новых технических возможностей в HF•18

* Повышение быстродействия системы за счет размещения в разных объектах полей с часто и редко используемыми данными.
* Повышение производительности API протокола за счет удаления неиспользуемых полей из методов плагинов, а также за счет перераспределения методов между плагинами для более эффективного их использования.
* Применение фильтрации тегов для настройки ленты в более удобной для пользователя форме.
* Возможность постраничного вывода личных сообщений на экран пользователя.

## Измененные и новые плагины в HF•18

### Изменения в плагине private\_message

В данный плагин добавлена возможность постраничного вывода списка личных сообщений. Изменены следующие методы (шрифтом bold выделены добавленные аргументы):

* get\_inbox(string to, time\_point newest **, uint limit, uint offset**)
* get\_outbox(string from, time\_point newest **, uint limit, uint offset**)

Метод `get_inbox` возвращает список входящих сообщений начиная с даты, заданной в newest.\
Метод `get_outbox` возвращает список исходящих сообщений начиная с даты, заданной в newest.\
`limit` — ограничивает количество сообщений (максимально допустимое значение — 100).\
`offset` — номер сообщения, с которого выполняется операция (начиная с №).

### Новый плагин witness\_api

Плагин `witness_api` образован перемещением части методов с часто используемыми полями из плагина `database_api`. В него вошли следующие методы:

* get\_current\_median\_history\_price
* get\_feed\_history
* get\_miner\_queue
* get\_witness\_schedule
* get\_witnesses
* get\_witness\_by\_account
* get\_witnesses\_by\_vote
* get\_witness\_count
* lookup\_witness\_accounts
* get\_active\_witnesses // <- из выдаваемого результата удалены пустые строки

Все методы перемещены `в witness_api` без изменений во входных параметрах и выдаваемых результатах. Исключение составляет метод `get_active_witnesses`, у которого из выдаваемого результата удалены пустые строки.

### Изменения в плагине account\_history

Плагин `account_history` дополнен следующим методом:

* get\_account\_history

Метод перемещен из `database_api` без изменений во входных параметрах и выдаваемых результатах.

### Новый плагин operation\_history

Плагин `operation_history` образован перемещением методов из плагина `database_api`. Создание данного плагина позволяет отделить индексирование операций в блокчейне от истории пользователей. Пользователь может запрашивать и получать информацию об операциях в транзакциях (блоках) без ведения истории по аккаунтам. Это обеспечивает снижение нагрузки на сервер и на потребляемую память.

Плагин `operation_history` дополнен следующими методами:

* get\_ops\_in\_block
* get\_transaction

Методы перемещены из `database_api` без изменений во входных параметрах и выдаваемых результатах.

### Изменения в плагине social\_network

Часть методов из плагина `social_network` была перемещена во вновь созданный плагин `tags`. Перенос методов осуществлен для того, чтобы создание дополнительных индексов и поиск информации по ним проводились в отдельном плагине. В плагине `social_network` оставлены методы, обеспечивающие обращение к корневым элементам, а методы, обрабатывающие теги, перемещены в новый плагин `tags`.

Введен опциональный параметр `vote_limit` для задания максимального количества проголосовавших в ответе пользователю. По умолчанию его значение принимается равным 10000. Например, количество комментариев к посту может достигать 1000 и более, что затрудняет их просмотр и поиск интересующей информации. Пользователь может с использованием тэга сформировать запрос на получение комментариев, выбранных (отсортированных) в соответствии с указанными в тэге признаками. Параметр `vote_limit` позволяет уменьшить размер отправляемого от сервера ответа. При этом в ответе добавляется дополнительное поле `active_votes_count`, информирующее об общем количестве проголосовавших (без необходимости получать полный список).

Изменена результирующая структура:

```javascript
struct discussion {
    "active_votes_count": uint, // <— Добавлено. Общее количество голосов для vote_limit
      ...
}
```

Изменения внесены в методы, возвращающие структуру `discussion` и массив `discussion`. В этот перечень вошли следующие методы:

* get\_replies\_by\_last\_update(string start\_parent\_author, string start\_permlink, uint limit `[, uint vote_limit]`)
* get\_content(string account, string permlink `[, uint vote_limit]`)
* get\_content\_replies(string author, string permlink `[, uint vote_limit]`)
* get\_all\_content\_replies(string author, string permlink `[, uint vote_limit]`)
* get\_content(string author, string permlink `[, uint32_t limit]`)
* get\_active\_votes(string account, string permlink `[, uint vote_limit]`)
* get\_account\_votes(string account `[, uint from, uint vote_limit]`)

Фоном выделены параметры, которыми были дополнены методы.

Следующие методы, дублирующие функции плагина `tag`, были удалены из плагина `social_network`:

* get\_trending\_categories
* get\_active\_categories
* get\_recent\_categories
* get\_best\_categories

### Новый плагин tags

В плагин `tags` перемещены методы, выполняющие операции с тэгами (например, получение наиболее популярных тэгов; получение списка языков; получение тэгов, используемых автором). Это позволяет сэкономить размер файла разделяемой памяти тем пользователям, которые не используют данную функциональность.

Методы, которые перемещены из `social_network` без изменений:

* get\_trending\_tags(string start, uint limit)
* get\_languages()
* get\_tags\_used\_by\_author(string)
* get\_discussions\_by\_payout(query)
* get\_discussions\_by\_trending(query)
* get\_discussions\_by\_created(query)
* get\_discussions\_by\_active(query)
* get\_discussions\_by\_cashout(query)
* get\_discussions\_by\_votes(query)
* get\_discussions\_by\_children(query)
* get\_discussions\_by\_hot(query)
* get\_discussions\_by\_feed(query)
* get\_discussions\_by\_blog(query)
* get\_discussions\_by\_comments(query)
* get\_discussions\_by\_promoted(query)

В метод `get_discussions_by_author_before_date` добавлен новый параметр `vote_limit` (шрифтом bold выделен добавленный параметр):

* get\_discussions\_by\_author\_before\_date(string author, string start\_permlink, datetime before\_date, uint limit **\[, uint vote\_limit]**)

  ```javascript
  struct discussion_query {
        limit: uint,
        select_tags: [string],
        filter_tags: [string]
        select_languages: [string],
        filter_languages : [string],
        truncate_body: uint,
        vote_limit: uint,   // <— Новый параметр, по умолчанию принимает значение 10000 
        select_authors : [string],
        start_author: string,
        start_permlink: string,
        parent_author: string,
        parent_permlink: string
  }
  ```

  Изменена результирующая структура метода:

  ```javascript
  struct discussion {
     “reputation”: uint, // <- Поле отсутствует, если выключен плагин follow
    "active_votes_count": uint,   // <- Добавлено. Общее количество голосов для vote_limit
      ...
  }
  ```

### Изменения в плагине follow

В плагине `follow` изменена структура метода `get_account_reputations` в соответствии со следующим представлением:

* get\_account\_reputations(array accounts)&#x20;
  * Результат array

### Изменения в плагине database\_api

Плагин `database_api` дополнен новыми методами для выполнения новых операций.

Новые методы:

* [get\_proposed\_transaction](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-метод-getproposedtransaction)
* [get\_database\_info](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-метод-getdatabaseinfo)
* [get\_vesting\_delegations](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-метод-getvestingdelegations)
* [get\_expiring\_vesting\_delegations](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новый-метод-getexpiringvestingdelegations) &#x20;

Новые операции:

* [изменение или возврат делегирования Силы Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-изменение-или-возврат-делегирования-силы-голоса)
* [создание аккаунта с делегированием Силы Голоса](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-создание-аккаунта-с-делегированием-силы-голоса)
* [изменение json\_metadata  аккаунта](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-изменение-jsonmetadata--аккаунта)
* [предложение на транзакцию](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-предложение-на-транзакцию)
* [обновление предложенной транзакции](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-обновление-предложенной-транзакции)
* [удаление предложенной транзакции](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-удаление-предложенной-транзакции)
* [изменение параметров блокчейна](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-изменение-параметров-блокчейна)

#### Неизменяемая часть database\_api

Часть методов из `database_api` перемещена в плагины `witness_api`, `account_history`, `operationt_history` и `follow`. Сохраненными в `database_api` без изменений остались следующие методы:

* get\_block\_header
* get\_block
* set\_block\_applied\_callback
* get\_config
* get\_dynamic\_global\_properties
* get\_chain\_properties
* get\_hardfork\_version
* get\_next\_scheduled\_hardfork
* get\_account\_count
* get\_owner\_history
* get\_recovery\_request
* get\_escrow
* get\_withdraw\_routes
* get\_account\_bandwidth
* get\_savings\_withdraw\_from
* get\_savings\_withdraw\_to
* get\_conversion\_requests
* get\_transaction\_hex
* get\_required\_signatures
* get\_potential\_signatures
* verify\_authority
* verify\_account\_authority
* lookup\_account\_names
* lookup\_accounts

### Изменения в методах database\_api

Поля `average_bandwidth` и `average_market_bandwidth` были удалены из плагина `database_api` как неиспользуемые. Заменяемые их в выполнении операций поля `new_average_bandwidth`, `new_average_market_bandwidth` были переименованы в первоначальные их имена `average_bandwidth` и `average_market_bandwidth` соответственно.

Поле `lifetime_bandwidth` было удалено и заменено на вновь созданное одноименное поле `lifetime_bandwidth`, зависящее от новых значений, а также поле `lifetime_market_bandwidth` для использования в маркетинговых операциях.

Из описания типа `bandwidth_type`, используемого в вызове метода `get_account_bandwidth`, удалены поля `old_forum` и `old_market`.

В поле `lifetime_bandwidth` хранится суммарное значение `bandwidth`, используемое аккаунтом за все время его работы. В поле `average_bandwidth` хранится среднее значение `bandwidth`, по которому определяется порог чрезмерной активности аккаунта.

#### Внесены изменения в выдаваемый результат следующего метода:

* get\_accounts

  ```javascript
  struct account {
    reputation, // <- Поле отсутствует, если выключен плагин follow
    transfer_history, // <- Удалено
    market_history, // <- Удалено
    post_history, // <- Удалено
    vote_history, // <- Удалено
    other_history, // <- Удалено
    tags_usage, // <- Удалено
    guest_bloggers, // <- Удалено
    blog_category, // <- Удалено
    ...
  }
  ```

  Удаление полей из структуры account обусловлено тем, что ранее эти поля никогда не использовались.

#### Новый метод get\_proposed\_transaction

Этот метод обрабатывает запрос на выдачу списка предложенных для подписания транзакций, поступивший от какого-либо аккаунта. Метод возвращает массив транзакций, в который входят транзакции, созданные непосредственно данным аккаунтом, а также транзакции, которые ему необходимо подписать.

* get\_proposed\_transaction(account: string)

  ```javascript
  struct proposal_object {
    author: string,
    title: string,
    memo: string,
    expiration_time: datetime,
    review_period_time: datetime, // может отсутствовать
    proposed_operations: [ operation ],
    required_active_approvals: [ string ],
    available_active_approvals: [ string ],
    required_owner_approvals: [ string ],
    available_owner_approvals: [ string ],
    required_posting_approvals: [ string ],
    available_posting_approvals: [ string ],
    available_key_approvals: [ string ]
  };
  ```

#### Новый метод get\_database\_info

Этот метод возвращает информацию о текущем статусе разделяемой памяти, в том числе: общий объем разделяемой памяти, размер свободного и зарезервированного пространства для определенных нужд, а также список индексов, хранящихся в разделяемой памяти (название индекса, количество записей).

* get\_database\_info()

  ```
  struct database_info {
    total_size: uint,
    free_size: uint,
    reserved_size: uint,
    used_size: uint

    index_list: [
            {
              name: string,
              record_count: uint
            },
    ]
  };
  ```

#### Новый метод get\_vesting\_delegations

Этот метод возвращает массив значений с описанием операции делегирования (далее — блок делегирования) аккаунта (делегированный другим аккаунтам или же полученный от других аккаунтов).

* get\_vesting\_delegations

  ```
  get_vesting_delegations(
    string account,
    string from, uint32_t limit = 100,
    delegations type = delegated
  )
  ```

  `account` — аккаунт, по запросу от которого выдается блок делегирования. Отправитель\*/получатель определяется аргументом `type`.

  `from` — начальный аккаунт, парный в операции делегирования. Получатель/отправитель - задается аргументом `type` (для пагинации).

  `limit` — количество возвращаемых элементов (для пагинации). По умолчанию принимается равным 100. Максимальное значение равно 1000.

  `type` — тип запрашиваемого блока делегирования: "delegated" (делегированный), "received" (полученный). По умолчанию принимает значение "delegated".

Пример возвращаемого блока делегирования: `массив vesting_delegation_api_object [{id: 0, delegator: "zzz", delegatee: "zxcat", vesting_shares: "90.000000 GESTS", min_delegation_time: "2018-04-25T21:48:15"}]`.

#### Новый метод get\_expiring\_vesting\_delegations

Этот метод используется для получения списка возвращаемых (отозванных и «замороженных») делегированных средств аккаунта. Метод возвращает результат в виде массива значений с описанием операции возврата делегированных средств (далее — блок отозванного делегирования)

* get\_expiring\_vesting\_delegations

  ```
  get_expiring_vesting_delegations(
    string account,
    time_point_sec from,
    uint32_t limit = 100)
  ```

  `account` — аккаунт, возвращающий делегированные средства.

  `from` — начальное время возврата делегированных средств (для пагинации).

  `limit` — количество возвращаемых элементов (для пагинации). По умолчанию принимается равным 100. Максимальное значение равно 1000.

Пример возвращаемого модулем блока отозванного делегирования: `массив vesting_delegation_expiration_api_object, [{id: 0, delegator: "zxcat", vesting_shares: "123.000000 GESTS", expiration: "2018-05-25T11:18:45"}]`.

#### Новая операция: изменение или возврат делегирования Силы Голоса

Эта операция позволяет изменять количество делегированного, а также осуществлять возврат делегированного в полном объеме. Для выполнения этих операций необходима подпись ключом `active`. Операции выполняются с использованием следующей процедуры:

```javascript
delegate_vesting_shares
{
    delegator: string,    // делегирующий аккаунт
    delegatee: string,    // аккаунт-получатель
    vesting_shares: asset    // новое количество делегируемой Силы Голоса
}
```

Для выполнения этой опирации требуется подпись ключом `active`.

Для изменения количества делегирования Силы Голоса в поле `vesting_shares` следует задать новое значение. Для полного возврата делегированной части Силы Голоса в поле `vesting_shares` следует задать значение вида “0.000000 GESTS”. При изменении значения в сторону уменьшения делегированная Сила Голоса сразу снимется с аккаунта-получателя и переходит в «замороженное» состояние сроком на семь дней (в случае создания аккаунта с делегированием этот период определяется параметром `create_account_delegation_time`).

Минимальное количество Силы Голоса, необходимое для делегирования, определяется по результатам голосования делегатов.

#### Новая операция: создание аккаунта с делегированием Силы Голоса

Операция выполняется с использованием следующей процедуры:

```javascript
account_create_with_delegation
{
      fee: asset,        // комиссия, в GOLOS
      delegation: asset,    // делегируемая доля, в GESTS
      creator: string,        
      new_account_name: string,
      owner: authority,
      active: authority,
      posting, authority,
      memo_key: string,
      json_metadata: string,
      extensions: extensions_type    // Не используется, исходное значение — пусто
}
```

Для выполнения этой опирации требуется подпись ключом `active`.

Для создания аккаунта с делегированием необходимо, чтобы выполнялись следующие два условия:

```
    1. fee ≥ create_account_min_golos_fee
    2. (delegation) ≥ (create_account_min_delegation)
```

где\
`fee` — размер комиссионных отчислений;\
`create_account_min_golos_fee` — минимальный размер комиссионных отчислений в криптовалюте Голос, требуемых на создание аккаунта с делегированием;\
`delegation` — делегированная часть Силы Голоса;\
`create_account_min_delegation` — минимальное количество Силы Голоса, необходимое для создания аккаунта с делегированием.

При создании аккаунта с делегированием бо́льшую часть комиссии можно оплатить с «заморозкой» на период, определяемый параметром `create_account_delegation_time`. Делегированная Сила Голоса может быть отозвана в любой момент (например, в случае злоупотребления полученной делегированной частью новым аккаунтом). При этом делегированная Сила Голоса будет снята с нового аккаунта сразу, а на делегирующий аккаунт будет возвращена по истечении срока «заморозки». Время «заморозки» является параметром, определяемым по результатам голосования. Его значение выбирается по медиане из списка всех значений, полученных от делегатов с помощью операции `chain_properties_update_operation`.

#### Новая операция: изменение json\_metadata  аккаунта

Пользователю предоставляется возможность изменять метаданные своего профиля без использования ключа `active`. Поля профиля хранятся в `json_metadata`. Для изменения любого поля профиля требовалась подпись только ключом `active`, что не всегда было приемлемым.

Было принято решение разделить поля на две группы. В состав первой группы вошли поля с наиболее значимыми данными профиля (ключи: `posting`, `active`, `owner` и `memo`), а в другую — с менее значимыми, но часто используемыми (аватар, пол, местонахождение и пр.). Процедура изменения полей первой группы сохранена и требует подписи только ключом `active`. В версии HF•18 вносить изменения в поля второй группы стало возможным с использованием ключа `posting` для подписи.

Операция выполняется с использованием следующей процедуры:

```javascript
account_metadata
{
    account: string,    // изменяемый аккаунт
    json_metadata: string    // новое значение json_metadata
}
```

Для выполнения этой опирации требуется подпись ключом `posting`.

#### Новая операция: предложение на транзакцию

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

Операция выполняется с использованием следующей процедуры:

```javascript
proposal_create_operation
{
    author: string, // автор предлагаемой транзакции
    title: string,  // заголовок предложенной транзакции.
    memo: string,   // примечание
    proposed_operations: [ operation ], // список операций в предлагаемой транзакции
    expiration_time: datetime, // максимальное время, отведенное на транзакцию
    review_period_time: datetime, // время на принятие решения участников транзакции. Опциональный параметр
    extensions: extensions_type // расширение, по аналогии с другими операциями. Исходное значение — пусто
}
```

Для выполнения этой опирации требуется подпись ключом `active`.

Создаваемая транзакция должна быть уникальной по сочетанию полей author-title. По этой паре author-title идентифицируется транзакция в случае внесения в нее изменений или ее удаления.

В поле `proposed_operations` задается список операций для выполнения их в транзакции (например, `{["delete_comment_operation":{"autor":"jim", "permlink":"hello"}}]`). На каждую операцию из этого списка должна быть получена подпись автора, которому она предназначена. Право проставления подписи на выполнение любой операции из списка имеет также каждый из участников транзакции. Например, операция публикации поста назначается одному автору, а операция перечисления вознаграждения за нее — другому. В случае несогласия другого автора с выполнением второй операции он может удалить подпись на выполнение первой операции предложенной транзакции.

В поле `review_period_time` проставляется время, отводимое на принятие решений участников транзакции. Этот период должен быть меньше максимального времени из поля `expiration_time`, которое отводится на транзакцию. По истечении этого периода подписи в транзакции могут быть только удаляться.

Если параметр `review_period_time` не задан, то транзакция будет сразу выполняться после сбора всех необходимых подписей.

#### Новая операция: обновление предложенной транзакции

Автору, а также участникам транзакции, предоставляется возможность менять свое решение и обновлять подписи до истечения времени, отводимого на транзакцию.

Если транзакция не получает одобрения на выполнение какой-либо из операций, эта транзакция не отменяется и ее актуальность будет сохраняться до отведенного на ее выполнение времени. После получения всех необходимых подписей транзакция сразу будет выполняться и все последующие обновления будут считаться недействительными.

Операция выполняется с использованием следующей процедуры:

```javascript
proposal_update_operation
{
    author: string, // автор предложенной транзакции
    title: string,  // заголовок предложенной транзакции.
    active_approvals_to_add: [string], // список аккаунтов для подписи. Транзакция должна быть  
                    // подписана ключом active
    active_approvals_to_remove: [string], // список аккаунтов для удаления подписи из предложенной  
                    // транзакции. Транзакция должна быть подписана ключом active
    owner_approvals_to_add: [string], // список аккаунтов для подписи на операции в предложенной  
                    // транзакции. Транзакция должна быть подписана ключом owner
    owner_approvals_to_remove: [string], // список аккаунтов для удаления подписи из предложенной  
                    //транзакции. Транзакция должна быть подписана ключом owner
    posting_approvals_to_add: [string], // список аккаунтов для подписи на операции в предложенной  
                    // транзакции. Транзакция должна быть подписана ключом posting 
    posting_approvals_to_remove: [string], // список аккаунтов для удаления подписи из предложенной  
                    // транзакцию. Транзакция должна быть подписана ключом posting
    key_approvals_to_add: [string], // список ключей public для проставления подписей в предложенной  
                    // транзакции
    key_approvals_to_remove: [string], // список ключей public для удаления подписей из предложенной  
                    // транзакции
    extensions: extensions_type // расширение, по аналогии с другими операциями. Исходное значение — пусто
}
```

Подпись зависит от списка операций, предлагаемых на подписание.

По этой паре author-title идентифицируется транзакция в случае внесения в нее изменений или ее удаления. Поля, в которые записывается псевдоним для подписи транзакции, выбираются в зависимости от типа операций в предложенной транзакции.

#### Новая операция: удаление предложенной транзакции

В случае отказа кого-либо из участников транзакции в выполнении операции он может сформировать запрос на удаление предложенной транзакции. Идентификация транзакции осуществляется по паре author-title.

Операция выполняется с использованием следующей процедуры:

```javascript
proposal_delete_operation
{
    author: string, // автор предложенной транзакции
    title: string,  // заголовок предложенной транзакции
    requester: string, // псевдоним запросившего удаление транзакции или автор предложенной транзакции
    extensions: extensions_type // расширение, по аналогии с другими операциями. Исходное значение — пусто
}
```

Для выполнения этой опирации требуется подпись ключом `active`.

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

#### Новая операция: изменение параметров блокчейна

Предыдущие версии блокчейна обеспечивают поддержку операции `witness_update`, которая позволяет делегатам Голоса изменять по результатам голосования значения следующих параметров:

* `account_creation_fee` — размер комиссионных отчислений, требуемых на создание аккаунта без делегирования; &#x20;
* `maximum_block_size` — максимальный размер блока блокчейна; &#x20;
* `sbd_interest_rate` — процент, начисляемый на SBD. &#x20;

Ввиду того, что `witness_update` не позволяет расширить перечень параметров, значения которых определяются голосованием, в версии HF•18 реализована новая операция `chain_properties_update`, которая поддерживает более расширенный перечень таких параметров и позволяет наращивать его в будущем. В версии HF•18 операция `chain_properties_update` поддерживает следующий перечень параметров, значения которых определяются голосованием:

* `account_creation_fee` — размер комиссионных отчислений, требуемых на создание аккаунта без делегирования; &#x20;
* `maximum_block_size` — максимальный размер блока блокчейна; &#x20;
* `sbd_interest_rate` — процент, начисляемый на SBD; &#x20;
* `create_account_min_golos_fee` — минимальный размер комиссионных отчислений в криптовалюте Голос, требуемых на создание аккаунта с делегированием (по умолчанию принимает значение "1.000 GOLOS", см. операцию [account\_create\_with\_delegation](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-создание-аккаунта-с-делегированием-силы-голоса)); &#x20;
* `create_account_min_delegation` — устанавливает минимально возможное количество Силы Голоса при создании аккаунта с делегированием (по умолчанию принимает значение "5.000 GOLOS", см. операцию [account\_create\_with\_delegation](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-создание-аккаунта-с-делегированием-силы-голоса)); &#x20;
* `create_account_delegation_time` — устанавливает минимально возможное время (в секундах) «заморозки» делегированной Силы Голоса при создании аккаунта с делегированием (по умолчанию принимает значение за период в 30 дней, см. операцию [account\_create\_with\_delegation](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-создание-аккаунта-с-делегированием-силы-голоса)); &#x20;
* `min_delegation` — устанавливает минимально возможное количество Силы Голоса для делегирования на аккаунт (по умолчанию принимает значение "10.000 GOLOS", см. операцию [delegate\_vesting\_shares](https://github.com/golos-blockchain/wiki/tree/d940af7f54725dd68c7f9080f07d5b5f609bf4d4/developers/hardforks/new_hardfork-hf18.md#новая-операция-изменение-или-возврат-делегирования-силы-голоса)). &#x20;

Операция выполняется с использованием следующей процедуры:

```javascript
chain_properties_update_operation
{
     owner: string, // автор изменения
     props: {
       account_creation_fee: asset,
       maximum_block_size: uint,
       sbd_interest_rate: uint,
       create_account_min_golos_fee: uint,
       create_account_min_delegation: uint,
       create_account_delegation_time: uint,
       min_delegation: uint    
     }
}
```

Для выполнения этой опирации требуется подпись ключом `active`.


# HF18: Изменения в cli\_wallet

***Эта страница содержит информацию об изменениях в клиентском приложении cli\_wallet, предоставляющих возможность создания транзакции произвольного вида в ручном режиме.***

Клиентское приложение `cli_wallet` (виртуальный кошелек) поставляется вместе с программой-эмулятором демоном (от англ. daemon). Данное приложение является одним из основных программных устройств, широко используемым участниками биржевых торгов. Приложение обеспечивает выполнение балансовых операций со счетами виртуальных кошельков клиентов, а также создание постов, голосование за посты и пр.

Целью доработок `cli_wallet` в HF·18 являлось создание удобного программного инструмента, обеспечивающего создание транзакции произвольного вида в ручном режиме.

В предыдущих версиях блокчейна создание транзакции выполнялось только в автоматическом режиме с подключением JS-, Python- и GO-библиотек. Главными достоинствами автоматического создания транзакции являлись быстрота и избавление пользователей от трудоемких операций. Недостатком такой реализации являлось наличие фиксированного набора команд, ограничивающего пользователей в возможности манипулирования параметрами.

В версии HF·18 создан конструктор, обеспечивающий формирование транзакций с произвольным набором выполняемых операций. С помощью конструктора пользователь может задать перечень операций с их описанием. Пользователь также может добавлять, изменять и редактировать операции в создаваемой транзакции. Каждая отдельная операция выполняется отдельным методом, входящим в состав методов `cli_wallet`.

Доработка заключается в добавлении необходимых методов в `cli_wallet` и выполнена в соответствии с требованиями поставленной задачи №542.

## Новые методы в cli\_wallet для расширения возможностей API

Клиентское приложение `cli_wallet` дополнено новыми методами, реализующими новый программный компонент — конструктор транзакций. В отличие от предыдущих версий блокчейна пользователь с помощью конструктора может формировать транзакцию произвольного вида по своему усмотрению. Кроме этого, конструктор позволяет создавать несколько транзакций для одновременного выполнения операций и идентифицировать каждую отдельную транзакцию. Доработка не вносит изменения в работу API, а только расширяет его возможности. Только два метода — `create_account` и `create_account_with_keys`, входящие в прежний состав методов приложения `cli_wallet` были незначительно модифицированы.

### Метод create\_account\_delegated

Этот метод позволяет создавать публичные ключи `owner`, `active`, `posting` и `memo` для нового аккаунта. За создание аккаунта в качестве комиссионных отчислений с баланса кошелька создателя аккаунта (автора) снимается определенная сумма `fee`. Величина этих отчислений не может быть меньше значения параметра `account_creation_fee`, устанавливаемого по результатам голосования делегатов. Параметр `fee` показывает изначальный базовый баланс кошелька аккаунта, необходимый для его существования в системе. С баланса кошелька создателя аккаунта снимается криптовалюта в виде Голоса (Golos) и зачисляется на баланс кошелька нового аккаунта в виде Силы Голоса (VESTS). Размер комиссионных отчислений, а также другую информацию от блокчейна, можно найти в выдаче команды `wallet`, имеющей вид `“account_creation_fee”:”X.000 GOLOS”`.

Затрачиваемое на создание аккаунта количество криптовалюты не может быть возвращено обратно в кошелек создателя.

Создатель аккаунта может делегировать часть Силы Голоса на новый аккаунт. В этом случае делегированная часть будет также списана с баланса Силы Голоса его кошелька и зачислена на баланс Силы Голоса нового аккаунта. Делегированная Сила Голоса может быть возвращена в кошелек создателя через определенный период, длительность которого определяется голосованием.

Метод имеет следующий вид:

```
annotated_signed_transaction create_account_delegated(
    string creator,
    asset steem_fee, 
    asset delegated_vests, 
    string new_account_name,
    string json_meta,
    bool broadcast
);
```

где:\
`creator` — пользователь, который создает новый аккаунт;\
`steem_fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть возвращена обратно в кошелек создателя аккаунта;\
`delegated_vests` — сумма комиссионных отчислений в криптовалюте Сила Голоса, снимаемая с баланса кошелька пользователя за операцию делегирования и зачисляемая на баланс кошелька нового аккаунта в криптовалюте Сила Голоса. Эта сумма может быть возвращена обратно в кошелек создателя аккаунта по истечении определенного периода, устанавливаемого голосованием делегатов;\
`new_account_name` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`broadcast` — ‘true’, если транзакция пересылается на демон; ‘false’, если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

### Метод create\_account\_with\_keys\_delegated

Этот метод используется для создания новых аккаунтов через вызов операции `account_create`. В отличие от метода `create_account`, который обеспечивает генерацию ключей для нового аккаунта автоматически, метод `create_account_with_keys_delegated` требует явного задания ключей для нового аккаунта. Создатель аккаунта обязан иметь соответствующий ключ.

Созданный аккаунт не может контролироваться его кошельком. С баланса кошелька создателя снимается сумма комиссионных отчислений в криптовалюте Голос и зачисляется на баланс кошелька нового аккаунта в криптовалюте Сила Голоса. Метод имеет следующий вид:

```
annotated_signed_transaction create_account_with_keys_delegated(
    string creator,
    asset steem_fee,
    asset delegated_vests,
    string newname,
    string json_meta,
    public_key_type owner,
    public_key_type active,
    public_key_type posting,
    public_key_type memo,
    bool broadcast
) const;
```

где:\
`creator` — пользователь, который создает новый аккаунт;\
`steem_fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть возвращена обратно в кошелек создателя аккаунта;\
`delegated_vests` — сумма комиссионных отчислений в криптовалюте Сила Голоса, снимаемая с баланса кошелька пользователя за операцию делегирования и зачисляемая на баланс кошелька нового аккаунта в криптовалюте Сила Голоса. Эта сумма может быть возвращена обратно в кошелек создателя аккаунта по истечении определенного периода, устанавливаемого голосованием делегатов;\
`newname` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`owner` — значение публичного ключа `owner` нового аккаунта;\
`active` — значение публичного ключа `active` нового аккаунта;\
`posting` — значение публичного ключа `posting` нового аккаунта;\
`memo` — значение публичного ключа `memo` нового аккаунта;\
`broadcast` — ‘true’, если транзакция пересылается на демон.

### Метод delegate\_vesting\_shares

Метод обеспечивает делегирование части криптовалюты Силы Голоса с одного аккаунта на другой. Метод имеет следующий вид:

```
annotated_signed_transaction delegate_vesting_shares(
    string delegator,
    string delegatee,
    asset vesting_shares,
    bool broadcast
);
```

где:\
`delegator` — имя аккаунта, который делегирует Силу Голоса;\
`delegatee` — имя аккаунта, на который делегируется Сила Голоса;\
`vesting_shares` — сумма делегирования;\
`broadcast` — ‘true’, если транзакция пересылается на демон.

### Метод begin\_builder\_transaction

Метод вызывает операцию создания конструктора транзакций и возвращает уникальный номер созданного конструктора. Начальное значение уникального номера принимается равным «0» и увеличивается на единицу с каждым вызовом метода. Метод имеет следующий вид:

```
transaction_handle_type begin_builder_transaction();
```

### Метод get\_prototype\_operation

Метод используется для получения и заполнения шаблона для операции, создаваемой с помощью другого метода `add_operation_to_builder_transaction`. Метод возвращает неинициализированный объект в виде заданной последовательности операций. Созданный объект может быть дополнен любой операцией с помощью вызова `add_operation_to_builder_transaction()`.

Предварительно необходимо определить json-формат данных операции, чтобы получить соответствующий шаблон. Метод имеет следующий вид:

```
operation get_prototype_operation(
    string operation_type
);
```

где:\
`operation_type` — тип операции. Операция должна быть определена в файле `steem/chain/operations.hpp`.

### Метод add\_operation\_to\_builder\_transaction

Этот метод используется для добавления операции в список операций конструктора транзакций. Метод имеет следующий вид:

```
void add_operation_to_builder_transaction(
    transaction_handle_type handle,
    const operation& op
);
```

где:\
`handle` — уникальный номер конструктора;\
`op` — добавляемая операция.

### Метод add\_operation\_copy\_to\_builder\_transaction

Метод обеспечивает копирование операции между конструкторами транзакций. Каждый их конструкторов идентифицируется значением параметра `handler`, возвращаемого методом `begin_builder_transaction()`. Метод имеет следующий вид:

```
void add_operation_copy_to_builder_transaction(
    transaction_handle_type src_handle,
    transaction_handle_type dst_handle,
    uint32_t op_index
);
```

где:\
`src_handle` — уникальный номер конструктора, из которого копируется операция;\
`dst_handle` — уникальный номер конструктора, на который копируется операция;\
`op_index` — номер копируемой операции.

### Метод replace\_operation\_in\_builder\_transaction

Метод обеспечивает замену операции в конструкторе транзакций под номером `op_index` на операцию `op`. Метод имеет следующий вид:

```
void replace_operation_in_builder_transaction(
    transaction_handle_type handle,
    unsigned op_index,
    const operation& op
);
```

где:\
`handle` — уникальный номер конструктора;\
`op_index` — номер операции в конструкторе транзакций, которую необходимо заменить;\
`op` — заменяющая операция.

### Метод preview\_builder\_transaction

Метод обеспечивает поиск и получение конструктора транзакций по заданному идентификационному номеру из списка конструкторов. Метод имеет следующий вид:

```
transaction preview_builder_transaction(
    transaction_handle_type handle
);
```

где:\
`handle` — уникальный номер получаемого конструктора.

### Метод sign\_builder\_transaction

Метод используется для подписания всех транзакций в конструкторе транзакций. Метод имеет следующий вид:

```
signed_transaction sign_builder_transaction(
    transaction_handle_type handle,
    bool broadcast
);
```

где:\
`handle` — уникальный номер конструктора транзакций;\
`broadcast` — ‘true’, если подписанные транзакции необходимо переслать на демон.

### Метод propose\_builder\_transaction

Метод используется для создания конструктора предлагаемых транзакций. Метод имеет следующий вид:

```
signed_transaction propose_builder_transaction(
    transaction_handle_type handle,
    std::string author,
    std::string title,
    std::string memo,
    time_point_sec expiration = time_point::now() + fc::minutes(1),
    time_point_sec review_period_time = time_point::min(),
    bool broadcast
);
```

где:\
`handle` — уникальный номер создаваемого конструктора транзакций;\
`author` — автор предлагаемой транзакции;\
`title` — заголовок предлагаемой транзакции;\
`memo` — примечание, текст которого дополняет смысловое значение заголовка;\
`expiration` — время, по истечении которого прекращается подписание транзакции;\
`review_period_time` — период, выделенный для подписания транзакции;\
`broadcast` — ‘true’, если транзакция пересылается на демон.

### Метод remove\_builder\_transaction

Метод обеспечивает удаление конструктора транзакций по заданному идентификационному номеру. Метод имеет следующий вид:

```
void remove_builder_transaction(
    transaction_handle_type handle
);
```

где:\
`handle` — уникальный номер конструктора транзакций. Этот номер уменьшается на единицу после каждого вызова метода.

### Метод approve\_proposal

Метод обеспечивает проверку и сбор подписей на предложенную транзакцию. Метод возвращает подписанную версию транзакции.

Поскольку для подписи транзакции используются три типа ключей (`owner`, `active` и `posting`), подсчет подписей каждого типа ключей выполняется отдельно. Для этого в методе находится специальный структурный параметр `delta`, в котором содержатся актуальные данные результатов голосования по каждому типу ключей. Структура параметра имеет следующий вид:

```javascript
struct approval_delta {
    vector<string> active_approvals_to_add; // список необходимых аккаунтов, которые должны
            // поставитьподпись вида «active» для одобрения предложенной транзакции
    vector<string> active_approvals_to_remove; // список необходимых аккаунтов, чьи подписи
            // вида «active» должны быть удалены из списка подписей, которые одобрили
            // транзакцию
    vector<string> owner_approvals_to_add; // список необходимых аккаунтов, которые должны  
            // поставить подпись вида «owner» для одобрения предложенной транзакции
    vector<string> owner_approvals_to_remove; // список необходимых аккаунтов, чьи подписи  
            // вида «owner» должны быть удалены из списка подписей, которые одобрили
            // транзакцию
    vector<string> posting_approvals_to_add; // список необходимых аккаунтов, которые должны
            // поставить подпись вида «posting» для одобрения предложенной транзакции
    vector<string> posting_approvals_to_remove; // список необходимых аккаунтов, чьи подписи
            // вида «posting» должны быть удалены из списка подписей, которые одобрили
            // транзакцию
    vector<string> key_approvals_to_add; // список подписей вида «public», которые необходимо
            // получить для одобрения транзакции
    vector<string> key_approvals_to_remove; // список подписей вида «public», которые необходимо
            // удалить из списка подписей, которые одобрили транзакцию
}
```

Метод имеет следующий вид:

```
signed_transaction approve_proposal(
    std::string author,
    std::string title,
    approval_delta delta,
    bool broadcast
);
```

где:\
`author` — автор, предложенной транзакции;\
`title` — заголовок предложенной на подпись транзакции;\
`delta` — список подписей, необходимых для одобрения транзакции. В JSON-формате список может быть пустым;\
`broadcast` — ‘true’, если транзакция пересылается на демон; ‘false’, если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

### Метод get\_proposed\_transactions

Метод обеспечивает получение информации о всех предложенных транзакция, применительно к одному и тому же аккаунту. Для получения информации об ограниченном количестве транзакций, необходимо задать начальный номер транзакции и пороговое значение `limit`. Метод имеет следующий вид:

```
std::vector<database_api::proposal_api_object> get_proposed_transactions(
    std::string account,
    uint32_t from,
    uint32_t limit
);
```

где:\
`account` — аккаунт, информацию о предложенных транзакциях которого необходимо получить;\
`from` — начальный номер транзакции;\
`limit` — пороговое значение количества транзакций.

## Модифицированные методы в приложении cli\_wallet

Следующие методы не являются новыми в приложении `cli_wallet` и уже использовались в предыдущих версиях блокчейна. Они изменены незначительно.

### Метод create\_account

Метод обеспечивает создание аккаунта с автоматической генерацией ключей. Метод использует операцию `account_create` и возвращает созданный аккаунт. Доработка состоит из добавления параметра `fee`. Метод имеет следующий вид:

```
annotated_signed_transaction create_account(
    string creator,
    string new_account_name,
    string json_meta,
    asset fee,
    bool broadcast
);
```

где:\
`creator` — пользователь, создающий новый акаунт;\
`new_account_name` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля `json_metadata`;\
`fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть меньше значения `account_creation_fee`, устанавливаемого по результатам голосования делегатов;\
`broadcast` — ‘true’, если транзакция пересылается на демон; ‘false’, если выполняется базовый контроль с выдачей подписанной транзакции на консоль.

### Метод create\_account\_with\_keys

Метод обеспечивает создание аккаунта и требует явного задания ключей. Доработка состоит из добавления параметра `fee`. Метод имеет следующий вид:

```
annotated_signed_transaction create_account_with_keys(  
    string creator,  
    string newname,  
    string json_meta,  
    asset fee,  
    public_key_type owner,  
    public_key_type active,  
    public_key_type posting,  
    public_key_type memo,  
    bool broadcast  
) const;
```

где:\
`creator` — пользователь, который создает новый аккаунт;\
`newname` — имя нового аккаунта;\
`json_meta` — метаданные профиля нового аккаунта поля json\_metadata;\
`fee` — сумма комиссионных отчислений в криптовалюте Голос, снимаемая с баланса кошелька пользователя за создание нового аккаунта и зачисляемая на баланс кошелька созданного аккаунта в криптовалюте Сила Голоса. Эта сумма не может быть меньше значения `account_creation_fee`, устанавливаемого по результатам голосования делегатов;\
`owner` — значение публичного ключа `owner` нового аккаунта;\
`active` — значение публичного ключа `active` нового аккаунта;\
`posting` — значение публичного ключа `posting` нового аккаунта;\
`memo` — значение публичного ключа `memo` нового аккаунта;\
`broadcast` — ‘true’, если транзакция пересылается на демон.

## Этапы создания транзакций произвольной формы

Процедура создания транзакций, подписания и передача их на демон в ручном режиме включает в себя следующие основные этапы:

**1. Создание конструктора транзакций.** На начальном этапе необходимо по API вызвать метод `begin_builder_transaction`. В результате вызова будет получено значение параметра `HANDLE` — идентификационный номер конструктора транзакций. По этому номеру будет вызываться созданный конструктор для формирования транзакций.

**2. Создание набора операций.** На этом этапе создается набор необходимых для выполнения в транзакции операций с помощью вызова `add_operation_to_builder_transaction $HANDLE [opID, {operation}]` по API. Полученный на начальном этапе конструктор позволяет создать произвольный набор операций в ручном режиме, а также изменять и редактировать их. Каждая из операций будет доступна по присвоенному ей идентификационному номеру `opID`, получаемого с помощью вызова `get_prototype_operation <operation-type>`. Конструктор обеспечивает построение нескольких транзакций параллельно.

**3. Формирование суммы необходимых комиссионных отчислений.** На этом этапе определяется сумма комиссионных отчислений за сформированный набор операций для каждой из транзакций. Пользователь может либо определить размер комиссионных отчислений за каждую операцию в отдельности, либо воспользоваться вызовом метода `set_fees_on_builder_transaction` для автоматического определения общей суммы комиссионных отчислений.\
Метод `set_fees_on_builder_transaction` не дорабатывался и вызывается так же как и в предыдущей версии блокчейна.

**4. Подписание и передача на демон предложенной транзакции.** На заключительном этапе необходимо вызвать `sign_builder_transaction $HANDLE true`. Предложенная транзакция будет автоматически отправлена на подпись и затем передана на демон.

**Note**\
Из-за доработки `cli_wallet` изменилась выдача метода `get_ops_in_block`. В предыдущих версиях выдача этого метода имела следующий вид:

```
vector<operation_api_object> get_ops_in_block(
    uint32_t <blockquote></blockquote>_num,
    bool only_virtual
);
```

Вид измененной выдачи get\_ops\_in\_block:

```
vector<golos::plugins::operation_history::applied_operation> get_ops_in_block(
    uint32_t block_num,
    bool only_virtual
);
```


# SF18.4: Новые функции

## Дополнительная информация в оповещениях о подписанных блоках

### Получение информации о виртуальных операциях в блоке

В предыдущих версиях SF пользователь мог подписаться на получение актуальной информации в виде оповещения о новых блоках, создаваемых в блокчейне. Операция выполнялась вызовом метода `set_block_applied_callback()`. Получаемое пользователем оповещение было недостаточно полным и содержало только информацию о подписанном блоке без информации о виртуальных операциях в этом блоке.

В версии SF-0.18.4 в вызов метода `set_block_applied_callback()` добавлен настраиваемый параметр type, принимающий четыре значения. В зависимости от задаваемого значения этого параметра, пользователь может получать следующую информацию о блоке:\
— подписанный блок;\
— заголовок блока;\
— виртуальные операции блока;\
— подписанный блок и виртуальные операции.

Пользователь имеет возможность получать не только наиболее полную информацию о подписанном блоке, но также задавать ее содержимое по своему усмотрению.

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

| Значение параметра | Альтернативное значение параметра | Тип информации в оповещении                      |
| ------------------ | --------------------------------- | ------------------------------------------------ |
| «block»            | 0                                 | Подписанный блок (по аналогии с версией HF 18.0) |
| «header»           | 1                                 | Заголовок блока (по аналогии с версией HF 16.4)  |
| «virtual\_ops»     | 2                                 | Только виртуальные операции блока                |
| «full»             | 3                                 | Подписанный блок и виртуальные операции блока    |

Любое другое задаваемое значение параметра принимается методом `set_block_applied_callback()` как «block».

Доработка выполнена с сохранением обратной совместимости с предыдущими версиями SF. В доработке применяется ранее неиспользуемый параметр, в поле которого был ноль. В версии SF-0.18.4 это поле отведено под тип возвращаемого результата. В случае задания в этом поле нулевого значения, возвращаемый результат будет соответствовать результату предыдущих версий. Добавление трех новых значений этого параметра расширяет возможность API.\
Метод имеет следующий вид:

```cpp
void set_block_applied_callback(
    block_applied_callback_result_type type
)
```

Параметр:\
`type` — тип информации в получаемом оповещении.

### Получение информации о транзакциях на Узле, не включенных в блок

В версии SF-0.18.4 введен дополнительный (ранее разработанный, но заблокированный для использования) вид операции оповещения пользователя о блоках. Данная операция выполняет отправку сообщения пользователю о появившихся на Узле блокчейна транзакциях, уже подписанных, но еще не включенных в блок. Информация о таких транзакциях отсутствует в блоках и поэтому не может быть доступна пользователю с помощью обычного вызова `set_block_applied_callback()`.

Пользователю для подписания на получение оповещения о таких транзакциях необходимо вызвать API-метод `set_pending_transaction_callback()`.

### Получение информации о вознаграждении подписчика блока

В версии SF-0.18.4 введена новая виртуальная (не заданная явным образом) операция `producer_reward_operation()`, генерируемая на каждом из блоков. Операция оповещает пользователя о вознаграждении в виде GESTS подписчика блока — продюсера блока, которым может являться одно из следующих лиц:\
— делегат, входящий в утвержденный список делегатов;\
— делегат, выбранный случайным образом;\
— майнер.

Виртуальная операция имеет вид:

```cpp
struct producer_reward_operation {
    account_name_type producer;
    asset vesting_shares
};
```

Параметры:\
`producer` — имя аккаунта-продюсера блока;\
`vesting_shares` — размер вознаграждения (в GESTS).

Виртуальная операция хранится в истории Узла блокчейна и может быть запрошена API-методом `get_ops_in_block()` для получения информации о вознаграждении продюсера блока. Метод имеет вид:

```cpp
std::vector<applied_operation> get_ops_in_block(
    uint32_t block_num,
    bool only_virtual
)
```

Параметры:\
`block_num` — идентификатор блока, виртуальные операции которого запрашиваются;\
`only_virtual` — «true», если возвращаются только виртуальные операции.

## Улучшение диагностики ошибок

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

В версии SF-0.18.4 реализовано решение, обеспечивающее выдачу пользователю диагностической информации об ошибке с описанием уровня иерархической структуры блокчейна, на котором возникает ошибка. Решение основано на разбиении всех ошибок по категориям и формировании диагностической информации для каждой категории.

Был проведен анализ ошибок непосредственно в местах их формирования с последующей их классификацией по информативным признакам. В результате анализа было выделено три класса ошибок:\
1\. ошибки пользователя в задании параметров;\
2\. ошибки пользователя при выполнении операций бизнес-логики (например, превышение bandwidth;\
3\. ошибки в тексте программы (внутренние ошибки блокчейна, не зависящие от пользователя).

Каждый из этих классов ошибок был разбит на подклассы и далее на категории ошибок. Были получены следующие категории ошибок:\
1\. неподдерживаемая блокчейном операция;\
2\. ошибка количества аргументов, переданных плагину;\
3\. ошибка значения параметра (проверка синтаксиса заданного значения параметра, в том числе: наличие недопустимых символов в именах аккаунтов, корректность записи единиц актива, превышение максимально допустимого количества символов в комментарии);\
4\. превышение лимита на выдачу результата операции;\
5\. ошибка структуры запроса JSON-API (например, наличие незаполненного поля, запрос к несуществующему методу);\
6\. нарушение структуры транзакции;\
7\. отсутствие заданного объекта (например, отсутствие аккаунта с заданным именем или транзакции с заданным идентификатором);\
8\. отсутствие требуемой версии HardFork;\
9\. ошибка бизнес-логики (например, попытка клиента подписать на себя бизнес-объект), в том числе:\
— отсутствие достаточного количества активов для выполнения операции;\
— превышение значения bandwidth (например, превышение количества размещаемых постов или отдаваемых голосов за определенный период);\
10\. ошибка сервера (например, отсутствие доступа к серверу);\
11\. выполнение операции на заблокированном кошельке;\
12\. ошибка программного кода , в том числе:\
— ошибка, возникающая в используемых библиотеках;\
— ошибка кода (например, недопустимое использование функции внутри кода).

Для каждой из категорий ошибок сформирована диагностическая информация и добавлена в каталог сообщений. Конкретные ошибки внутри категории разделяются по дополнительному полю. Кроме этого, доработана система возврата диагностической информации о возникшей ошибке при обработке запроса в формате JSON.\
Все ошибки, за исключением ошибок категории 12, являются пользовательскими и могут анализироваться непосредственно пользователем.

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

## Создание многофункционального плагина для обработки личных сообщений пользователя

В версии SF-0.18.4 реализован новый плагин `private_message_operations` расширяющий возможности пользователя в обмене сообщениями с другими пользователями, а также в обработке личных сообщений.

Введение нового плагина добавило пользователю следующие функциональные возможности:\
— обмен сообщениями с другими пользователями без использования токенов;\
— получение подписки на (виртуальные) операции, связанные с работой плагина;\
— получение списка пользователей, с которыми было общение;\
— создание списка "закрепленных контактов" с возможностью добавления в список нового пользователя (закрепление контакта), а также удаления из списка незадействованного в общении пользователя (удаление контакта);\
— получение истории обмена сообщениями с конкретным пользователем (по заданному имени пользователя);\
— получение истории обмена сообщениями по заданному имени пользователя, отфильтрованных по определенным признакам (например, по дате, количеству сообщений или по другим признакам);\
— постраничный просмотр сообщений с пользователем, с которым ведется переписка;\
— редактирование отправленного сообщения;\
— удаление отправленного сообщения (с пометкой сообщения как удаленного).

### Операции с личными сообщениями пользователя

**Отправка, редактирование личных сообщений**

Для отправки и редактирования сообщений пользователя используется следующий метод:

```cpp
struct private_message_operation {
    account_name_type from;  
    account_name_type to;  
    uint64_t nonce;   
    public_key_type from_memo_key;   
    public_key_type to_memo_key;  
    uint32_t checksum;  
    bool update;  
    vector<char> encrypted_message
};
```

Параметры:\
`from` — имя аккаунта, отправляющего сообщение;\
`to` — имя аккаунта, которому адресовано сообщение;\
`nonce` — произвольное целочисленное значение, уникальное значение части ключа (рекомендуется использовать текущее время в миллисекундах);\
`from_memo_key` — публичный ключ категории `memo` отправителя, используемого для шифрования сообщения;\
`to_memo_key` — публичный ключ категории `memo` получателя сообщения, используемого для расшифровки сообщения;\
`checksum` — контрольная сумма результата ключа шифрования;\
`update` — “true”, если сообщение редактируется (поля `from`, `to`, `nonce`); “false”, если сообщение создается;\
`encrypted_message` — результирующее сообщение.

Для редактирования сообщения требуется указывать уникальный ключ (поля `from`, `to`, `nonce`). Алгоритм получения ключа шифрования аналогичен алгоритму шифрования поля `memo` в операциях с переводами средств.

Внутри зашифрованного сообщений содержится структура в формате JSON, которая может быть расширена. Структура имеет вид:

```cpp
struct  message {  
    string  subject;  
    string body  
};
```

**Удаление личного сообщения**

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

```cpp
struct private_delete_message_operation {
    account_name_type requester;  
    account_name_type from;  
    account_name_type to;  
    uint64_t nonce;  
    time_point_sec start_date;  
    time_point_sec stop_date  
};
```

Параметры:\
`requester` — имя аккаунта, запросившего опреацию удаления;\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`start_date` — дата и время, начиная от которого сообщения должны быть удалены;\
`stop_date` — дата и время, заканчиваясь которым сообщения должны быть удалены.

Для удаления сообщения требуется указать уникальный ключ (поля `from`, `to`, `nonce`). Для удаления серии сообщений дополнительно требуется указать диапазон сообщений `start_date-stop_date`.

**Пометка личных сообщений как прочитанных**

Сообщение (или группа сообщений) может быть помечена меткой вида «прочитанное». Операция выполняется аналогично операции удаления сообщений и вызывается следующим методом:

```cpp
struct private_mark_message_operation {
    account_name_type from;
    account_name_type to;
    uint64_t nonce;
    time_point_sec start_date;
    time_point_sec stop_date
};
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`start_date` — дата и время, начиная от которого сообщения должны быть помечены как прочитанные;\
`stop_date` — дата и время, заканчиваясь которым сообщения должны быть помечены как прочитанные.

Для пометки сообщения требуется указать уникальный ключ (поля `from`, `to`, `nonce`). Для пометки серии сообщений дополнительно требуется указать диапазон сообщений `start_date-stop_date`.

**Создание и настройка контакт-листа аккаунтов**

Для удобства отслеживания входящих и исходящих сообщений в систему личных сообщений добавлен контакт-лист, содержащий перечень аккаунтов, с которыми пользователь обменивается сообщениями. Контакт-лист для пользователя создается сразу после первого обмена сообщением с любым из аккаунтов. После каждой отправки или приема очередного сообщения этот лист пополняется новым аккаунтом, с которым выполнялся обмен данным сообщением.

Пользователь может добавлять в контакт-лист нового аккаунта, с которым еще не обменивался сообщением.\
Метод, выполняющий создание нового контакта, имеет следующий вид:

```cpp
struct private_contact_operation {
    account_name_type owner;
    account_name_type contact;
    private_contact_type type;
    string json_metadata
};
```

Параметры:\
`owner` — имя аккаунта, создающего контакт;\
`contact` — имя аккаунта, добавляемого в контакт-лист;\
`type` — тип контакта (`pinned`, чтобы добавить контакт);\
`json_metadata` — данные о добавляемом в контакт-лист аккаунте в формате JSON.

Разрешенные типы контактов:

```cpp
enum private_contact_type {
    unknown = 1, // неизвестный контакт
    pinned = 2,    // контакт, который персонально добавляется контакт лист
    ignored = 3  // игнорируемый контакт 
};
```

Для удаления контакта из контакт-списка, необходимо задать тип `unknown` и удалить все его сообщения.\
Для внесения аккаунта в контакт-лист необходимо задать тип `pinned`.\
Для прекращения приема сообщений от контакта из контакт-списка, необходимо задать тип `ignored`.\
Для прекращения приема сообщений от всех аккаунтов, за исключением находящихся в контакт-листе, необходимо настроить контакт-лист. Операция по настройке контакт-листа выполняется вызовом следующего метода:

```cpp
struct private_settings_operation {
    account_name_type owner;
    bool ignore_messages_from_unknown_contact
};
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`ignore_messages_from_unknown_contact` — "true" для прекращения получения сообщений от неизвестного контакта.

### Операции с личными сообщениями пользователя с использованием клиентского приложения cli\_wallet

**Отправка личного сообщения**

Отправление личного сообщения аккаунту выполняется вызовом следующего метода:

```cpp
send_private_message(
    string from, 
    string to, 
    message_body message,
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`message` — сообщение вида ({"subject":"", "body":""})\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Редактирование личного сообщения**

Редактирование личного сообщения выполняется следующим методом:

```cpp
edit_private_message(
    string from, 
    string to, 
    uint64_t nonce, 
    message_body message, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`message` — сообщение вида ({"subject":"", "body":""});\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Получение списка входящих сообщений**

Для получения списка входящих сообщений используется следующий метод:

```cpp
get_private_inbox(
    string to, 
    message_box_query query
);
```

Параметры:\
`to` — имя аккаунта-получателя сообщения;\
`query` — параметры поиска.

**Получение списка отправленных сообщений**

Для получения списка отправленных сообщений используется следующий метод:

```cpp
get_private_outbox(
    string from, 
    message_box_query query
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`query` — параметры поиска.

**Получение списка из канала сообщений**

Для получения списка из канала сообщений используется следующий метод:

```cpp
get_private_thread(
    string from, 
    string to, 
    message_thread_query query
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`query` — параметры поиска.

**Настройка личных сообщений**

Для настройки личных сообщений используется следующий метод:

```cpp
set_private_settings(
    string owner, 
    settings_api_object settings, 
    bool broadcast
);
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`settings` — настройки;\
`broadcast` — “true”, если операция пересылается на сервер. “false”, если транзакция выводится на экран.

**Получение настроек личных сообщений**

Для получения настроек личных сообщений используется следующий метод:

```cpp
get_private_settings(string owner)
```

Параметр:\
`owner` — имя аккаунта, собственника контакт-листа.

**Добавление и изменение контакта личных сообщений в контакт-листе**

Для добавления или изменения контакта в контакт-листе используется следующий метод:

```cpp
add_private_contact(
    string owner, 
    string contact, 
    private_contact_type type, 
    string json_metadata, 
    bool broadcast
)
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`contact` — имя аккаунта, контакт которого добавляется или изменяется в контакт-листе;\
`type` — тип контакта (`unknown` - неопределенный, `pinned` - закрепленный, `ignored` - игнорируемый);\
`json_metadata` — данные контакта в формате JSON;\
`broadcast` — "true", если операция пересылается на сервер; "false", если транзакция выводится на экран.

**Получение списка контактов личных сообщений из контакт-листа**

Для выполнения данной операции необходимо задать тип контактов, по которому будет сформирован требуемый список контактов, имеющихся в в контакт-листе. Операция выполняется с использованием следующего метода:

```cpp
get_private_contacts(
    string owner, 
    private_contact_type type, 
    int limit, 
    int offset
);
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`type` — тип контактов, по которому формируется список;\
`limit` — максимальное количество контактов в формируемом списке;\
`offset` — смещение относительно начала контактов в контакт-листе, от которого формируется список.

**Получение информации об отдельном контакте**

Для получения информации об отдельном контакте из контакт-листа используется следующий метод:

```cpp
get_private_contact(
    string owner, 
    string contact
);
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`contact` — имя аккаунта контакта.

**Удаление личного сообщения из списка входящих**

Для удаления личных сообщений из списка входящих используется следующий метод:

```cpp
delete_inbox_private_message(
    string from, 
    string to, 
    uint64_t nonce, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Удаление серии сообщений из списка входящих**

Для удаления серии личных сообщений из списка входящих используется следующий метод:

```cpp
delete_inbox_private_messages(
    string from, 
    string to, 
    time_point_sec start_date, 
    time_point_sec stop_date, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`start_date` — дата и время, начиная от которого входящие сообщения должны быть удалены;\
`stop_date` — дата и время, заканчиваясь которым входящие сообщения должны быть удалены;\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Удаление сообщения из списка отправленных**

Для удаления личного сообщения из списка отправленных используется следующий метод:

```cpp
delete_inbox_private_message(
    string from, 
    string to, 
    uint64_t nonce, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Удаление серии сообщений из списка отправленных**

Для удаления серии личных сообщений из списка отправленных используется следующий метод:

```cpp
delete_outbox_private_messages(
    string from, 
    string to, 
    time_point_sec start_date, 
    time_point_sec stop_date, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`start_date` — дата и время, начиная от которого отправленные сообщения должны быть удалены;\
`stop_date` — дата и время, заканчиваясь которым отправленные сообщения должны быть удалены;\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Пометка личного сообщения как прочитанного**

Операция выполняется аналогично операции удаления сообщения и вызывается следующим методом:

```cpp
mark_private_message(
    string from, 
    string to, 
    const uint64_t nonce, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — уникальное значение части ключа (поля `from`, `to`, `nonce`);\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

**Пометка серии личных сообщений как прочитанных**

Операция выполняется аналогично операции удаления сообщений и вызывается следующим методом:

```cpp
mark_private_messages(
    string from, 
    string to, 
    time_point_sec start_date,
    time_point_sec stop_date, 
    bool broadcast
);
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`start_date` — дата и время, начиная от которого сообщения должны быть помечены как прочитанные;\
`stop_date` — дата и время, заканчиваясь которым сообщения должны быть помечены как прочитанные;\
`broadcast` — “true”, если операция пересылается на сервер; “false”, если транзакция выводится на экран.

### API личных сообщений пользователя

**Получение списка личных сообщений**

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

```cpp
struct message_api_object {
    account_name_type from;  
    account_name_type to;  
    uint64_t nonce;  
    public_key_type from_memo_key;  
    public_key_type to_memo_key;  
    uint32_t checksum;  
    std::vector<char> encrypted_message;  
    time_point_sec create_date;  
    time_point_sec receive_date;  
    time_point_sec read_date;  
    time_point_sec remove_date  
};
```

Параметры:\
`from` — имя аккаунта-отправителя сообщения;\
`to` — имя аккаунта-получателя сообщения;\
`nonce` — случайное число, необходимое для дешифрования сообщения и являющееся составной частью уникального ключа (с содержанием полей `from`, `to` и `nonce`);\
`from_memo_key` — публичная часть ключа `memo` аккаунта-отправителя;\
`to_memo_key` — публичная часть ключа `memo` аккаунта-получателя;\
`checksum` — контрольная сумма ключа шифрования;\
`encrypted_message` — зашифрованное сообщение;\
`create_date` — дата и время создания сообщения;\
`receive_date` — дата и время получения сообщения. Если сообщение не редактируется, значение этого поля совпадает со значением поля `create_data`;\
`read_date` — дата и время прочтения сообщения;\
`remove_date` — дата и время удаления сообщения из ящика аккаунта собеседника.

**Просмотр сообщений, получаемых из ящиков входящих и исходящих сообщений**

Для просмотра сообщений, хранящихся в ящиках входящих и исходящих сообщений, используется структура следующего вида:

```cpp
struct message_box_query {
    set<string> select_accounts;   
    set<string> filter_accounts;  
    time_point_sec newest_date;  
    bool unread_only;  
    uint16_t limit;  
    uint32_t offset  
};
```

Параметры:\
`select_accounts` — список имен аккаунтов, выбранных для просмотра их сообщений;\
`filter_accounts` — список имен аккаунтов, исключенных для просмотра их сообщений; `newest_date` — дата и время, начиная с которого показываются сообщения;\
`unread_only` — показывать только непрочитанные сообщения;\
`limit` — максимальное количество выдаваемых сообщений;\
`offset` — смещение относительно начала списка, с которого выдаются сообщения.

**Получение списка входящих сообщений для аккаунта-получателя сообщений**

Для получения списка входящих сообщений для аккаунта-получателя используется запрос следующего вида:

```cpp
get_inbox(
    string to, 
    message_box_query
)
```

Параметры:\
`to` — имя аккауна-получателя сообщений;\
`message_box_query` — запрос на получение сообщений;

Результатом является получение пользователем вектора вида: `vector<message_api_object>`.

**Получение списка исходящих сообщений для аккаунта-отправителя сообщений**

Для получения списка исходящих сообщений для аккаунта-отправителя используется запрос следующего вида:

```cpp
get_outbox(
    from, 
    message_box_query
)
```

Параметры:\
`from` — имя аккауна-отправителя сообщений;\
`message_box_query` — запрос на получение сообщений.

Результатом запроса является получение пользователем вектора вида: `vector<message_api_object>`.

**Фильтрация списка сообщений**

Фильтрации списка сообщений в канале сообщений (между пользователями `from` и `to`) выполняется с использованием структуры следующего вида:

```cpp
struct message_thread_query {
    time_point_sec newest_date;  
    bool unread_only;  
    uint16_t limit;  
    uint32_t offset
};
```

Параметры:\
`newest_date` — дата и время, начиная с которого показываются сообщения;\
`unread_only` — показывать только непрочитанные сообщения;\
`limit` — максимальное количество выдаваемых сообщений;\
`offset` — смещение относительно начала списка, с которого выдаются сообщения.

**Получение потока сообщений между отправителем и получателем сообщений**

Получение потока сообщений (между пользователями `from` и `to`) выполняется с использованием метода следующего вида:

```cpp
get_thread(
    string from,
    string to, 
    message_thread_query
)
```

Параметры:\
`from` — имя аккаунта-отправителя сообщений;\
`to` — имя аккаунта-получателя сообщений;\
`message_thread_query` — запрос на получение потока сообщений.

Результатом запроса является получение пользователем вектора вида: `vector<message_api_object>`.

**Получение актуальных настроек модуля личных сообщений**

Для получения актуальных настроек модуля личных сообщений используется API-запрос следующего вида:

```cpp
get_settings(string owner)
```

Параметр:\
`owner` — имя аккаунта, собственника контакт-листа.

Результатом запроса является получение структуры следующего вида:

```cpp
struct settings_api_object {
    bool ignore_messages_from_unknown_contact;
};
```

Параметр:\
`ignore_messages_from_unknown_contact` — “true”, если блокируются сообщения от неизвестных контактов.

**Получение данных о размерах контакт-листа**

Для получения данных о размерах контакт листа используется запрос следующего вида:

```cpp
get_contacts_size(string owner)
```

Параметр:\
`owner` — имя аккаунта, собственника контакт-листа.

Результатом запроса является получение структуры следующего вида:

```cpp
struct contacts_size_api_object {
    map<private_contact_type, contacts_size_info> size
};
```

Параметры:\
`size` — данные размера контакт-листа в виде следующей структуры:

```cpp
struct contacts_size_info {  
    int total_contacts;  
    int total_outbox_messages;  
    int unread_outbox_messages;  
    int total_inbox_messages;  
    int unread_inbox_messages  
};
```

`total_contacts` — общее количество имен аккаунтов (контактов) в контакт-листе;\
`total_outbox_messages` — общее количество исходящих сообщений;\
`unread_outbox_messages` — общее количество непрочитанных исходящих сообщений;\
`total_inbox_messages` — общее количество входящих сообщений;\
`unread_inbox_messages` — общее количество непрочитанных входящих сообщений

**Получения данных об отдельно взятом контакте**

Для получения данных об отдельно взятом контакте используется запрос следующего вида:

```cpp
get_contact_info(
    string owner, 
    string contact
)
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`contact` — имя аккаунта, данные о котором требуется получить.

Результатом запроса является получение структуры следующего вида:

```cpp
struct contact_api_object {
    account_name_type owner;
    account_name_type contact;
    string json_metadata;
    private_contact_type local_type;
    private_contact_type remote_type;
    contact_size_info size
};
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа (не более 16 символов);\
`contact` — имя контакта, данные о котором выдаются (не более 16 символов);\
`json_metadata` — данные об аккаунте в формате JSON;\
`local_type` — тип контакта в контакт-листе аккаунта с именем `owner`;\
`remote_type` — тип контакта в контакт-листе аккаунта с именем `contact`;\
`size` — данные размера контакт-листа.

**Получения полного списка контактов, имеющихся в контакт-листе**

Для получения полного списка имен аккаунтов (контактов), имеющихся в контакт-листе, используется запрос следующего вида:

```cpp
get_contacts(
    string owner,
    private_contact_type type,
    int limit,
    int offset
)
```

Параметры:\
`owner` — имя аккаунта, собственника контакт-листа;\
`type` — тип контактов, список которых требуется получить (`unknown`, `pinned`, `ignored`);\
`limit` — максимальное количество выдаваемых контактов;\
`offset` — смещение относительно начала списка, с которого выдаются контакты.

Результатом запроса является получение массива структур вида `vector<contact_api_object>`.

**Подписка на события о личных сообщениях**

Для подписки на события о личных сообщениях используется вызов следующего вида:

```cpp
set_callback(callback_query)
```

Параметр `callback_query` в этом вызове является структурой следующего вида:

```cpp
struct callback_query {
    set<account_name_type> select_accounts;  
    set<account_name_type> filter_accounts;  
    set<callback_event_type> select_events;  
    set<callback_event_type> filter_events  
};
```

Параметры:\
`select_accounts` — список имен аккаунтов, выбранных для просмотра их сообщений;\
`filter_accounts` — список имен аккаунтов, исключенных для просмотра их сообщений;\
`select_events` — список событий для мониторинга;\
`filter_events` — список событий для исключения из мониторинга.

Список событий является перечислением следующего вида:

```cpp
enum callback_event_type {
    message,     // мониторинг сообщений
    mark,        // пометка сообщений как прочитанных
    remove_inbox,     // удаление входящих сообщений
    remove_outbox,     // удаление исходящих сообщений
    contact        // добавление имени аккаунта в контакт-лист
};
```

На события `message`, `mark`, `remove_inbox` и `remove_outbox` будет приходить структура следующего вида:

```cpp
struct callback_message_event {
    callback_event_type type;  // тип контакта (`unknown`,  `pinned`, `ignored`)
    message_api_object message // объект сообщения 
};
```

На события `contact` будет приходить структура следующего вида:

```cpp
struct callback_contact_event {
    callback_event_type type; // тип контакта (`unknown`,  `pinned`, `ignored`)
    contact_api_object contact // объект контакта
};
```

## Расширение возможностей пользователя с операциями над реблогами

В предыдущих версиях пользователю предоставлялись только небольшие возможности с операциями над размещенными в его блоге постами (реблогами), которые являлись копиями публикаций других блогов (например, собственник блога (блоггер) не мог удалить из него ранее размещенный в нем реблог или дополнить этот реблог собственным комментарием). Версия SF-0.18.4 предоставляет пользователю такие возможности.

### Удаление реблога

В новой версии, в отличие от предыдущих версий, блоггеру предоставляется возможность удалять реблоги, а также скопированные случайным образом в его блог сторонние публикации. Для этого в плагин `follow` добавлен новый метод `delete_reblog_operation()`. Вызов этого метода возможен из `cli_wallet` с использованием эвалюатора `custom_json`. Операция удаления реблога формируется в ручном режиме.

Пример вызова операции удаления реблога:

```cpp
begin_builder_transaction
add_operation_to_builder_transaction 0 ["custom_json", {"required_posting_auths":["<reblogger-name>"], \
    "id": "follow", "json":"["delete_reblog", {"account":"<reblogger-name>","author":"<post-author-name>", \
    "permlink":"<post-title>"}]"}]
sign_builder_transaction 0 true
```

В приведенном примере:\
`begin_builder_transaction` — команда вызова транзакции, в состав которой входит операция удаления реблога;\
`add_operation_to_builder_transaction` — команда, формирующая операцию удаления реблога, которой присвоен идентификационный номер “0”;\
`<reblogger-name>` — имя аккаунта-реблоггера, скопировавшего в свой блог сторонний пост;\
`<post-author-name>` — имя аккаунта оригинального поста;\
`<post-title>` — заголовок удаляемого реблога;\
`sign_builder_transaction` — команда для получения одобрения транзакции с отправлением ее на демон.

Для удаления более одного реблога необходимо сформировать транзакцию с несколькими операциями.

### Добавление комментария к реблогу

В новой версии, в отличие от предыдущих, автору реблога предоставляется возможность добавлять к реблогу собственный комментарий. Для этого в плагине `follow` доработан метод `reblog_operation`. Вызов этого метода возможен из `cli_wallet` с использованием эвалюатора `custom_json`. Операция добавления комментария к реблогу формируется в ручном режиме.

**Изменения в клиентском приложении cli\_wallet**

Для добавления комментария в реблог в вызываемую из приложения `cli_wallet` операцию `reblog_operation` добавлены следующие поля:

| Имя поля       | Тип            | Назначение                                                  |
| -------------- | -------------- | ----------------------------------------------------------- |
| body           | string (UTF-8) | Содержит тело добавляемого к реблогу комментария            |
| title          | string (UTF-8) | Содержит заголовок добавляемого к реблогу комментария       |
| json\_metadata | string (UTF-8) | Содержит метаданные добавляемого комментария в формате JSON |

**Примечание:** Наличие поля `body` в вызове является обязательным для операции реблога поста с добавлением комментария.

Пример вызова операции реблога поста с добавлением комментария:

```cpp
begin_builder_transaction
add_operation_to_builder_transaction 0 ["custom_json", {"required_posting_auths":["<reblogger-name>"], \
    "id": "follow", "json":"["reblog", {"account":"<reblogger-name>","author":"<post-author-name>", \
    "permlink":"<post>","title":"<comment-title>","body":"<comment-body>"}]"}]
sign_builder_transaction 0 true
```

В приведенном примере:\
`begin_builder_transaction` — команда вызова транзакции, в состав которой входит операция реблога поста с добавлением комментария;\
`add_operation_to_builder_transaction` — команда, формирующая операцию реблога поста с добавлением комментария, которой присвоен идентификационный номер “0”;\
`<reblogger-name>` — имя аккаунта-блоггера, выполняющего реблог поста;\
`<post-author-name>` — имя аккаунта, автора оригинального поста;\
`<post>` — копируемый пост;\
`<comment-title>` — заголовок добавляемого комментария;\
`<comment-body>` — тело добавляемого комментария;\
`sign_builder_transaction` — команда для получения одобрения транзакции с отправлением ее на демон.

**Изменения в API-методах:**

Ответы API-методов `get_blog` и `get_blog_entries` дополнены полями, приведенными в следующей таблице:

| Имя поля               | Тип    | Назначение                                                     |
| ---------------------- | ------ | -------------------------------------------------------------- |
| `reblog_title`         | string | Содержит заголовок реблога, к которому добавляется комментарий |
| `reblog_body`          | string | Содержит тело реблога                                          |
| `reblog_json_metadata` | string | Содержит метаданные реблога                                    |

Ответы API-методов `get_feed`, `get_feed_entries`, `get_discussions_by_blog` и `get_discussions_by_feed` дополнены массивом объектов `reblog_entries`, структура которого дополнена полями, приведенными в следующей таблице:

| Имя поля               | Тип    | Назначение                                                     |
| ---------------------- | ------ | -------------------------------------------------------------- |
| `author`               | string | Содержит имя аккаунта-блоггера                                 |
| `reblog_title`         | string | Содержит заголовок реблога, к которому добавляется комментарий |
| `reblog_body`          | string | Содержит тело реблога                                          |
| `reblog_json_metadata` | string | Содержит метаданные реблога                                    |

## Возможность настройки конфигурационного файла для хранения только необходимой информации на Узле

С целью сбережения ресурсов памяти пользователь заинтересован хранить на Узле блокчейна только необходимую для него информацию, такую как метаданные аккаунта, сопроводительный текст (примечание) в операциях перевода средств, последние обновления постов и комментариев. После закрытия поста актуальность такой информации исчезает и ее необходимо удалять.

Для хранения на Узле блокчейна только важную информацию пользователю нет необходимости создавать Узел в варианте полной конфигурации памяти. Для снижения потребления ресурсов памяти пользователь мог построить Узел в варианте конфигурации LOW\_MEM.

В предыдущих версиях для включения или выключение режима на хранение важной информации на Узле требовалось заново перестраивать Узел в одном из вариантов конфигурации — стандартном или LOW\_MEM соответственно. Поскольку на перестроения затрачивалось значительное время, это негативно сказывалось на быстродействие Узла.

### Возможность настройки конфигурационного файла для хранения метаданных аккаунта

В версии SF-0.18.4 для хранения метаданных аккаунта на Узле блокчейна (без перестроения Узла в варианте конфигурации LOW\_MEM) добавлены новые флаги `store-account-metadata` и `store-account-metadata-list` в конфигурационный файл `config.ini`, а также внесены изменения в API-библиотеку. Использование этих флагов обеспечивает более гибкое настройку Узла для хранения важной информации в режиме сбережения памяти.

Для включения или выключения режима на хранение метаданных аккаунта пользователю достаточно настроить конфигурационный файл `config.ini` и один раз перезапустить Узел. По завершении синхронизации Узла в дальнейшем его перезапуск не требуется.

**Изменения в конфигурационном файле config.ini**\
Файл `config.ini` дополнен настраиваемыми флагами, приведенными в следующей таблице:

| Имя флага                     | Тип    | Значение по умолчанию | Устанавливаемое значение                                                                                                                                                                                             |
| ----------------------------- | ------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `store-account-metadata`      | bool   | —                     | “true” — включение режима на хранение метаданных для всех аккаунтов, заданными в списке флага `store-account-metadata-list`.                  "false" —  выключение режима на хранение метаданных для всех аккаунтов |
| `store-account-metadata-list` | string | —                     | Список имен аккаунтов, для которых сохраняются метаданные                                                                                                                                                            |

**Изменение в API-библиотеке**\
API-метод `account_api_object()` использует пустое значение json\_metadata без необходимости задания режима LOW\_MEM для случая, если у Узла блокчейна выключен режим хранения метаданных.

### Возможность настройки конфигурационного файла для хранения сопроводительной информации в операциях перевода средств

В версии SF-0.18.4 для хранения на Узле блокчейна (без перестроения Узла в варианте конфигурации LOW\_MEM) сопроводительного текста поля `memo` в операциях перевода средств из кошельков добавлен новый флаг `store-memo-in-savings-withdraws` в конфигурационный файл `config.ini`. Использование этого флага обеспечивает более гибкое задание режима сбережения памяти.

Для включения или выключения режима на хранение сопроводительного сообщения поля `memo` пользователю достаточно настроить конфигурационный файл `config.ini` и всего один раз перезапустить Узел. По завершении синхронизации Узла в дальнейшем его перезапуск не требуется.

**Изменения в конфигурационном файле config.ini**\
Файл `config.ini` дополнен настраиваемым флагом, приведенным в следующей таблице:

| Имя флага                         | Тип  | Значение по умолчанию | Устанавливаемое значение                                                                                       |
| --------------------------------- | ---- | --------------------- | -------------------------------------------------------------------------------------------------------------- |
| `store-memo-in-savings-withdraws` | bool | true                  | "true" — включение режима на хранение сообщения поля `memo` для всех операций по переводу средств из кошельков |

### Возможность настройки конфигурационного файла для хранения изменений в постах и комментариях с учетом глубины истории этих изменений

В предыдущих версиях пользователю для включения или выключения режима на хранение комментариев полей `last_update` и `active` необходимо было каждый раз перестраивать Узел.

В версии SF-0.18.4 для устранения этого недостатка введен новый флаг `store-comment-last-update` в конфигурационный файл `config.ini`, а также внесены изменения в API-библиотеку. Использование этого флага предоставляет пользователю возможность устанавливать глубину истории хранения с учетом даты изменения и даты последнего обновления. Для включения или выключения режима на хранение комментариев полей `last_update` и `active` необходимо настроить конфигурационный файл `config.ini` и перезапустить Узел. По завершении синхронизации Узла в дальнейшем его перезапуск не требуется.

**Изменения в конфигурационном файле config.ini**\
Файл `config.ini` дополнен настраиваемым флагом, приведенным в следующей таблице:

| Имя флага                   | Тип  | Значение по умолчанию | Устанавливаемое значение                                                                              |
| --------------------------- | ---- | --------------------- | ----------------------------------------------------------------------------------------------------- |
| `store-comment-last-update` | bool | true                  | “true” — включение режима на хранение изменений в постах и комментариях. “false” —  выключение режима |

**Изменения в API-библиотеке**\
В версии SF-0.18.4 поля `last_update` и `active` являются произвольными и в возвращаемом значении API-метода `comment_api_object()` могут отсутствовать.

Изменены имена аргументов, представленных в следующей таблице.

| Имя аргумента в предыдущей версии                             | Имя аргумента в версии SF-0.18.4 |
| ------------------------------------------------------------- | -------------------------------- |
| `discussion_helper::impl fill_comment_content`                | `fill_comment_info`              |
| `discussion_helper::discussion_helper() fill_comment_content` | `fill_comment_info`              |

### Возможность настройки конфигурационного файла для хранения истории о вознаграждениях за публикации

После окончания выплат в виде вознаграждений автору за публикацию поста, а также лицам, принимавшим участие в голосовании, данные о выплатах становятся неактуальными и в дальнейшем не используются в системе. Пользователь, в случае необходимости, может хранить на своем Узле историю о вознаграждениях за публикации и использовать ее по своему усмотрению без необходимости перестроения Узла в варианте конфигурации LOW\_MEM.\
В конфигурационный файл `config.ini` добавлена новая переменная `store-comment-rewards`, а также внесены изменения в API-библиотеку. Использование этой переменной обеспечивает хранение на Узле блокчейна историю выплат вознаграждений без необходимости перестроения Узла в варианте конфигурации LOW\_MEM. **Изменения в API-библиотеке**\
Структура объекта комментариев дополнена новыми параметрами (помечены комментарием “новый”):

```cpp
struct comment_api_object {
    …
    asset total_payout_value;
    asset beneficiary_payout_value;
    asset beneficiary_gests_payout_value;
    asset curator_payout_value;
    asset curator_gests_payout_value; // новый

    share_type author_rewards;
    asset author_gbg_payout_value; // новый 
    asset author_golos_payout_value; // новый
    asset author_gests_payout_value; // новый
    …
}
```

Параметры:\
`total_payout_value` — общая сумма выплат в GBG;\
`beneficiary_payout_value` — бенефициарские выплаты в GBG;\
`beneficiary_gests_payout_value` — бенефициарские выплаты в GESTS;\
`curator_payout_value` — кураторские выплаты в GBG;\
`curator_gests_payout_value` — кураторские выплаты в GESTS.\
`author_rewards` — авторские вознаграждения в GOLOS;\
`author_gbg_payout_value` — авторские выплаты в GBG;\
`author_golos_payout_value` — авторские выплаты в GOLOS;\
`author_gests_payout_value` — авторские выплаты в GESTS.

### Возможность настройки конфигурационного файла для хранения истории постов или комментариев

Пользователю предоставляется возможность более гибко настраивать конфигурационный файл для хранения контента поста или комментариев до определенного времени. Конфигурационный файл `config.ini` дополнен новыми параметрами `comment-title-depth`, `comment-body-depth`, `comment-json-metadata-depth` и `set-content-storing-depth-null-after-update`.

Первые три параметра используется для настройки глубины истории хранения заголовка, тела и метаданных постов (или комментариев) соответственно. Задание нулевых значений для всех этих параметров в конфигурационном файле означает, что контент не должен сохраняться. Ненулевое целочисленное значение хотя бы одного из этих параметров означает хранение соответствующей ему части контента до момента оплаты за этот пост (или комментарий).

Параметр `set-content-storing-depth-null-after-update` используется для случая, когда контент необходимо сохранять только после его изменения. Задание этого параметра автоматически отменяет действие первых трех параметров.

Для сбережения ресурсов памяти пользователь может сохранять контент не полностью, а только определенную его часть без необходимости перестроения Узла в варианте конфигурации LOW\_MEM.

Параметры приведены в следующей таблице.

| Имя параметра                                 | Тип       | Значение по умолчанию | Устанавливаемое значение                                                          |
| --------------------------------------------- | --------- | --------------------- | --------------------------------------------------------------------------------- |
| `comment-title-depth`                         | uint32\_t | —                     | Максимальное количество блоков для хранения заголовков                            |
| `comment-body-depth`                          | uint32\_t | —                     | Максимальное количество блоков для хранения тела поста или комментария            |
| `comment-json-metadata-depth`                 | uint32\_t | —                     | Максимальное количество блоков для хранения метаданных в формате JSON             |
| `set-content-storing-depth-null-after-update` | bool      | "false"               | "true", если глубина хранения контента должна обнуляться после изменения контента |

### Возможность настройки конфигурационного файла для удаление устаревшей информации

В предыдущих версиях удаление устаревших голосов (объектов) выполнялось с помощью опции LOW\_MEMORY\_NODE, которая могла быть установлена либо в командной строке, либо в конфигурационном файле с помощью флага компиляции «–DLOW\_MEMORY\_NODE=ON/OFF».\
Удаление голосов выполнялось после закрытия поста и проведения всех необходимых расчетов с целью освобождения памяти от устаревшей информации и, следовательно, сокращения времени, затрачиваемое на начальную синхронизацию.\
Также удаление голосов можно было выполнить с помощью другой опции `clear-votes-before-block, bpo::value<uint32_t>()->default_value(0)`, обеспечивающей удаление всех голосов до определенного фиксированного блока. Недостаток такого способа был в том, что он не обеспечивал удаление вновь пришедших голосов, которые заново накапливались в системе и по истечении определенного времени также становились ненужными.

Для удаления устаревших голосов в версии SF-0.18.4 конфигурационный файл `config.ini` дополнен новым параметром `clear-votes-older-n-blocks, bpo::value<uint32_t>()->default_value(0xFFFFFFFF)` обеспечивающим сохранение голосов N блоков и удаление голосов в блоках старше N.\
Соответствие задаваемого значения N и выполняемой операции приведено в следующей таблице.

| Значение N | Количество блоков с сохраняемыми голосами | Выполняемая операция                        | Комментарий                                                                                                                                                                                 |
| ---------- | ----------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| N = 0      | 0                                         | Удаление голосов сразу после закрытия поста | Используется для случая, когда не требуется сохранения голосов                                                                                                                              |
| N > 0      | N                                         | Удаление голосов в блоках старше N          | Используется для сохранения голосов N блоков от текущего и удаления голосов в блоках старше N. Значение N показывает разность (возраст) между текущим блоком и блоком, в котором есть голос |
| N = -1     | Все блоки                                 | Удаление голосов не выполняется             | Значение «-1» преобразуется в максимально возможное беззнаковое число (аналог бесконечности). Используется для хранения голосов длительное время                                            |

Во всех случаях удаление голосов не выполняется до закрытия поста.

**Примечание:** Доработка выполнена по просьбе делегатов.

### Возможность настройки конфигурационного файла для увеличения количества ключевых слов или фраз для поиска нужной информации в постах

В предыдущих версиях количество тегов (ключевых слов или фраз) в запросе к Узлу блокчейна ограничивалось пятью, что не всегда было достаточным для более детального описания запрашиваемой информации в постах.

В новой версии максимальное количество тегов в запросе к Узлу блокчейна может быть увеличено до 15 включительно. Кроме этого, введено ограничение на размер тега, составляющее 512 символов. В конфигурационный файл `config.ini` добавлены параметры `tags-number` и `tag-max-length`, с помощью которых пользователь может задать количество и размер тега по своему усмотрению, что позволяет пользователю более гибко настраивать работу блокчейна.

**Изменения в конфигурационном файле config.ini**\
Параметры `tags-number` и `tag-max-length` приведены в следующей таблице.

| Имя              | Тип          | Значение по умолчанию | Комментарий                                                   |
| ---------------- | ------------ | --------------------- | ------------------------------------------------------------- |
| `tags-number`    | std::size\_t | 5                     | Это значение может быть увеличено до 15 включительно          |
| `tag-max-length` | std::size\_t | 512                   | Не рекомендуется устанавливать размер тега более 512 символов |

В случае принимаемого значения параметра `tags-number` по умолчанию доработка имеет обратную совместимость с предыдущими версиями.

## Устранение недостатка в работе приложения cli\_wallet с аккаунтом, имеющим несколько авторизаций

В предыдущих версиях возникала сложность с подписанием аккаунтом транзакции, если этот аккаунт имел возможность авторизоваться ключами сторонних аккаунтов. Перечень имен сторонних аккаунтов содержался в поле `account_auths`.\
Транзакции, создаваемые аккаунтом могли быть подписаны только ключами сторонних аккаунтов из поля `account_auths`. При попытке подписать транзакцию ключом основного аккаунта приложение `cli_wallet` выдавало сообщение об ошибке.\
Для устранения этого недостатка в версии SF-0.18.4 доработан метод `annotated_signed_transaction()` приложения `cli_wallet` с сохранением перечня входных и выходных параметров этого метода. Доработка обеспечила возможность подписывать транзакцию как ключами аккаунтов с именами из поля `account_auths`, так и ключом основного аккаунта.

## Устранение недостатка в отображении авторов в ленте публикаций

Недостаток в отображаемой информации в ленте публикаций проявлялся в случае, когда автор, на публикации которого у пользователя была подписка, перепубликовывал работу стороннего автора. В результате в ленте публикаций отображалась информация о стороннем авторе, на публикации которого у пользователя не было подписки. Из-за отсутствия сообщения о причине его появления у пользователя возникало сложности в восприятии отображаемой информации на ленте публикаций.\
В версии 0.18.4 лента публикаций дополнена полем `"reblogged_by:<a name>"`, в котором отображается имя автора, перепубликовавшего работу стороннего автора.

## Фильтрация запрашиваемой информации об операциях из истории аккаунта

В плагине `account_history` содержится информация о большом количестве операций. С целью ускорения поиска необходимой информации в версии 0.18.4 добавлен параметр, с помощью которого можно фильтровать операции по определенным признакам.

**Изменения в API-методе get\_account\_history**\
В метод добавлен произвольный параметр `query` для фильтрации операций. По умолчанию фильтрация отключена. Метод имеет следующий вид:

```cpp
get_account_history(account_name, [from, [limit, [query]]])
```

Параметры `from` и `limit` в методе являются произвольными и по умолчанию принимают значения «-1» «100» соответственно. Метод может быть вызван с одним заданным параметром (например, `get_account_history(account)`) для получения 100 последних операций аккаунта.\
\
Параметр `query` является структурой (объектом) и содержит следующие поля:\
`select_ops` — перечень операций, которые необходимо получить. Значение может содержать имена операций (в том числе оканчивающие на «\_operation»), а также ключевые слова:\
`ALL` — все операции;\
`REAL` — только операции явно заданные;\
`VIRTUAL` — только виртуальные операции;\
`filter_ops` — перечень операций, которые следует исключить. Принимает те же значения, что и `select_ops`. Это поле является произвольным и по умолчанию принимает значение пусто;\
\
`direction` — «направление» операции относительно аккаунта. Это поле является произвольным и принимает следующие значения:\
`any` — отсутствие направления фильтрации (значение по умолчанию);\
`sender` — характеризует аккаунта как отправителя (например, `creator` или `voter`);\
`receiver`— характеризует аккаунта как получателя (например, `created` или `voted`);\
`dual` — характеризует аккаунта как отправителя и получателя одновременно (например, `voting self post` или операция неоднозначно определяющая аккаунта).

**Изменения в клиентском приложении cli\_wallet**\
Приложение `cli_wallet` дополнено методом `filter_account_history()`, который выполняет те же функции, что и метод `get_account_history()`. В отличие от последнего имеет входной параметр `query` для поддержки фильтрации. Примеры вызова `filter_account_history()`:

```cpp
get_account_history cyberfounder -1 100
filter_account_history cyberfounder -1 100 {"select_ops":["REAL","interest"], "filter_ops":["transfer"]}
filter_account_history cyberfounder -1 100 {"direction":"receiver","filter_ops":["producer_reward"]}
```


# HF19: Новые возможности

## Внедрение реферальной программы в блокчейн Golos

**(Задача** [**№295**](https://github.com/GolosChain/golos/issues/295)**)**

Решением делегатов было предложено реализовать в HF-19.0 новую функциональную возможность — внедрить реферальную программу привлечения новых пользователей.

**Реализация новой функциональности**

Реализация реферальной программы предусматривает вознаграждение пользователей (рефереров), пригласивших для регистрации в блокчейн своих друзей или сторонних лиц через социальные сети (просматривая публикации сторонних авторов или размещая собственные посты о блокчейне).\
Для реализации реферальной программы в HF-19.0 добавлены следующие операции:\
— создание аккаунта-реферала для приглашенного пользователя. В качестве реферера для аккаунт-реферала может быть указан как пользователем, непосредственно пригласивший другого пользователя, так и сторонний аккаунт;\
— прекращение действия реферальной программы пользователем-рефералом через выкуп своего аккаунта. Операция позволяет рефералу выкупить свой аккаунт для прекращения выплат рефереру;\
— получение информации о пользователе-реферале;\
— получение информации о пользователе-реферале по его комментарию или посту.

1\) Пример команды для создания аккаунта-реферала с использованием `cli_wallet` имеет вид:

```
create_account_referral test "0.200 GOLOS" "0.000001 GESTS" <referral account name> "{}" {"referrer": "test", "interest_rate": 900, "end_date": "2018-09-26T14:00:00", "break_fee": "0.000 GOLOS"} true
```

где:\
`referral` — имя аккаунта-реферала;\
`referrer` — имя аккаунта-реферера;\
`interest_rate` — процент выплат рефереру от доходов реферала, умноженный на 100. Максимальный процент выплаты рефереру устанавливается голосованием делегатов через операцию `update_chain_properties()`. Выплаты рефереру осуществляются через назначение реферера бенефициаром в публикуемых постах;\
`end_date` — дата окончания выплат рефереру из доходов реферала. Максимальный срок выплаты рефереру устанавливается голосованием делегатов через операцию `update_chain_properties()`;\
`break_fee` — cумма выкупа рефералом своего аккаунта для прекращения выплат рефереру. Если в качестве сумма выплаты будет указан 0, то аккаунт нельзя будет выкупить. Максимальная сумма выплаты выбирается делегатами через операцию `update_chain_properties()` по медиане.

2\) Пример задания команды для операции по прекращению выплат рефереру имеет вид:

```
break_free_referral <referral account name> true
```

3\) Для получения информации о пользователе-реферале через `cli_wallet` используется команда `get_account`. Для придания аккаунту-рефералу особого статуса в системе в ответ API-метода `golos.api.getAccounts()` добавлены следующие поля:

```
    "referrer_account": "test",
    "referrer_interest_rate": 900,
    "referral_end_date": "2018-09-26T14:00:00",
    "referral_break_fee": "0.002 GOLOS"
```

В период действия реферальной программы для аккаунта-реферала значения полей соответствуют полям из `account_referral_options`. После прекращения действия реферальной программы поля принимают нулевые значения.

4\) Для получения информации о пользователе-реферале по его комментарию или посту в поле `beneficiaries` добавляется объект с параметрами account= и weight=. Выплата рефереру осуществляются с учетом этих параметров.

## Изменение метода начисления вознаграждения кураторам (доработка для штрафного окна голосования)

**(Задача** [**№898**](https://github.com/GolosChain/golos/issues/898)**)**

Начало голосования за пост начинается сразу по завершении его публикации. Размер вознаграждения кураторам за голосование зависит от времени голосования. Длительность интервала, отведенного для голосования составляла 30 мин — аукционное окно (англ. auction window), которое открывалось сразу по завершении создания поста. Вес голоса, отданного в интервале этого окна вычислялся по формуле

```
W = t / (30 × 60) × weight
```

где:\
t — время голосования с момента открытия окна (в секундах);\
(30 × 60) — продолжительность окна (в секундах);\
weight — вес голоса аккаунта.

В соответствии с этой формулой результирующий вес W уменьшается пропорционально раннему голосованию — более ранний голос, отданный в период открытого окна, получает более меньший вес. При этом недостающая (срезанная) часть токенов начисляется автору поста. Голосование в период открытого окна более выгодно авторам поста.

В версии HF-19.0 (по предложению делегатов) доработан алгоритм для более гибкого начисления вознаграждения кураторам, в том числе:\
— стало возможным изменять длительность аукционного окна голосованием делегатов через операцию `update_chain_properties()`;\
— стало возможным недостающую (срезанную) часть токенов возвращать либо в пул вознаграждений, либо кураторам, проголосовавшим после закрытия аукционного окна. Решение о том, куда направлять срезанную часть токенов, принимает автор поста.

С этой целью в метод `comment_options_operation` добавлена опция `comment_auction_window_reward_destination`, принимающая следующие значения:\
`to_reward_fund` — возврат токенов в пул вознаграждений. При возврате токенов в пул-вознаграждений генерируется виртуальная операция auction\_window\_reward\_operation;\
`to_curators` — возврат токенов кураторам, проголосовавшим после закрытия аукционного окна;\
`to_author` — только для постов, созданных до релиза HF-19.0 (после релиза HF-19.0 выбор данного варианта будет невозможным).

## Возможность делегатов изменять интервалы времени, отводимые на создание постов, оставление комментариев и голосование

**(Задачи** [**№№533**](https://github.com/GolosChain/golos/issues/533)**,** [**1002**](https://github.com/GolosChain/golos/issues/1002)**)**

Делегатами было предложено сократить временные интервалы, отводимые на создание постов, оставление комментариев к посту и голосование, составляющие 5 мин, 20 и 3 с соответственно. Такие жестко установленные интервалы имеют недостаток. Например, за отведенное время 20 с могут появиться до десяти и более комментариев, на ответы которых делегатам приходится затрачивать значительное время.

В версии HF-19.0 появилась возможность изменять длительности интервалов (окон), отводимых на создание постов, оставление комментариев и на голосование, а также возможность изменять предельно допустимое количество постов, комментариев и голосов, оставляемых в течение этих интервалов.

В операцию `update_chain_properties`, с помощью которой конфигурируется блокчейн, добавлены параметры `posts_window`, `posts_per_window`, `comments_window`, `comments_per_window`, `votes_window`, `votes_per_window`. С помощью этих параметров делегаты могут задавать длительности интервалов, в течение которых разрешается создавать посты, оставлять комментарии и голосовать, а также допустимое количество комментариев и голосов, оставляемых в течение этих интервалов. Значения этих параметров определяются голосованием делегатов через операцию update\_chain\_properties(), за результаты которых принимаются медианные значения.

В версии HF-19.0 длительность окна для комментирования и допустимое количество оставленных комментариев в течение этого окна составляют 200 с и 10 шт. соответственно. Длительность окна для голосования и допустимое количество отданных голосов в течение этого окна составляют 15 с и 5 шт. соответственно.

Кроме этого в версии HF-19.0 доработан алгоритм, ограничивающий чрезмерную активность пользователей в создании постов, в комментировании и голосовании. Алгоритм позволяет более гибко совершать действия подряд без ожидания завершения 20-секундного интервала до начала следующего действия. Алгоритм работает по принципу «батарейки». Минимальная частота совершаемых действий определяется по формуле

```
V=window/items
```

где:\
`window` — длительность интервала, отведенного на отдельный вид действий;\
`items` — количество публикаций, комментариев или голосов, оставленных за отведенный интервал.

Медианное значение выбирается через сортировку указанных делегатами значений по двум величинам — минимальная частота действий, и длина окна в которое эти действия можно совершать.

Пользователь может создавать посты, оставлять комментарии или участвовать в голосовании при условии наличия ресурсов (заряда) в его «батарейке». Алгоритм фиксирует время появления поста и содержимого заряда «батарейки», расходуемого с оставлением каждого комментария к посту или голосованием.

## Начисление делегирующему Силы голоса доли от кураторских

**(Задача** [**№756**](https://github.com/GolosChain/golos/issues/756)**)**

Количество желающих делегировать Силу голоса невелико. Отчасти это вызвано тем, что делегирующий (инвестор СГ) не получает каких-либо отчислений от кураторских вознаграждений и следовательно не получает вознаграждение вообще.

В версии HF-19.0 добавлена возможность устанавливать процент отчислений инвестору СГ. Куратору, которому делегируется СГ, по результатам голосования за пост отчисляет часть кураторских выплат инвестору.\
Алгоритм начисления инвесторам СГ реализован в соответствии со следующими особенностями :\
1\) Выплата вознаграждений инвесторам происходит одновременно с выплатами кураторам, которым делегировали СГ инвесторы. Инвестору начисляется определенный процент от выплаты куратору. Размер отчисления инвестору определяется по следующей формуле:

```
Вознаграждение инвестору = (вознаграждение куратора) × (доля инвестора в СГ куратора) × (процент отчислений инвестору)
где:
доля инвестора в СГ куратора = (количество делегированной СГ) / (общее количество СГ куратора)
```

2\) Процент отчислений инвестору назначается непосредственно инвестором. Верхнее значение процента отчислений инвестору устанавливается голосованием делегатов с использованием операции `update_chain_properties()`.

3\) В блокчейн добавлена новая виртуальная операция `delegation_reward_operation`, которая используется для уведомления делегаторов о получаемых ими вознаграждениях за делегированную СГ.

4\) Возможность отказа от делегированной СГ получателем (в случае нежелания обмена выплат с инвестором). Для этого была добавлена операция `reject_vesting_shares_delegation_operation`.\
При отказе получателя от делегированной СГ, ее автоматическое зачисление на его баланс получателя не производится. Возврат делегированной СГ делегатору происходит после окончания заморозки длительностью 7 дней.

## Возможность пользователя хранить личную информацию  в хэш-таблице хранилища в виде key-value

**(Задача** [**№924**](https://github.com/GolosChain/golos/issues/924)**)**

Решением делегатов было предложено реализовать в HF-19.0 новую функциональную возможность — предоставить возможность пользователю сохранять нужную ему информацию в хэш-таблице хранилища в виде key-value.

Решение основано на создании нового плагина `account_notes`, который позволяет аккаунту сохранять необходимую для него информацию в хэш-таблице базы данных системы в виде записей «key-value» в зависимости от настроек конфигурационного файла `config.ini`. Объем информации для хранения на отдельном Узле (ноде) блокчейна определяется с учетом ресурсов этого Узла.

В плагине `account_notes` реализован вызов операции `set_value_operation`, выполняющей создание, изменение и удаление записи в хэш-таблице хранилища. Операция вызывается с полями account, key и value.\
Для изменения записи в хэш-таблице операция вызывается с ключом уже имеющейся записи. Для удаления записи в хэш-таблице операция вызывается с ключом уже имеющейся записи и пустым значением.

В конфигурационный файл `config.ini` добавлены следующие настраиваемые параметры: — `an-tracked-accounts` — «белый» список аккаунтов. Используется для задания списка аккаунтов, которым разрешено сохранять записи. По умолчанию задается пустое поле, разрешающее хранение записей всем аккаунтам;\
— `an-untracked-accounts` — «черный» список аккаунтов. Содержит список аккаунтов, которым не разрешается хранение записей. По умолчанию задается пустое поле;\
— `an-max-key-length` — максимально допустимое количество символов в ключе. По умолчанию содержит значение 20;\
— `an-max-value-length` — максимально допустимое количество символов в записи. По умолчанию содержит значение 512;\
— `an-max-note-count` — максимально допустимое количество записей для одного аккаунта. По умолчанию содержит значение 10.

В случае превышения в сохраняемой записи установленных граничных значений операция не выполняется. При этом сообщение об ошибке не выдается. Для контроля успешного сохранения информации пользователь должен запросить у Узла его текущую конфигурацию и сопоставить данные сохраняемой записи с граничными значениями этого Узла.\
После HF-19.0 стоимость ресурсов бендвича для операций `custom_json` будет увеличиваться за счет умножения на значение мультипликатора. По умолчанию значение мультипликатора составляет 100. Делегаты могут изменить данное значение путем голосования через операцию `update_chain_properties()`. Это позволяет пользователям с большим количеством СГ сохранять в хэш-таблице информацию более часто и большего размера в отличие от пользователей с меньшим количеством СГ.

## Возможность автора устанавливать размер кураторских отчислений за пост

**(Задачи** [**№№324**](https://github.com/GolosChain/golos/issues/324)**,** [**677**](https://github.com/GolosChain/golos/issues/677)**)**

В предыдущей версии доля выплаты кураторам была неизменной и составляла 25 % от суммы вознаграждения автору поста. В версии HF-19.0 делегатам предоставляется возможность изменять это значение и устанавливать границы его изменений в интервале от 25 до 100 % включительно.

В случае, если делегаты устанавливают интервал возможных значений доли выплаты кураторам, авторы также могут устанавливать это значение по своему усмотрению для каждого публикуемого поста, но в пределах установленных делегатами границ. После создания поста автор может указать процент кураторских отчислений от ожидаемого вознаграждения за этот пост (автор не может выбрать процент кураторских отчислений до тех пор, пока делегаты не установят его граничные значения). Это позволяет автору поста увеличивая процент кураторских отчислений, стимулировать кураторов голосовать за их посты чаще.

Сумма средств, полученная от процента кураторских отчислений, распределяется между кураторами в соответствии с их весом. Вес куратора определяется по одному из трех алгоритмов:

* Старый алгоритм (bounded) — алгоритм, в соответствии с которым доля кураторского вознаграждения определяется в зависимости от времени голосования и используемой Силы Голоса. В версии HF-19.0 этот метод распределения вознаграждения между кураторами сохраняется. &#x20;
* Линейный алгоритм (linear). Вес куратора зависит от средств в виде Силы Голоса и не зависит от времени голосования. Устанавливается по умолчанию. &#x20;
* Алгоритм квадратного корня (sqrt\_root). Вес куратора вычисляется с учетом уже имеющихся голосов за пост (отданных другими кураторами) и зависит от времени голосования. Например, если проголосовали 2 куратора с одинаковой Силой Голоса, но в разное время, то второй из проголосовавших получит вознаграждение меньше первого в два раза. &#x20;

В версии HF-19.0 делегатам предоставляется возможность выбирать один из трех приведенных алгоритмов через операцию `update_chain_properties`.

В операцию `comment_options_operation` добавлена структура `comment_curation_rewards_percent`. С помощью этой операции автор может задать процент кураторских отчислений.

**Примечание:**\
Поскольку данная функциональность не утверждена делегатами, в настоящий момент процент кураторских выплат зафиксирован и составляет 25 %.

## Устранение недостатка в ответе API-метода get\_account

**(Задача** [**№825**](https://github.com/GolosChain/golos/issues/825)**)**

Во входящем ответе на запрос `get_accounts` API-метода информация о количестве постов и комментариев находилась исключительно в поле `post_count`, при этом поле `comment_count` всегда возвращалось пустым. Также при этом отсутствовало какое-либо сообщение об ошибке, что могло привести пользователей в конфузное состояние.

В версии HF-19.0 этот недостаток устранен. Был доработан метод `get_accounts` для корректной записи данных в соответствующие поля при создании поста и комментария. Поле `comment_count` содержит количество комментариев, а поле `post_count` — только количество постов.

## Изменения в логике системы при долге системы, превышающем 10 %

**(Задача** [**№952**](https://github.com/GolosChain/golos/issues/952)**)**

В предыдущих версиях блокчейна в логику системы в части эмиссии GBG был заложен следующий алгоритм:

* если общая стоимость всех токенов GBG,  рассчитанная по заложенной в системе цене,  не превышает 10 % от стоимости всех токенов GBG и GOLOS, авторам постов начисляется вознаграждение в соответствии со следующей схемой: &#x20;
  * если долг системы не превышает 2 %, то авторам постов начисляется вознаграждение в виде GBG; &#x20;
  * если долг системы выше 2 %, но не превышает 5 %, то авторам постов начисляется вознаграждение в виде GBG и GESTS. При этом, при увеличении долга системы от 2 до 5 % включительно количественное соотношение GBG к GESTS пропорционально уменьшается (например, при долге системы 3,5 % вознаграждение начисляется в виде GBG и GESTS в соотношении 1:1. При долге системы 5 % вознаграждение начисляется только в виде GESTS); &#x20;
  * если долг системы превышает 5 %, прекращается начисление вознаграждения авторам постов. При этом владельцам токенов GBG выплата процентных начислений не прекращается;  &#x20;
* если общая стоимость всех токенов GBG,  рассчитанная по заложенной в системе цене,  превышает 10 % от стоимости всех токенов GBG и GOLOS, выплата процентных начислений владельцам токенов GBG продолжается без прекращения эмиссии этого вида токенов. &#x20;

В версии HF-19.0 внесены изменения в логику системы в части эмиссии GBG. Изменилась работа алгоритма при долге системы, превышающем 10 %. Измененная часть алгоритма:

* если общая стоимость всех токенов GBG,  рассчитанная по заложенной в системе цене,  превышает 10 % от стоимости всех токенов GBG и GOLOS, выплата процентных начислений владельцам токенов GBG прекращается без прекращения эмиссии этого вида токенов.&#x20;

При превышении долга системы на 10 % в системе устанавливается флаг, сигнализирующий достижение граничного значения токена GBG. Пользователь будет оповещен о состоянии этого флага при выполнении API-операции получения информации о текущем состоянии системы.

## Сброс понижения силы голоса на другой аккаунт после восстановления учетной записи

**(Задача** [**№971**](https://github.com/GolosChain/golos/issues/971)**)**

В предыдущих версиях блокчейна отсутствовала защита средств, имеющихся на счету аккаунта, в случае несанкционированного доступа к личному ключу аккаунта. Злоумышленник, завладев личным ключом аккаунта, мог поменять его и от имени аккаунта запустить операцию по выводу всех средств в виде GESTS. При этом при восстановлении аккаунта операция по выводу средств продолжалась и попытка отменить ее завершалась безуспешно.

В версии HF-19.0 введена доработка, обеспечивающая блокировку операции по выводу средств со счета аккаунта в случае потери личного ключа или несанкционированного доступа к личному ключу аккаунта.\
Доработана операция `withdraw_vesting`. Операция по выводу средств длится в течение 13 недель. Во время выполнения этой операции с частотой один раз в семь дней выводятся средства в виде GESTS. После восстановления учетной записи (аккаунта) автоматически отменяется операция `set_withdraw_vesting_route`. Удаляются все выводы из расписания. При этом все выплаты в GESTS восстанавливаются за исключением той части средств, которая уже до восстановления учетной записи была выведена в качестве выплат.

## Оптимизация расчета ожидаемых выплат автору и кураторам

**(Задача** [**№976**](https://github.com/GolosChain/golos/issues/976)**)**

После публикации поста открывается окно для голосования, за время которого определяется процент начисления автору и кураторам от вознаграждения за публикацию поста. Алгоритм выплаты состоит из таких операций как просмотр списка кураторов, определение процента выплат для каждого из кураторов, а также время их голосования с учетом штрафного окна. На этот процесс затрачиваются значительные ресурсы системы. Чтобы автор и куратор могли получить информацию об ожидаемых (прогнозируемых) им выплатах, потребовалось бы выполнять более сложные расчеты и, соответственно, увеличивать нагрузку на систему.

В новой версии блокчейна предложено для демонстрации ожидаемых выплат автору и кураторам расчет выполнять более простым способом, обеспечивающим получать значения выплат близким к реальным и с наименьшей нагрузкой на систему.\
После реализации стратегий с помощью окна аукциона получаемое сообщение имеет полную информацию о весе голосов кураторов, поэтому расчет ожидаемых выплат может быть оптимизирован. Из алгоритма вычисления ожидаемых выплат удалены операции, результат которых не оказывает существенного влияния на конечный результат. Сокращение операций в алгоритме вычисления ожидаемых выплат обеспечил снижение нагрузок на систему без существенного отклонения от реальных значений выплат.

## Возможность постраничного просмотра и сортировки результата, получаемого от API-запроса

**(Задача** [**№981**](https://github.com/GolosChain/golos/issues/981)**)**

Просмотр списка проголосовавших за пост выполняется через API-запросы вида `social_network::select_active_votes`. Количество проголосовавших может быть чрезмерно большим и поэтому просмотр списка голосов в виде «лайков» или «дизлайков» может занимать длительное время. В предыдущей версии блокчейна голоса появлялись в списке в соответствии с их появлением в окне голосования без учета их веса, что затрудняло анализ результатов голосования.

В версии HF-19.0 реализована новая функциональная возможность, обеспечивающий постраничный ввод списка проголосовавших, а также сортировку голосов по уменьшению их веса (голоса с наибольшим весом располагаются в начале списка). Сортировка голосов выполняется автоматически. Доработка позволяет сократить время на просмотр результатов голосования.

## Устранена ошибка в подсчете количества личных сообщений

**(Задача** [**№990**](https://github.com/GolosChain/golos/issues/990)**)**

Пользователь имеет возможность получать статистическую информацию о количестве поступающих личных сообщений от аккаунтов, в том числе от закрепленного с ним в переписке (англ. pinned), от неизвестного (англ. unknown) и заблокированного (англ. ignored) аккаунтов. В предыдущей версии блокчейна после удаления пользователем сообщений от одного из этих типов аккаунтов, данные о количестве личных сообщений от другого типа аккаунта могли быть также изменены и быть некорректными (например, отображать максимально возможное значение). В версии HF-19.0 доработаны счетчики, обрабатывающие количество поступающих пользователю личных сообщений, для каждого типа аккаунтов. Доработка обеспечила корректный подсчет личных сообщений пользователя, поступающих от аккаунтов всех типов.

## Используемая терминология

**Аккаунт-реферал** — аккаунт, созданный для приглашенного в систему пользователя (реферала) другим пользователем (реферером) этой системы.\
**Медианное значение** — значение, определяемое выборкой из середины множества чисел, расположенных в определенном порядке (по убыванию или по возрастанию). Например, медианное значение множества {8, 8, 7, 2, 1} равняется 7, так как это число находится в середине множества. Если множество состоит из четного количества чисел, то результатом является полусумма двух соседних значений. Например, медианное значение множества {7, 5, 3, 1} равняется 4.\
**Реферал** (англ. referral) — пользователь системы, приглашенный и зарегистрировавший в системе по рекомендации другого пользователя этой системы.\
**Реферер** (англ. referrer) — пользователь системы, привлекающий в данную систему других пользователей.


# HF20: Устранение бага

## Внесено изменение в программный код вычисления процента отчислений делегатору при голосовании за пост (задача [№1074](https://github.com/GolosChain/golos/issues/1074))

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

Делегаторы, для которых операция вычисления процента выплаты от кураторских вознаграждений завершилась успешно, получат вознаграждение в соответствии с вычисленным процентом

## Внесен запрет на изменение процента выплаты от кураторских вознаграждений после начала голосования (задача [№1075](https://github.com/GolosChain/golos/issues/1075))

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


# HF22: Новые возможности

## Система воркеров

О системе воркеров/исполнителей можно прочитать [здесь](https://golos.id/ru--golos/@lex/sistema-vorkerov-dlya-golos-blockchain), этот функционал позволит привлечь пользователей к участию в развитии Golos Blockchain, появлению новых приложений, клиентов, игр, ботов, документации, маркетинговой активности и многому другому.

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

## Распределение эмиссии

У делегатов появилась возможность менять параметры % распределения эмиссии по пулам

* worker\_reward\_percent
* witness\_reward\_percent
* vesting\_reward\_percent&#x20;

Также были сняты ограничения по параметрам на % прибыли от делегирования `max_delegated_vesting_interest_rate` ([исключен предел](https://github.com/GolosChain/golos/issues/1008) в макс. 80%) и кураторских отчислений `min_curation_percent` ([исключен предел](https://github.com/GolosChain/golos/issues/1009) в мин. 25%). Оба параметра опционально позволят исп. делегатам значения в диапазоне от 0 до 100%. Параметр количества апвоутов в день `vote_regeneration_per_day` сделан голосуемым делегатами (по умолчанию 10 вместо 40).

Исправлена и [ошибка](https://github.com/GolosChain/golos/issues/1010) из-за которой пользователи не могли добавлять посты в случае превышения порога активности на публикацию комментариев.

## Понижение СГ при неактивности

В случае если на аккаунте в течении 12 месяцев (срок голосуемый делегатами `account_idleness_time`) не было совершенно действий с использованием активного ключа (перевод токенов, ставка на внутренней бирже, голос за делегата и пр.) - отменяется делегирование и запускается механизм понижения Силы Голоса в ликвидные токены Голос.

Тем самым такие аккаунты перестанут влиять на выбор делегатов и получать % на вестинг/СГ из эмиссии при "полной пассивности" участия в проекте.

## Принцип голосования за делегатов

Кардинально [изменился](https://github.com/GolosChain/golos/issues/820). Если ранее можно было выбирать до 30 делегатов с полным весом своего стека СГ за каждого из них (о минусах подобного писали [тут](https://golos.id/newgolos/@newgolos/voterules323289)), то после 22ХФ размер стека СГ стал делиться на кол-во поддерживаемых делегатов.

Напр. если у вас 30 000 СГ и вы поддержите 3 делегатов, в поддержку каждого из них "пойдет" по 10 000 СГ.

Также в код был добавлен автоматический сброс голосов с делегатов, у которых прошло 12 месяцев (срок голосуемый делегатами `witness_idleness_time`) с момента подписания последнего блока.

## Решение по вопросу GBG

С учётом того, что вариант из [поста](https://golos.id/golos/@gusaru/sostoyanie-defolta-golos-blockchain-i-chto-s-etim-delat) @gusaru ранее [рассматривался](https://steemit.com/steem/@dantheman/steem-dollar-stability-enhancements) как оптимальный и одним из создателей Bitshares/Steem/EOS, в составе 22ХФ была принята именно эта реализация: *при объеме долга более 20% запускается механизм ежедневной конвертации 1% доступных на балансах GBG в GOLOS* (ордера на внутренней бирже перед конвертацией будут отменяться).

Процент ежедневной конвертации `sbd_debt_convert_rate` голосуемый делегатами, по умолчанию 1%.


# HF23: Новые возможности

## Система вознаграждений (донаты)

Поступающий процент от эмиссии токенов блокчейна в Силу Голоса пользователей будет накапливаться на промежуточном **CLAIM-балансе** (в БЧ `accumulative_balance`).

С него, в рамках срока установленного делегатами по параметру `claim_idleness_time` пользователи смогут получать (операция `claim`) свою долю с вариантом вывода её как в пополнение Силы Голоса, так и на отдельный **TIP-баланс** для вознаграждений.

Именно с этого баланса пользователи смогут вознаградить пост/комментарий/автора, любую иную активность к которой разработчики привяжут новую операцию `donate` (напр. вознаграждения токенами Голос сообщений в мессенджерах, играх и пр.). Фактически это появление **персональных пулов вознаграждений**, когда сам пользователь решает как распорядиться долей от эмиссии без борьбы за общий пул.

Важно заметить, что `claim_idleness_time` по умолчанию 1 сутки, однако делегаты могут сделать этот параметр с большей длительностью.

Если же за установленный срок токены не были востребованы пользователями, их доля от эмиссии будет направлена в фонд воркеров на дальнейшее развитие проекта.

TIP-баланс можно пополнять с основного баланса (операция `transfer_to_tip`), выводить токены, полученные на TIP-баланс, возможно через увеличение Силы Голоса (операция `transfer_from_tip`).

Команды для тестирования через cli\_wallet можно найти в [этом ](https://golos.id/ru--golos/@lex/23-khardfork-uzhe-blizko-predlagayu-delegatam-potestirovat)посте, примеры сериализации к новым операциям в [обновлении](https://github.com/golos-blockchain/golos-lib-js/commit/6d85d634205ee12b7ec43ed13b1d006f61291c64) JS библиотеки.

## Снижение срока понижения СГ

С учётом перехода к новой системе вознаграждений и обсуждений делегатов принято компромиссное изменение - срок понижения Силы Голоса в 8 недель (было 13 недель).

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

## Система чеков/инвайтов

Пользователи смогут создавать чеки/коды на любое количество ликвидных токенов, имеющихся на балансе. Такие чеки/коды на предъявителя представляют собой пару ключей (публичный и приватный), публичным можно проверять баланс чека (`get_invite`), приватный служит для получения средств. Получателем может быть любой аккаунт, в том числе и тот, что выписал чек.

Добавлен делегатский параметр минимальной суммы чека/инвайта `min_invite_balance` (по умолчанию 10 токенов Голос).

С помощью чеков/инвайтов можно будет регистрировать новые аккаунты (операция `account_create_with_invite`). Баланс чека/инвайта будет конвертирован в Силу Голоса создаваемого аккаунта, такой вариант возможно подойдёт для привлечения на проект популярных авторов с других сайтов, чатов где будут использоваться боты с механикой донатов (с выделением из фонда воркеров на подобный целевой маркетинг токенов и создания инвайтов cо стартовым балансом).

С использованием кодов/чеков токены Голос станет проще и продавать/покупать через площадки цифрового контента, распечатывать в виде QR-кодов, игровых сценариев и т.д.

**Примеры операций к cli\_wallet:**

`invite cyberfounder "11.000 GOLOS" "GLS7Pbawjjr71ybgT6L2yni3B3LXYiJqEGnuFSq1MV9cjnV24dMG3" true`

`claim_invite cyberfounder cyberfounder "5JFZC7AtEe1wF2ce6vPAUxDeevzYkPgmtR14z9ZVgvCCtrFAaLw" true`

`create_account_invite cyberfounder cat "{}" "5JFZC7AtEe1wF2ce6vPAUxDeevzYkPgmtR14z9ZVgvCCtrFAaLw" true`

## Печать токенов GBG

С учетом приблежающегося [выхода из долга](https://golos.id/golos/@gusaru/sostoyanie-defolta-golos-blockchain-i-chto-s-etim-delat) по токену GOLD BACKED GOLOS были внесены изменения и по их печати. При её начале золотые станут поступать в фонд воркеров для дальнейшего распределения по заявкам в результате голосования сообщества.

## Изменения по реферальной программе

Были внесены изменения в реализованный [19 ХФ](/developers/hardforks/hf19_release) вариант реферальной системы, теперь она распространяется и на донаты.

С правками на веб-клиенте пользователи получат возможность привлекать новых авторов, а 10% от отправляемых им донатов будут поступать на баланс пригласившего/реферера в течении 6 месяцев. За счёт [гибкой параметризации](https://wiki.golos.id/developers/hardforks/hf19_release), детали реферальной системы могут быть изменены делегатами после обсуждения с пользователями.

**Был исправлен и ряд ошибок/багов**: перезапуск docker-контейнера ноды, запуск ноды с mongo-плагином, пропуск блоков из-за нагрузки обработки множ. операций и другие...


# HF24: Новые возможности

## Создание собственных токенов (UIA)

Функциональность эмитированных пользователями активов (User Issued Assets). Это позволит создавать на блокчейне свои собственные токены (торговать ими на внутренней бирже), использовать в качестве вознаграждений/донатов, интеграции в сервисах, ботах, играх, запуска шлюзов/бирж.&#x20;

Плата за создание ассета/токена поступает в фонд воркеров, по умолчанию значение голосуемого делегатами параметра `asset_creation_fee` - 2000 GBG\
\
Примеры операций для cli-wallet и JS, доступны в описании реализации [тут](https://golos.id/ru--golos/@lex/uia-v-testovoi-seti-prisoedinyaites), о веб-интерфейсе также был [пост](https://golos.id/ru--golos/@lex/interfeis-k-uia-planiruemye-v-24khf) и [дополнения](https://golos.id/ru--golos/@lex/interfeis-k-uia-dopolneniya).

## Чеки-кошельки (без исп. аккаунтов)

С внедрением [функционала чеков/инвайтов](https://golos.id/ru--golos/@lex/anons-23-khf-golos-blockchain#sistema-chekov-invaijtov) в 23ХФ (описание интерфейса по работе с чеками [здесь](https://golos.id/ru--golos/@lex/cheki-kak-instrument-peredachi-tokenov)) в сообществе возникли идеи по развитию этого направления.

Дополнения позволят пользователям передавать токены (в том числе и UIA) через балансы чеков, не создавая аккаунт в блокчейне. По сути, пара приватный ключ + публичный ключ станет своего рода крипто-кошельком, и предоставляя данные публичного ключа, пользователь сможет получать переводы/трансферы непосредственно на такой чек-кошелёк.\
\
Добавлен и голосуемый делегатами параметр `invite_transfer_interval_sec` (в целях защиты от спама переводами с чека на чек, по умолчанию 60 сек).

Подробнее о операциях и реализации можно прочитать в [этом посте](https://golos.id/ru--golos/@lex/cheki-bez-isp-akkauntov-v-testovoi-seti).

Кроме того, в целях мер по снижению инфляции и долга GBG делегатам блокчейна Голос в данном хардфорке предлагается направить токены аккаунта `bittrex` на `null`, произведя их сжигание из экономики (выведение из оборота).

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


# HF25: Новые возможности

* Внесены правки в плагин [account\_notes](/developers/hardforks/hf19_release#vozmozhnost-polzovatelya-khranit-lichnuyu-informaciyu-v-khesh-tablice-khranilisha-v-vide-key-value) для предстоящего запуска [веб-клиента форумов](https://golos.id/ru--golos/@lex-escrow/zayavka-na-razrabotku-foruma-veb-klienta-s-otkrytym-kodom) на блокчейне Голос (запись разделов/категорий, модераторов, блокировок и прочее).<br>
* Добавлено условие "неснижаемого остатка" при автопонижении Силы Голоса [по неактивности](/developers/hardforks/hf22_release#ponizhenie-sg-pri-neaktivnosti) (\~10 Силы Голоса), чтобы в случае возвращения пользователей не возникало проблем с пропускной способностью аккаунта.<br>
* Изменения по вопросу отсутствия торговой комиссии эмитенту UIA токена в случае сделок по уже существующим ордерам на внутренней бирже.<br>
* Добавлено округление торговой комиссии по сделкам где кол-во знаков после запятой в UIA токене таково, что процент комиссии умноженный на сумму сделки был меньше возможного, округление до последнего знака.


# HF26: Новые возможности

## **Конвертация токенов GOLOS в GBG**

Расширен функционал внутренней конвертации токенов, стал возможен обмен GOLOS на GBG по среднему 3.5 дневному курсу делегатских котировок. Доработан интерфейс конвертации в обе стороны, с отображением примерной суммы (по текущей медиане) и размера комиссии. [Подробнее](https://golos.id/ru--golos/@lex/osnovnye-izmeneniya-26khf-uzhe-v-testovoi-seti).

Добавлен делегатский параметр процента комиссии по конвертации `convert_fee_percent`, 5% по умолчанию.

## **Доработка параметров распределения эмиссии**

В целях исключения манипуляций с медианой и возникновения ошибок, в параметрах исключена «взаимозависимость» и они заменены на `worker_emission_percent` и `vesting_of_remain_percent`

Где `worker_emission_percent` процент эмиссии, поступающий на наполнение фонда воркеров, а `vesting_of_remain_percent` процент распределения оставшейся эмиссии на пул вестинга и общий пул.

Несменяемое годами значение 15% на вознаграждения делегатов вернулось из параметров в конфиг, `worker_emission_percent` 1%, `vesting_of_remain_percent` 80%. Что означает, 80% от оставшихся 84% эмиссии (67.2% эмиссии) пойдёт пул вестинга/СГ, 20% (16.8% эмиссии) в общий пул.

## **Минимум СГ для получения кураторских наград**

Добавлен делегатский параметр минимальной суммы СГ, с которой пользователь начинает получать процент за курирование контента. `min_golos_power_to_curate`, 1000 GOLOS по умолчанию.

## **Влияние на репутацию пользователей из профиля**

Как и ранее, для снижения репутации нужно иметь репутацию выше, операции повышения/понижения расходуют батарейку апвоутов, но не влияют на распределение общего пула, не имеют ограничений в 7 дней и не могут быть отменены.

Была доработана `vote_operation`, без указания `permlink` в операции. В интерфейсе веб-клиента добавлена страница со списком аккаунтов, ушедших в отрицательную репутацию за поcледнее время (виртуальная операция `minus_reputation_operation`). [Подробнее](https://golos.id/ru--golos/@lex/osnovnye-izmeneniya-26khf-uzhe-v-testovoi-seti).

## **Параметризируемые лимиты при отриц. репутации**

Проведен перенос репутации из плагина и добавлены делегатские параметры на постинг-активность аккаунтов с отрицательной репутацией.

По умолчанию за сутки (1440 в минутах) - 3 поста/комментария/апвоута.

`negrep_posting_window: 1440`\
`negrep_posting_per_window: 3`

Кроме того, доработаны имеющиеся «антиспам» параметры:

```
"posts_window": 32767,
"posts_per_window": 4,
"comments_window": 32767,
"comments_per_window": 80,
"votes_window": 32767,
"votes_per_window": 80,
```

Значения в секундах будут пересчитаны на минуты. Делегаты смогут установить 12 часов, сутки, иные значения (не упираясь в текущий потолок 32767 секунд \~9 часов).

## **Добавлен** event-плагин

Что позволит получать события с виртуальными операциями для развития функционала веб-клиентов, альтернативы получения/стриминга блоков и пр. \
\
Для настройки, добавить к списку плагинов в конфиге ноды `event_plugin` и

```
store-evaluator-events = true
event-blocks = 600
```

*Информация будет дополнена.*

**Также**, были восстановлены и добавлены тесты для нод, для локализации ошибок доработана запись стектрейса в логах докера ноды. В случае необходимости вывода строк сборку запускать в режиме Debug (добавив к `docker build` параметр `--build-arg TYPE=Debug).`

Исправлена ошибка с отменой всех ордеров (в том числе и по UIA токенам) на внутренней бирже при автоконвертации GBG.

Доработано начисление процентов держателям GBG в случае активного параметра `sbd_interest_rate`, только на сейф-балансе.


# HF27: Новые возможности

## Делегирование СГ с правом на эмиссию

В дополнение к имеющемуся делегированию СГ с процентом (когда часть кураторских поступает инициатору, другая получателю), была добавлена опция при которой станет возможным делегировать СГ с передачей права получения эмиссии.

У получателя появляется своего рода автоматически и ежечасно наполняемый персональный пул для вознаграждений с TIP-баланса (за счет эмиссии на спонсорское делегирование СГ).&#x20;

В методе [get\_accounts](https://gapi.golos.today/api/database_api/get_accounts?ws=https%3A%2F%2Fapibeta.golos.today\&accountNames_0=abc) были добавлены поля:\
`emission_received_vesting_shares` (сколько СГ с правом на эмиссию было получено)\
`emission_delegated_vesting_shares` (сколько делегировано другим)

[Доработана](https://github.com/golos-blockchain/libs/commit/885a8cef2ad92f29df4e2c73b435f7828380d60c) операция `delegate_vesting_shares_with_interest`, где поле `extensions` расширяется параметром `interest_direction` (`is_emission = true`).

## Эмиссия за стейкинг в СГ на TIP-баланс

Так как с момента появления CLAIM-баланса невостребованная пользователями часть эмиссии (что отправлялась в фонд сообщества) снизилась с \~12% до менее 3%, а также решения большинства проявлять свою «активность» ботами, были внесены правки.

После ХФ начисление эмиссии за стейкинг токенов в Силе Голоса станет автоматическим, но с поступлением на TIP-баланс (шаг в сторону развития донатов, сервисов, игр).

## Создание аккаунтов переводом токенов

В блокчейне добавится ещё один способ создания аккаунта, переводом токенов на спецаккаунт **newacc**.

Это позволит купив токены на бирже или обменнике вывести их сразу для анонимного создания аккаунта. Например, пользователь отправляет 1000 токенов с заметкой/memo к переводу **НовоеИмя:ПубличныйКлюч** (`vasya:GLS6XuUhWu1LmCbBmQX8c5861Q3L1VzKALVqy1JcYzECxQKGbR4q`), в БЧ создается аккаунт с этим ключом для owner/active/posting/memo прав.

С суммы перевода вычитается комиссия, установленная делегатами (как видно на [explorer.golos.id](https://explorer.golos.id/) сейчас `Account Creation Fee = 25.000 GOLOS`), остальные токены начиcляются в Силу Голоса аккаунта.

Для тех кто не готов проверять [доступность](https://gapi.golos.today/api/database_api/get_accounts) имени, [генерировать](https://gapi.golos.today/utils/keys) пару (приватного + публичного) ключей, регистрация переводом токенов будет добавлена и в сервисе [Golos Auth](https://golos.app/register), тут и проверка имени, генерация ключа, подсказки...

## Комиссии за создание аккаунтов

Доработаны параметры комиссии за создание аккаунтов в блокчейне, [устанавливаемые делегатами](https://props.golos.today/chainprops).

Теперь fee/комиссия будет поступать в [фонд сообщества](https://golos.today/workers) на развитие проекта, вне зависимости от способа:

* операция `account_create` или `перевод на newacc` (параметр комиссии `Account Creation Fee`)
* операция `account_create_with_delegation` (параметр `Create Account Min Golos Fee`)
* операция `account_create_with_invite` (параметр `Min Invite Balance`)

## Заморозка «забытых» аккаунтов

После обсуждений вопроса о сбросе аккаунтов (описанного [в заявке](https://golos.today/@lex-escrow/zayavka-na-registraciyu-perevodom-dorabotku-komissii-sbros-akkauntov-pravki-servisa-registracii-khf27)), реализован более «мягкий» вариант - заморозка аккаунтов.

Он не коснется [\~912 пользователей](https://dpos.space/golos/top/gp/10) с более 100 токенами в Силе Голоса и [\~7745 пользователей](https://dpos.space/golos/top/golos/78) с более 100 токенами на ликвидном балансе. Достаточно иметь на ликвидном балансе **или** СГ аккаунта 100 и более токенов.

При этом около 160 тысяч аккаунтов будут «заморожены», что даст оптимизацию внутренних процессов на нодах блокчейна (циклы начисления эмиссии, автопонижения СГ, конвертации GBG и пр.), а также снижение рисков спам-активности с «забытых» аккаунтов.

В БЧ добавлена виртуальная операция списания токенов за активацию аккаунта `account_freeze` (по ней же можно отслеживать кто «возвращается»):

```
"account_freeze",
{
    "account": "abc",
    "frozen": false,
    "unfreeze_fee": "25.000 GOLOS"
}
```

В методе [get\_accounts](https://gapi.golos.today/api/database_api/get_accounts?ws=https%3A%2F%2Fapibeta.golos.today\&accountNames_0=abc) добавляются поля:

```
"frozen": true (заморожен ли)
"freeze": {
    публичные ключи...
    "hardfork": 27 (в каком ХФ)
    "frozen": "2022-08-04T12:38:00" (когда)
```

Доработан метод [lookup\_accounts](https://gapi.golos.today/api/database_api/lookup_accounts?ws=https%3A%2F%2Fapibeta.golos.today\&limit=20), в котором по умолчанию будет выгружаться список без «замороженных», снижая дерганье аккаунтов в запросе с \~170 до \~10 тысяч.

## Замена `recovery_account` gc-regfund

С учетом реализации [интерфейса по восстановлению](https://golos.today/@lex/vosstanovlenie-dostupa-s-recovery-akkaunta-optimizaciya-delegatskikh-nod-pravki-registracii) аккаунтов в случае их кражи и сброса ключей, установленный в 21 транзитном хардфорке мультисиг-аккаунт [@gc-regfund](https://golos.today/@gc-regfund) в ожидаемом 27 ХФ будет изменен на аккаунт [@recovery](https://golos.today/@recovery) (для возможностей оперативного восстановления).

Для желающих выбрать иной `recovery_account`, подсказки были [описаны тут](https://golos.today/@lex/vosstanovlenie-dostupa-s-recovery-akkaunta-optimizaciya-delegatskikh-nod-pravki-registracii).

### Прочие правки

* Если на момент завершения недельного окна выплаты у аккаунта отрицательная репутация, выплата из общего пула за посты/комментарии не производится.
* Исправлено сжигание токенов на TIP-балансе спецаккаунта [@null](https://golos.today/@null).
* Доработаны и добавлены автотесты на нодах по подписи операций, цикле конвертации GBG, начисления процентов в сейфе, выплатах при отрицательной репутации и другие...

## Функционал личной блокировки

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

После ХФ **на уровне блокчейна** если `пользователь-1` добавил `пользователя-2` в свой черный список, от него не пройдут сообщения в мессенджере, трансферы, донаты (в заметках к которым [хейтеры](https://yandex.ru/search/?text=%D1%85%D0%B5%D0%B9%D1%82) нередко «достают» или отправляют по копейке), игнор упоминаний @ника, а комментарии к постам/ответам станут платными.

Тут и небольшой эксперимент «токенизации» (о чем отмечалось в [заявке](https://golos.today/@lex-escrow/zayavka-na-optimizaciyu-nod-dorabotku-delegirovaniya-vopros-claim-balansa-lichnyi-chs-v-blokcheine-i-prochee)), добавлен делегатский параметр `unwanted_operation_cost` (цена 1 «нежелательной» операции, по умолчанию `100 GOLOS`), токены поступают **на баланс получателя операции**, плата за внимание :-)

Для информации держателей АПИ-нод, добавлен новый плагин **account\_relations** (пригодится тем, кто использует блоги или форумы со своими нодами), в нём методы `list_account_relations` и `get_account_relations`.

Поступления на TIP-баланс (в случае комментариев при ЧС, а в перспективе и сообщений мессенджера) отображаются в кошельке, добавлена виртуальная операция:

```
"unwanted_cost",
{
    "blocker": "lex",
    "blocking": "abc",
    "amount": "100.000 GOLOS",
    "target": ""
}
```

Вместо `ignore` в операции `custom_json` (с которым порой были ошибки), для настроек личного ЧС в блокчейне добавлена операция:

```
"account_setup",
{
    "account": "lex",
    "settings": [
        [
            0,
            {
                "account": "abc",
                "block": true
            }
        ]
    ],
    "extensions": []
}
```

## Опция «не беспокоить» (на базе ЧС)

Реализована и опция для «особых интровертов», а скорее на случай «каруселей [хейта](https://yandex.ru/search/?text=%D1%85%D0%B5%D0%B9%D1%82)» (когда создают новые и новые аккаунты, а игра в персональную блокировку надоедает). Опция позволит временно включать блокировку **всех пользователей** с репутацией ниже 65.

В методе [get\_accounts](https://gapi.golos.today/api/database_api/get_accounts?ws=https%3A%2F%2Fapibeta.golos.today\&accountNames_0=abc) добавляется поле `"do_not_bother": true`, операция вкл-выкл опции выглядит так:

```
"account_setup",
{
    "account": "lex",
    "settings": [
        [
            1,
            {
                "do_not_bother": true
            }
        ]
    ],
    "extensions": []
}
```

## «Токенизация» при отрицательной репутации

В дополнение к правкам [об отмене выплат](https://golos.today/@lex/izmeneniya-27khf-gotovy-v-testovoi-seti-chast-1#prochie-pravki) с общего пула по постам/комментариям в случае отрицательной репутации, тяряет практический смысл ограничения на поток контента.&#x20;

Вспоминая о желании избавления от запретов и пути к токенизации, добавлен новый делегатский параметр `unlimit_operation_cost`, по умолчанию `10 GOLOS`. Цена 1 операции при отрицательной репутации (пост или комментарий или лайк/дизлайк).

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

Добавлена виртуальная операция `unlimit_cost` (для отображения в истории кошелька затрат на «анлимитные» операции).

```
"unlimit_cost",
    {
        "account": "xel",
        "amount": "10.000 GOLOS",
        "limit_type": "negrep",
        "target_type": "comment",
        "id1": "xel",
        "id2": "re-lex-donaty-v-messendzhere-rasshirenie-dlya-brauzera-golos-keychain-i-prochie-pravki-20220824t202918070z",
        "id3": "lex",
        "id4": "donaty-v-messendzhere-rasshirenie-dlya-brauzera-golos-keychain-i-prochie-pravki"
    }
```

## «Токенизация» при превышении лимитов

Не менее логичное изменение, и в вопросе общих лимитов, сейчас пользователи могут написать только 4 поста, 40 комментариев и 80 лайков/дизлайков в сутки, после чего при операции возникнет ошибка.

Параметр `unlimit_operation_cost` (описанный выше для действий при отрицрепе) распространяется и на эти операции сверх лимита.

В методе [get\_accounts](https://gapi.golos.today/api/database_api/get_accounts?ws=https%3A%2F%2Fapibeta.golos.today\&accountNames_0=abc) АПИ добавляются поля:

```
"services": {
  "post": "0.000 GOLOS",
  "comment": "0.000 GOLOS",
  "vote": "0.000 GOLOS"
}
```

В которых и обновляется «ценник» на операции при достижении лимитов, установленных имеющимися делегатскими параметрами.


# HF28: Новые возможности

## Изменение модели начислений за стейкинг

Делегаты смогут определять параметром `min_golos_power_to_emission` минимальную сумму в Силе Голоса, при которой токены поступают на TIP-баланс и доступны к использованию (донаты, повышение Силы Голоса и пр.).

Если баланс СГ (`vesting_shares`) аккаунта менее установленного медианой параметра, токены поступают на накопительный баланс (`accumulative_balance`), который отдельно отображается в кошельке:

Параметры `min_golos_power_to_emission`, а также `min_golos_power_to_curate`, задаются делегатами в токенах GBG, эквивалент которых рассчитывается в динамике котировок внутреннего курса GOLOS к GBG.

Тем самым при повышении курса токена GOLOS, требуется меньше токенов в Силе Голоса для автоматического получения начислений за стейкинг и кураторство, при cнижении курса - больше токенов или активности в поддержке курса путем выкупа участниками проекта.

## **Отключение поддержки майнеров**

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

Вместо 1 майнера в раунде подписи блоков станет +1 резервный делегат (ниже топ19), что добавит стимула оплаты подписи блогов резервным делегатам/их нодам.

В случае наличия параметров ноды (`miner, mining-threads, miner-account-creation-fee, miner-maximum-block-size, miner-sbd-interest-rate`) предусмотрено уведомление, операция `pow2` станет неактуальной.

## Доработка начислений за хранение GBG в сейфе

Так как на Голос существует стейблкоин привязанный к стоимости \~1 мг золота, и может быть полезен тем, кто хочет иногда обезопасить баланс от снижения курса на основной токен.

Доработки позволят ежемесячно и автоматически начислять проценты на хранимые пользователями GBG в сейфе (без прохождения квеста операций с сейфом), если:

* долг в блокчейне ниже 10%,
* медиана делегатского параметра не равна 0,
* стейкинг СГ больше параметра описанного выше.

#### Токенизация дизлайков из профиля

Изменения по платности дизлайков, которые пользователи ставят не за посты/комментарии, а репутацию в профиле аккаунта.

Как и на комментарии при блокировке пользователей, действует делегатский параметр `Unwanted Operation Cost`, с той разницей, что в данном случае комиссия сжигается.

#### **Ошибка при понижении Силы Голоса (лишняя неделя)**

Поскольку обсуждения выявили давние неудобства и непонимание пользователей с этим моментом, в 28 ХФ будет исправлен и он. Арифметические нюансы будут учтены при выводе Силы Голоса в последнюю (4-ю неделю).

#### **Ошибка при отмене делегирования (с небольшим балансом)**

Со сменой параметров делегатов, аккаунты с небольшими суммами делегирования требовали доделегирования перед отменой операции, этот момент также исправлен.


# Руководства (HowTo)

* [Примеры операций для торговли на GolosDEX ](/developers/howto/dex#sozdanie-ordera)
* [Скрипт регистрации аккаунтов](/developers/howto/registration-service) (автор [@vik](https://golos.id/@vik))
* [Создаем сайт на базе блокчейна](https://golos.id/ru--golos/@vik/sozdaem-sobstvennyi-sait-na-baze-blockchain-golosa-za-30-minut) (автор [@vik](https://golos.id/@vik))
* [Как использовать мультиподписи](/developers/howto/multisig) (автор [@vik](https://golos.id/@vik))
* [Как объединять операции в одну транзакцию](/developers/howto/ops-merging) (автор [@vik](https://golos.id/@vik))
* [Кэширование API](https://golos.id/ru--golos/@vik/zapusk-mnozhestva-mnogopotochnykh-zhivykh-skriptov-na-odnoi-node-reshenie-dlya-mashtabiruemosti-botov-golosa) (автор [@vik](https://golos.id/@vik))
* [Пример запуска тестнета](/developers/howto/testnet) (автор [@ropox](https://golos.id/@ropox))
* [Примеры команд к cli\_wallet](https://golos.id/ru--golos/@lindsay/dlya-delegatov-i-derzhatelei-nod-rabochie-komandy-i-metody-cliwallet) (автор [@lindsay](https://golos.id/@lindsay))


# Скрипт регистрации аккаунтов

Автор: [@vik](https://golos.id/@vik)

Этот простой скрипт поможет вам зарегистрировать любое количество новых аккаунтов на голосе.

**Браузерная версия** [golos.cf/reg/](https://golos.cf/reg/)

![](https://i.imgur.com/ZV6OXXu.jpg)

![](https://i.imgur.com/2lbzERi.png)

💡 Вы сможете создать новый аккаунт только при помощи своего существующего аккаунта

💡 Вам необходимо иметь на счету минимум **1 GOLOS**, эти голоса должны быть на счету, а не в СИЛЕ ГОЛОСА регистратора! При создании аккаунта они будут переведены в силу голоса нового аккаунта.

💡 Если у вас есть только GBG - вы можете обменять их на GOLOS используя внутреннюю биржу голоса.

💡 Операция создания аккаунта будет видна в блокчейн, таким образом вы не сможете создать анонимный аккаунт для спама.

💡 Аккаунт регистратора будет так же установлен в качестве RECOVERY. В случае если вы потеряете доступ к новому аккаунту - вы сможете восстановить его только при помощи своего аккаунта регистратора.

**📢 Рекомендуется скопировать исходный код страницы и использовать ее локально! Не вводите активный ключ на непроверенных сайтах - у вас могут украсть ваши GOLOS/GBG. Если вы нашли эту или похожую форму на другом сайте - обратитесь в чат** [**@chain\_cf**](https://t.me/chain_cf) **и спросите совета у более опытных пользователей!**

**Node JS**

* Поставьте nodeJS
* Установите библиотеку golos-lib-js `npm install golos-lib-js`
* Скачайте файл accountregistartor.js

<https://github.com/vikxx/robot/blob/master/accountregistartor.js>

* Заполните необходимые поля и запустите `node accountregistartor.js`

```javascript
// Придумайте логин и пароль для нового аккаунта
const NAME = "nickname123"
const PASS = "MyStrongPass1234567890"


const golos = require('golos-lib-js')
golos.config.set('websocket', "wss://api.golos.blckchnd.com/ws")

// Данные создателя аккаунта
// Активный ключ создателя (вашего существующего аккаунта)
const wif= "5ouriuruemACTIVEKEYkjnfjnvnjfnvjnfjnvfjnvnjdu"

// Стоимость создания аккаунта.
// Эти средства пойдут в силу голоса созданному пользователю.
//Вы можете их увеличить при желании.
const fee= "3.000 GOLOS"

// Логин создателя (вашего существующего аккаунта)
const creator= "robot"


// Профиль пользователя. О себе, аватар, и т.д. , можно оставить пустым и заполнить позднее
const jsonMetadata= {}


let x = golos.auth.generateKeys(NAME, PASS, ['owner','active','posting','memo'])
const ownerAuth = {
    weight_threshold: 1,
    account_auths: [],
    key_auths: [[x.owner, 1]]
}
const activeAuth = {
    weight_threshold: 1,
    account_auths: [],
    key_auths: [[x.active, 1]]
}
const postingAuth = {
    weight_threshold: 1,
    account_auths: [],
    key_auths: [[x.posting, 1]]
}
const memoKey= x.memo

golos.broadcast.accountCreate(wif, fee, creator, NAME, 
ownerAuth, 
activeAuth, 
postingAuth, 
memoKey, 
jsonMetadata, 
(err, result) =>
 {
  if(err) return console.log(err);
    console.log(result)
});
```

По материалам[ статьи](https://golos.id/ru--golos/@vik/mgnovennaya-registraciya-akkauntov-na-golos-i-steem-bez-verifikacii-i-ogranichenii)


# Операции на бирже

## Создание ордера

На внутренней бирже GolosDEX можно покупать и продавать средства в GOLOS, GBG и токенах UIA. Чтобы продать или купить средства, нужно создать ордер.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
golos.config.set('websocket', 'wss://api.golos.today/ws')

const acc = 'snake' // имя аккаунта, который будет создавать ордер
const wif = '5JFZC7AtEe1wF2ce6vPAUxDeevzYkPgmtR14z9ZVgvCCtrFAaLw' // приватный active-ключ

const orderid = Math.floor(Date.now() / 1000) // у каждого ордера должен быть уникальный id, который необходимо сгенерировать. Здесь применяется один из способов

let expiration = new Date()
expiration.setHours(expiration.getHours() + 1)
expiration = expiration.toISOString().substr(0, 19) // получается формат вида 2022-01-18T11:33:00

try {
    const res = await golos.broadcast.limitOrderCreateAsync(wif, acc, orderid, '1.000 GOLOS', '0.010 GBG', false, expiration)
    console.log('order created')
} catch (err) {
    console.error('cannot create order', err)
}
```

{% endtab %}

{% tab title="Python" %}

```python
#!/usr/bin/env python3
from datetime import datetime, timedelta
import logging
from golos.steem import Steem
from golos.transactionbuilder import TransactionBuilder
from golosbase import operations

acc = 'snake'
wif = '5JFZC7AtEe1wF2ce6vPAUxDeevzYkPgmtR14z9ZVgvCCtrFAaLw'

steem = Steem('wss://api.golos.today/ws')
print('Connected to GOLOS successfully!')

steem.commit.wallet.setKeys(wif)

orderid = int(datetime.now().timestamp())

expiration = datetime.utcnow() + timedelta(hours=1)
expiration = expiration.replace(microsecond=0).isoformat()

op = operations.LimitOrderCreate(
    owner=acc,
    orderid=orderid,
    amount_to_sell='1.000 GOLOS',
    min_to_receive='0.010 GBG',
    fill_or_kill=False,
    expiration=expiration
    )

try:
    steem.commit.finalizeOp([op], acc, 'active')
    print('order created')
except Exception as err:
    print('order not created')
    logging.error(err, exc_info=True)
```

{% endtab %}
{% endtabs %}

**В этом примере:**

* 1.000 GOLOS продаем. Они спишутся с баланса в момент создания ордера
* 0.010 GBG покупаем за 1.000 GOLOS
* false означает, что не следует использовать Immediate-Or-Cancel, то есть если нет подходящего ордера для сделки, то ордер будет висеть до момента expiration. Если заменить false на true, то при создании ордера сработает IOC и если нет подходящего ордера, то созданный ордер сразу самоуничтожится.
* expiration - сколько времени висеть ордеру (в данном случае 1 час)

## Отмена ордера

Аккаунт может отменить созданный им ордер, если по нему еще не прошли сделки.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const orderid = 13548 // а так неправильно: orderid = '13548'

try {
    const res = await golos.broadcast.limitOrderCancelAsync(wif, acc, orderid)
    console.log('order canceled')
} catch (err) {
    console.error('cannot cancel order', err)
}jaja
```

{% endtab %}

{% tab title="Python" %}

```python
orderid = 13548 # а так неправильно: orderid = '13548'

op = operations.LimitOrderCancel(
    owner=acc,
    orderid=orderid
)

try:
    steem.commit.finalizeOp([op], acc, 'active')
    print('order canceled')
except Exception as err:
    print('order not canceled')
    logging.error(err, exc_info=True)
```

{% endtab %}
{% endtabs %}

## Балансы пользователя

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const res = await golos.api.getAccounts(['snake'])
if (!data[0]) {
    console.log('no such account')
} else {
    console.log(data[0].balance) // GOLOS
    console.log(data[0].sbd_balance) // GBG
}

// для UIA следует использовать get_accounts_balances

const balances = await golos.api.getAccountsBalances(['lex'])
const dogecoin = balances[0]['DOGECOIN']
if (dogecoin) {
    console.log(dogecoin.balance)
    console.log(dogecoin.tip_balance)
    console.log(dogecoin.market_balance)
} else {
    console.log('no DOGECOIN balance')
}
```

{% endtab %}

{% tab title="Python" %}

```python
data = steem.get_accounts(['snake'])
if not len(data):
    print('no such account')
else:
    print(data[0]['balance']) # GOLOS
    print(data[0]['sbd_balance']) # GBG

# для UIA следует использовать get_accounts_balances

balances = steem.get_accounts_balances(['lex'])
data = None
try:
    data = balances[0'DOGECOIN']
except KeyError as err:
    print('no DOGECOIN balance')
if not data == None:
    print(data['balance'])
    print(data['tip_balance'])
    print(data['market_balance'])
```

{% endtab %}
{% endtabs %}

## Разработка на JavaScript

В этом случае требуется Node.js, и его версия должна быть не ниже **11**, а рекомендуется - **16**.

#### Установка Node.js

В случае с Ubuntu выполните в приложении Терминал следующие команды, чтобы удалить существующий Node.js (если он имеется) и установить 16:

```
sudo apt-get remove nodejs
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
```

* Для других Linux см. [здесь](https://github.com/nodesource/distributions#table-of-contents)
* Для Windows - [здесь](https://nodejs.org/dist/v16.13.2/node-v16.13.2-x64.msi)
* Для 32-битных Windows - [здесь](https://nodejs.org/dist/v16.13.2/node-v16.13.2-x86.msi) (использовать только на компьютерах, где обычный вариант не работает)
* Для macOS - [здесь](https://nodejs.org/dist/v16.13.2/node-v16.13.2.pkg)

После того, как Node.js установлен, проверьте, что он доступен из Терминала.

1. Проверьте работу npm:

```
npm --version
```

Она должна выдать ответ наподобие "8.1.2", а не ошибку.

1. Проверьте работу самого Nodejs:

```
nodejs --version
```

А если эта команда выдает ошибку, то должна работать эта:

```
node --version
```

Если все команды выдают ошибку, то в случае Windows необходимо сделать следующее:

1. Найдите, по какому пути установлен nodejs. Обычно это `C:\Program Files\nodejs`, но возможно также `C:\Program Files (x86)\nodejs`
2. Открыть "Панель управления", выбрать "Система", нажать синюю надпись "Дополнительные параметры системы", нажать кнопку "Переменные среды", в списке "Переменные среды пользователя" выбрать переменную Path или PATH, нажать кнопку "Изменить", затем "Создать" и вставить туда путь из пункта 1. Затем нажмите "OK", снова "ОК", затем "Применить", и закройте панель управления.
3. Откройте новый PowerShell и снова проверьте команды.

#### Создание скрипта

После того, как Node.js будет корректно установлен, можно создать свой первый скрипт, который будет работать на вашем ПК и взаимодействовать с Golos.

1. Создайте папку hellogolos
2. Откройте эту папку в терминале. В случае с Windows, сначала просто откройте папку, затем, щелкните "Файл", и затем "Запустить PowerShell".
3. Выполните команду

```
npm install golos-lib-js
```

1. Создайте в папке скрипт index\*\*.mjs\*\* со следующим кодом:

```js
import golos from 'golos-lib-js'

async function main() {
    const dgp = await golos.api.getDynamicGlobalProperties()
    console.log(dgp.head_block_number)

    process.exit(0)
}

main()
```

А если используете Node.js старше 14, то переименуйте файл в index\*\*.js\*\* и вместо import используйте

```js
const golos = require('golos-lib-js')
```

1. Запустите с помощью:

```
node index.mjs
```

## Разработка на Python

Необходим Python версии не ниже 3.6.1, но не 4.0.0 и выше.

#### Установка Python и инструментов для сборки

Чтобы установить Python на **Linux** и не приходилось собирать его из исходного кода, добавьте этот репозиторий:

```
sudo add-apt-repository ppa:deadsnakes/ppa
```

Затем используйте эти команды:

```
sudo apt-get update
sudo apt-get install python3.7 python3.7-dev python3.7-venv
```

(Пакет **-dev** нужен для сборки golos-lib-python. А пакет **-venv** для установки pip.)\
Установите pip:

```
python3.7 -m ensurepip
```

Готово.

**Windows**

Если у вас Windows, используйте [эту](https://www.python.org/downloads/windows/) страницу. Найдите там самую новую версию, которая имеет ссылку типа "Download Windows installer (64-bit)". В случае, если Windows 32-битный и этот установщик не работает, используйте "Download Windows installer (32-bit)".\
**Важно:** при установке обязательно отметьте флажок "Add Python to PATH", чтобы Python был доступен из PowerShell (терминала). Если вы установили Python без этого флажка, переустановите Python.

Затем необходимо установить Microsoft Visual Studio не ниже 2015, а рекомендуется 2019 (<https://visualstudio.microsoft.com/visual-cpp-build-tools/> и выбрать пункт "Классические приложения C++", остальное по умолчанию). Это необходимо для работы библиотеки python-golos.

Кроме того, необходимо установить OpenSSL.

**macOS**

Используйте [эту](https://www.python.org/downloads/macos/) страницу, а затем выполните [эти](https://github.com/golos-blockchain/lib-python#homebrew-build-prereqs) инструкции.

#### Создание скрипта

1. Создайте папку hellogolospy
2. Установите библиотеку golos-lib-python:

```
python3.7 -m pip install golos-lib-python
```

или (Windows)

```
python -m pip install golos-lib-python
```

Библиотеки устанавливаются для всей системы (в site-packages), а не в конкретную папку.\
3\. Создайте скрипт:

```python
#!/usr/bin/env python3
from golos.steem import Steem

steem = Steem('wss://api.golos.today/ws')
print('Connected to GOLOS successfully!')

dgp = steem.get_dynamic_global_properties()
print(dgp['head_block_number'])
```


# Как использовать мультиподписи

Автор [@vik](https://golos.id/@vik)

Ранее я уже добавлял примитивную форму для создания мультипостинг-аккаунта с равным весом, оказалось ее активно используют инициаторы различных программ совместного курирования. Считаю необходимым провести ликбез и показать как можно использовать кошельки с мультиподписью и распределением веса.

Для удобства я создал отдельный сервис [GOLOS.CF/MULTISIG](https://golos.cf/multisig)

**Опытные пользователи могут использовать сразу, все остальным рекомендую внимательно читать пост :)**

С его помощью можно создать мультисиг кошелек или мультисиг аккаунт куратора (кита с большой СГ) и многое другое

![](http://telegra.ph//file/1bc2b36e24b79b4306e2a.png)

**Примечательно, что этот функционал есть в блокчейне голоса (steemit) "по умолчанию" и его можно было использовать всегда.**

Мультиподпись на голосе работает очень удобным и гибким образом, как известно у каждого пользователя есть свой минимальный набор ключей, я буду использовать два основных ключа - активный и постинг.

Постинг ключ - Безопасно. Используйте приватный **постинг** ключ для операций связанных с голосованием, размещением постов, фолловингом и реблогами.

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

Реализация мультисига осуществляется с помощью добавления в существующий аккаунт мультиавторизации по ключу, например я могу добавить к своему постинг ключу логин другого пользователя и он сможет используя мой логин и его собственный ключ управлять моим аккаунтом на уровне постинга. Интересно, но не совсем то, что нужно, ведь у него появляются те же права постинга, что и у меня и это сложно назвать мультисигом в полной мере. Это решается так называемым весом для каждого логина и установкой минимального веса для принятия транзакции блокчейном.

Перейдем к практике!

## 🔑 Создание мультисиг-аккаунта для своего DAO

> DAO - децентрализованная автономная организация

Придумаем собственное DAO и некое подобие смартконтракта, пусть это будет аккаунт-кошелек @cryptobank

Аккаунт с наибольшим, но не решающим влиянием:

@vik (вес 5)

Аккаунты представители со средним влиянием:

@vox @robot @dpos @ceo - вес у каждого 2

Также мы установим минимально-необходимый вес для принятия блокчейном транзакции - 10

Эти условия означают, что для того, чтобы отправить средства с аккаунта @cryptobank, нужно чтобы транзакцию подписали несколько участников, их суммарный вес должен достигать 10.

@vox @robot @dpos @ceo - суммарный вес 8

Они не смогут потратить средства @cryptobank пока транзакцию не подпишет @vik и не сделает сумму веса не менее 10.

В то же время если @vik и @robot захотят потратить средства @cryptobank - они не смогут это сделать, так как их вес будет 7. Но если присоединятся @dpos и @vox - транзакция будет осуществлена (вес 5+2+2+2 = 11) и подпись @ceo не понадобилась, хватило веса и без него.

Говоря о смартконтракте, я подразумевал использование суперкитов голоса в качестве постинг мультисига с большим количеством участников. Например вес каждого участника 1. Всего участников 20. Минимальный вес для подписи операции с простановкой 100% апвота - 15. Таким образом если 15 человек из 20 согласны - суперкит голосует за некий пост. И это абсолютно безопасно - ключи остаются при ките.

## Создание мультисига [golos.cf/multisig/#step4](https://golos.cf/multisig/#step4)

![](http://telegra.ph//file/a2fb302ce6b9022e3d669.png)

В поле минимальный вес следует вводить целое число 1, 2, 3 ... 10 и т.п. это число будет минимальным суммарным весом для подписей начиная с которого транзакция сможет быть принята в блокчейн. Руководствуйтесь принципами весов для создания собственных комбинаций прав доступа.

В поле списка аккаунтов можно ввести логины и раздать им вес.

Опция уровня доступа позволяет выбирать между постинг/активной авторизацией.

На скриншоте я добавил аккаунту @cryptobank минимальный вес 10 и добавил в мультисиг логины с весом соблюдая синтаксис для моей формы:

`vik=5/robot=2/dpos=2/vox=2`

Уровень доступа я выбрал - активный, поскольку это интереснее и в случае ошибок "накажет рублем" :)

## 📓 Создание мультиподписной транзакции

Аккаунт мультисиг уже есть - @cryptobank

Теперь смоделируем ситуацию. Например @vik как участник мультисига и президент карманного DAO хочет распределить бюджет и перевести с бомжебанка монеты аккаунтам @registrator и @upvoter

Для этого @vik создает транзакцию, подписывает ее сам и передает на подпись другим.

![](http://telegra.ph//file/ffbbcd4b4021f0a4f2236.png)

На скрине в поле ввода операций можно ввести несколько операций и упаковать их в одну транзакцию. Это крайне удобно для отчетности.

Формат ввода операций был такой:

```
["transfer",{"from":"cryptobank","to":"registrator","amount":"0.002 GBG","memo":"Тест мультисига https://golos.cf/multisig/#step1"}],  
["transfer",{"from":"cryptobank","to":"upvoter","amount":"0.005 GBG","memo":"Тест мультисига https://golos.cf/multisig/#step1"}]
```

Обратите внимание, что в поле логина я вожу логин не @vik, а @cryptobank\
И саму транзакцию формирую так, будто ее отправляет криптобанк, а не я. Из своего я использую только ключ, он формирует подпись, которая будет добавлена в транзакцию.

В правой колонке у нас появилась транзакция с операциями и с важным атрибутом signatures (подписи)

![](http://telegra.ph//file/2c32e01307587c87998b3.gif)

Пока что там только одна подпись от аккаунта @vik

Обратите также внимание на срок действия транзакции - участники должны успеть подписать ее за час! (можно настроить иное значение, меньшее)

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

Копируем транзакцию и отправляем ее на подпись другому пользователю

*(это абсолютно безопасно - данные в сырой транзакции не являются приватными, без участников мультисига с полным весом ее нельзя отправить, а уж тем более изменить адресатов, суммы и т.д.)*

## 📓 Подпись ранее созданной транзакции участниками мультисига

@vik передает транзакцию @vox\
Тот (как и остальные кроме автора транзакции) использует уже другую форму

[golos.cf/multisig/#step2](https://golos.cf/multisig/#step2)

**🖋 Подписать транзакцию как участник мультисига**

В эту форму нужно ввести ключ @vox, логин @cryptobank\
и полученную от @vik транзакцию.\
На кнопку подписать для удобства повешена сразу и функция отправки в блокчейн.\
Однако если веса не хватает, вы получите вот такую ошибку об авторити связанную с отправкой транзакции, с тем, что не хватает веса подписей.

![](http://telegra.ph//file/201d3ce0694425cf7686e.png)

А справа появится эта же транзакция, но с дополнительной подписью в атрибуте signatures , подписью от @vox в нашем случае.

@vox копирует дополненую транзакцию и отправляет ее полный текст следующему в списке, @robot или @dpos.\
Те в свою очередь проделывают тоже самое, подписывают и передают дальше транзакцию со своими подписями.

![](http://telegra.ph//file/8ebcfecdec650222854fb.png)

*(Следует понимать, что эти подписи динамические и завязаны на каждом байте транзакции, эта подпись подойдет только для этой транзакции, если кто-то попробует подписать вашей одноразовой подписью другую транзакцию - ничего не выйдет.)*

Когда сумма всех подписей достигла минимального порога в мультисиге - транзакция отправляется.

![](http://telegra.ph//file/b1b517f53941bf26a07b2.png)

**Важно замечание**

В примере выше у @cryptobank есть возможность самому потратить средства без оглядки на участников мультисига. Чтобы исключить такую возможность, для мультисига нужно создавать отдельный аккаунт и уже на этапе создания назначать ему минимальный вес больший его собственного веса, тогда он не сможет самостоятельно использовать свой активный ключ!

**Можно также добавить в существующий аккаунт мульти авторизацию для owner ключа, поскольку в неумелых руках это может "убить" аккаунт, такую форму я не публикую.**

📢**Фидбек**

Если у вас есть пожелания по странице [golos.cf/multisig](https://golos.cf/multisig) можете оставлять комментарии или писать в чат [t.me/chain\_cf](https://t.me/chain_cf)

⚗️**Исходный код и безопасность**

Код не минифицирован, полностью открытый client-side, это значит, что вы можете нажать CTRL+U скопировать исходный код в файл имя.html и использовать локально из папки на компьютере. Ваши приватные ключи никуда не передаются, они используются только для локальной подписи операций, передаются в блокчейн уже подписанные операции. Однако злоумышленники могут сделать копию формы и поменять в коде функции так, что ваши ключи будут отправлены им, поэтому всегда проверяйте адрес страницы. Или используйте локальную версию.

Простые примеры использования мультисига:

* Для голосования, определения консенсуса. Например, как сервис для делегатов, голосующих за/против ХФ или другие нововведения.
* Конкурс с призом. Пусть будет конкурс красоты с выбором самой красивой свинки пепы :) 10 конкурсанток, формируется для каждой транзакция на перевод призового фонда. Мультисигу переводится призовой фонд (на балансе должен быть только он и переводиться полностью). Добавляется 100 членов жюри в мультисиг с весом 1 (минимальный вес принятия 51) Членам жюри доставляют на подпись 10 транзакций, можно оформить в GUI в виде 10 карточек с фото куртизанок. Чью карточку-транзакцию в течении часа первой подпишут 51 член жюри - та конкурсантка и получит призовой фонд.
* Или так, публикация клятвы, что если 75 пользователей подпишуться под транзакцией, автор разместит клятву, что съест свое лицо. Выставлен минимальный вес для постинга 75 И 100 пользователей наделены весом 1 (или другим, пропорционально стеку, репутации и т.д.) Если минимум 75 пользователь подписал транзакцию - отправляется пост или custom\_json с какой-то клятвой манифестом :)
* Или пример сложнее, с параметризацией. Формируется транзакция в которую пакуется update witness для каждого делегата с параметром: плата за создание аккаунта, 1 GOLOS Дополнительно формируются еще несколько с платой 2, 3 и т.д. Какой вариант соберет больше всего подписей - столько массово, одномоментно и объявят делегаты.

По материалам [статьи](https://golos.id/@vik/multisigi-na-golose-12-09)


# Как объединять операции в одну транзакцию

Автор: [@vik](https://golos.id/@vik)

Операции голосования своими 100+ аккаунтами, упакованные в ОДНУ транзакцию:

* **Экономит время (100+ операций одновременно)**
* **Экономит bandwidth (новореги смогут совершать в**`X`**раз больше транзакций)**
* **Экономит ресурсы среды скрипта (браузер, сервер, приложение)**

Для начала выбираем 1 свой основной аккаунт-ботовод и прописываем его логин своим ботам в постинг-авторити. Это можно сделать массово с помощью скрипта:\
<https://github.com/vikxx/bots/blob/master/sample/setBotMaster.js>

Нужно заполнить массив

```
const GolosBots = [
["логин бота1",["posting","5**************ACTIVE WIF****"]],
["логин бота 3",["posting","5*****************"]],

// бесконечный список аккаунтов...

["логин последнего бота",["posting","5******************"]]

]
```

В переменной прописываем аккаунты и ключи. Заполнять posting не обязательно, требуется только активный ключ.*(Я храню оба ключа для удобства, так как разные скрипты используя массовые действия смотрят список аккаунтов и обращаются к тому или иному ключу)*

В переменную`const BOTMASTER = "логин ботовода"`записываем логин аккаунта, который будет иметь права на постинг.

![](https://images.golos.io/DQmTJgMMvw4nkmxtVrFdrxdZXKUNbGQYUdckWUh6gshCCMA/image.png)

После выполнения скрипта он запишется в постинг авторизацию

![](https://images.golos.io/DQmXx3zZjuKyG1sWTsciMG1GJyQkhTLMJPjV3UJwFXtFtYr/image.png)

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

Пример на JS:\
<https://github.com/vikxx/bots/blob/master/sample/botVotes.js>

Прописывать ключи всем аккаунтам не нужно, достаточно перечислить логины:

```
const GolosBots = [
"vikx",
"vikxx",
// Endless list...
"vikxxx"
]
```

И для каждого логина сделаем свою операцию, записав их все в одну переменную **votes**

```
for(let botname of GolosBots){

votes.push(["vote",
{
"voter":botname,
"author":author,
"weight":10000,
"permlink":permlink
}])

}
```

Затем сформируем одну транзакцию, добавим в нее все операции votes и подпишем все операции постинг ключем аккаунта-ботовода

```
const unsignedTX = {
    'expiration': expire,    
    'extensions': [],
    'operations': votes,
    'ref_block_num': 60419,
    'ref_block_prefix': 2937707173               
   }

let signedTX = null

try {
    signedTX = golos.auth.signTransaction(unsignedTX,{"posting":wif})
}
catch (error) 
golos.api.broadcastTransactionSynchronous(signedTX)
```

Скрипт полностью здесь:\
<https://github.com/vikxx/bots/blob/master/sample/botVotes.js>

По материалам [статьи](https://golos.id/ru--golos/@vik/ekonomim-resurs-akkaunta-i-servera-sovmeshaya-100-operacii-v-odnoi-tranzakcii)


# Пример запуска тестнета

Автор: [@ropox](https://golos.id/@ropox)

Порой для писателей скриптов, ботов для голоса требуется отладить работу программ в тишине и спокойствии и в контролируемой среде. Не хочется, что бы бот к примеру перевел внезапно 10000 голосов неизвестно кому из-за глупой ошибки. Как это случилось однажды с доброботом. Опять же для регрессионных тестов, нужна возможность повторения сценариев с одинаковыми исходными данными, чтобы получить повторяемые, ожидаемые результаты. Ну и конечно тестирование ХФ, новой версии сети голоса. У нас сейчас актуальная версия сети 0.16.4, а новая версия будет 0.17.0. Если кто-то захочет протестировать новую версию, подключившись к реальной сети, то возможно нода с “неправильной” версией будет “саботировать” сеть.

Вот для этого и запускается testnet. С тестовыми пользователями уже имеющими на балансе средства, с измененными настройками, позволяющими ускорить тестирование.

К примеру можно установить уменьшение силы голоса не раз в неделю как в настоящей сети, а раз в 15 минут. Иначе бы пришлось ждать результатов теста неделями, а в тестнете всего 15 минут. Окно авторских вознаграждений можно сократить с недели, до получаса. Выгоды очевидны.

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

## Сборка образ докера

В официальном репозитории golos уже есть готовые файлы для docker, и предпочтительно использовать их, чтобы не городить свои скрипты для компиляции, бороться с зависимостями. Все для вас сделает docker. Как работать с докером я расписывать сильно не буду. Инструкций полно в интернете.

### Подготовка исходников

Для начала скачаем исходники golos. Для этого воспользуемся git-ом.

```
$ git clone https://github.com/GolosChain/golos.git

Клонирование в «golos»…
remote: Counting objects: 22425, done.
remote: Compressing objects: 100% (150/150), done.
remote: Total 22425 (delta 132), reused 177 (delta 76), pack-reused 22152
Получение объектов: 100% (22425/22425), 13.47 MiB | 4.58 MiB/s, готово.
Определение изменений: 100% (15314/15314), готово.
```

У нас создастся папка golos с исходниками. Перейдем в нее и последующие комманды будет запускать в ней.

Нам нужно будет переключить на нужную нам ветку. В настоящий момент меня интересует версия 0.17.0.

![](https://s3.postimg.cc/83dc9q33n/047.png)

Как видно на скриншоте, есть branch под названием **golos-v0.17.0**. Вот на нее нам и надо переключиться. Для этого в корне папки с исходниками выполним следующую команду

```
$ git checkout golos-v0.17.0
Ветка golos-v0.17.0 отслеживает внешнюю ветку golos-v0.17.0 из origin.
Переключено на новую ветку «golos-v0.17.0»
```

И теперь нам надо обновить локальные файлы до версий в репозитории на гитхабе

```
$ git submodule update --init --recursive
Подмодуль «libraries/chainbase» (https://github.com/GolosChain/chainbase.git) зарегистрирован по пути «libraries/chainbase»
Подмодуль «libraries/fc» (https://github.com/GolosChain/fc.git) зарегистрирован по пути «libraries/fc»
Подмодуль «libraries/libcds» (https://github.com/khizmax/libcds.git) зарегистрирован по пути «libraries/libcds»
Клонирование в «/hom...
```

Теперь можно поменять нужные нам для теста параметры. К примеру я хочу тестировать скрипт, который должен запускаться после понижения силы голоса. Чтобы не ждать неделями, я сокращу интервал вывода СГ до 10 минут. Для этого открываю файл с настройками сети в редакторе.

```
$ nano libraries/protocol/include/steemit/protocol/config.hpp
```

И ищу переменные со словам withdraw и почти сразу нахожу нужные мне.\
![](https://s1.postimg.cc/4vryqapwv/048.png)

Меня интересует конкретно вот эта строка

```
#define STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS (60*60*24*7) // 1 week per interval
```

Я исправляю, чтобы интервал был 10 минут и сохраняю файл

```
#define STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS (60*10) // 1 week per interval
```

### Сборка образа

В папке docker лежит файл для докера с инструкциями по сборке образа.

```
$ ls docker/*
docker/Dockerfile-testnet
```

Все, что нам требуется, это запустить сборку

```
$ docker build . -f docker/Dockerfile-testnet -t testnet-17
```

Спустя какое то время мы имеем готовый образ докера

![](https://s4.postimg.cc/7rt17rs0t/049.png)

## Запуск

Для начального запуска воспользуемся командой run докера

```
$ docker run -it -p 127.0.0.1:9090:8090 -d --name testnet -t testnet-17
```

Собственно все понятно. -it включает интерактивность. “-p 127.0.0.1:9090:8090” включает переадресацию порта 8090 изнутри контейнера наружу, на порт 9090. Это дает возможность подключаться скриптами к тестнету используя URL вида ws\://localhost:9090. Опция -d запускает контейнер отключенным от консоли в фоне. --name testnet задет простое имя контейнеру. -t testnet-17 задает имя образа, который будет использоваться для создания контейнера.

Если все нормально, после запуска контейнера докер распечатает ID контейнера и вернет управление в консоль.

Как я писал выше, в тестнете уже созданы пара тестовых пользователей. Самый важный cyberfounder. Естественно, чтобы можно было этим аккаунтом пользоваться, нужны ключи. Приватный и публичный. При запуске, golos распечатывает пару ключей в самом начале. Посмотреть их можно распечатав лог голоса.

```
$ docker logs testnet
```

![](https://s18.postimg.cc/uo28fw5bd/050.png)

```
initminer public key: GLS58g5rWYS3XFTuGDSxLVwiBiPLoAyCZgn6aB9Ueh8Hj5qwQA3r6
initminer private key: 5JVFFWRLwz6JoP9kguuRFfytToGU6cLgBVTL9t6NB3D3BQLbUBS
chain id: 5876894a41e6361bde2e73278f07340f2eb8b41c2facd29099de9deef6cdb679
blockchain version: 0.17.0
```

## Конфигурационный файл

Чтобы сеть заработала, нужен хотя бы один делегат, подписывающий блоки. Этим и будет заниматься аккаунт cyberfounder. Чтобы это заработало, нужно отредактировать конфигурационный файл.

Сначала зайдем в образ

```
$ docker exec -it testnet bash
```

Конфигурационный файл config.ini лежит в папке /etc/golosd.

```
vi /etc/golosd/config.ini
```

Изменим следующие параметры

```
witness = "cyberfounder"
private-key = 5JVFFWRLwz6JoP9kguuRFfytToGU6cLgBVTL9t6NB3D3BQLbUBS
enable-stale-production = true
required-participation = 0
```

После чего перезапускаем контейнер

```
$ docker stop testnet
$ docker start testnet
```

И видим, что сеть заработала и cyberfounder начал генерировать блоки

```
$ docker logs testnet
```

![](https://s3.postimg.cc/kirac52ub/051.png)

Дождемся 17-го хардфорка, после чего можно пользоваться тестнетом

```
1551001ms th_a       database.cpp:4890             apply_hardfork       ] HARDFORK 17 at block 36
1551002ms th_a       witness.cpp:205               block_production_loo ] Generated block #36 with timestamp 2017-07-29T15:25:51 at time 2017-07-29T15:25:51 by cyberfounder
```

Запускаем cli\_wallet, задаем пароль, и импортируем приватный ключ cyberfounder аккаунта

```
$ docker exec -it testnet cli_wallet

Please use the set_password method to initialize a new wallet before continuing
new >>> set_password 123
set_password 123
null
locked >>> unlock 123
unlock 123
null
unlocked >>> import_key 5JVFFWRLwz6JoP9kguuRFfytToGU6cLgBVTL9t6NB3D3BQLbUBS
import_key 5JVFFWRLwz6JoP9kguuRFfytToGU6cLgBVTL9t6NB3D3BQLbUBS
2152613ms th_a       wallet.cpp:534                save_wallet_file     ] saving wallet to file wallet.json
true
unlocked >>>
```

На аккаунте cyberfounder есть уже некая сумма голосов

```
unlocked >>> list_account_balances cyberfounder

[
  "43306208.000 GOLOS"
]
```

Можно создать нового пользователя и перевести ему GOLOS

```
unlocked >>> create_account cyberfounder ropox "{}" true
unlocked >>> transfer cyberfounder ropox "200000.000 GOLOS" "для тестов" true
{
  "ref_block_num": 338,
  "ref_block_prefix": 853465515,
  "expiration": "2017-07-29T15:41:27",
  "operations": [[
      "transfer",{
        "from": "cyberfounder",
        "to": "ropox",
        "amount": "200000.000 GOLOS",
        "memo": "для тестов"
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "20491f45c3f3f8d67f3a5c62f934c7c22312ddf392edde2f78a9962634a0ed7b4e4d2f6428282e0d0837893013c04e9e5e0057974c43a490b4abb4416091d5a18b"
  ],
  "transaction_id": "7d155661801e3b5a450d5c1f97378ee5a94a54b6",
  "block_num": 339,
  "transaction_num": 0
}
```

Ну и вишенка на торт, создаем свой, персональный токен

```
unlocked >>> create_asset cyberfounder ROPOX 3 {"description": "Золото царя Гороха", "core_exchange_rate":{"base":"1.000 ROPOX","quote":"1.000 GOLOS"}} null true
```

```
{
  "ref_block_num": 380,
  "ref_block_prefix": 3346277100,
  "expiration": "2017-07-29T15:43:33",
  "operations": [[
      "asset_create",{
        "issuer": "cyberfounder",
        "asset_name": "ROPOX",
        "precision": 3,
        "common_options": {
          "max_supply": "1000000000000000",
          "market_fee_percent": 0,
          "max_market_fee": "1000000000000000",
          "issuer_permissions": 79,
          "flags": 0,
          "core_exchange_rate": {
            "base": "1.000 ROPOX",
            "quote": "1.000 GOLOS"
          },
          "whitelist_authorities": [],
          "blacklist_authorities": [],
          "whitelist_markets": [],
          "blacklist_markets": [],
          "description": "Золото царя Гороха",
          "extensions": []
        },
        "is_prediction_market": false,
        "extensions": []
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "20225a9ce260f8434f3e83cf8e48c4e16557f38e5540fa9a9a53126c685b70f16b3619a95b50c7f7a611e9c26261fd669c4ad8496cdc45d95ea9d3ef12c5cc5e33"
  ]
}
```

Инстанциируем немного монет и переводим их тестовому пользователю

```
unlocked >>> issue_asset cyberfounder "1000.000 ROPOX" "Акции" true
unlocked >>> transfer cyberfounder ropox "20.000 ROPOX" "Подарок" true
unlocked >>> list_account_balances ropox
[
  "0.000 GBG",
  "200000.000 GOLOS",
  "20.000 ROPOX"
]
```

Удачных вам экспериментов!

По материалам [статьи](https://golos.id/ru--golos/@ropox/zapusk-testnet-golos)


# Делегатство и роли нод

Термин делегат (который применяется в Голосе) отражает суть данной роли, сообщество делегирует некоторым его членам определенные права.

В основе алгоритма DPOS (делегированное доказательство доли) лежит голосование, наделяющее пользователей имеющих определенный уровень репутации в сообществе и получивших определенное количество (вес) голосов, некоторыми правами (хотя скорее обязанностями). Делегаты используя своё (или арендованное) оборудование обеспечивают функционирование узлов (нод) сети, создают и подписывают новые блоки, обеспечивая децентрализацию и безопасность сети.

За раунд подписи создается 21 блок, с интервалом в 3 секунды. **Топ 19** делегатов (набравшие в сумме наибольший вес голосов за свои кандидатуры) производят блок в каждом раунде, еще один блок производит делегат, не попавший в топ 19, причем вероятность того, что он произведет блок пропорциональна весу голосов отданных за него, в сравнении с другими делегатами, не вошедшими в топ. И последний (21-й) блок в раунде производит POW-майнер в соответствии с очередью.

Задача делегатов не ограничивается подписанием блоков. Одной из задач является и публикация ценовых фидов (price feed) (курс токенов GOLOS в Золотых (GBG)). При этом они напрямую заинтересованы в выставлении корректной стоимости, (которая в свою очередь регулируется рынком), ведь получая вознаграждение в виде Силы Голоса они будут нести потери при публикации недостоверных цен. С учетом того, что ценовые фиды устанавливаются делегатами, которые были избраны сообществом, текущая цена, используемая для конверсии является медианным значением выборки. Из этого следует, что делегаты, имеющие существенное отклонение от медианного значения имеют минимальное влияние на цену конверсии, однако могут терять свою репутацию в сообществе. \
\
**Особая роль**, что именно делегаты устанавливают [параметры](/witnesses/median-props) в блокчейне, а также принимают/отклоняют новые версии кода для обновлений протокола сети (хардфорки).

Делегаты получают награду с каждого произведенного блока, что мотивирует их поддерживать и развивать сеть в долгосрочной перспективе.

Одним из важных преимуществ данной системы – является то, что с её помощью все держатели Силы Голоса являются одновременно акционерами платформы, и могут через доверенных лиц (делегатов) принимать участие в принятии важных для платформы решений.&#x20;

Для безопасности и устойчивой работы сети они должны держать свои ноды в рабочем состоянии 24 часа в сутки, 365 дней в году.

Хотя в принципе, даже если делегат пропускает блок, ничего страшного для сети не произойдет, блок следующего делегата будет содержать пропущенную транзакцию, а время подтверждения составит 6 секунд вместо трех.&#x20;

## Типы и роли нод

Нода, это сердце блокчейна, программное обеспечение, которое обрабатывает блок за блоком, исполняет все операции и хранит состояние системы. Владелец настраивает ноду, выбирает используемые плагины, от конфигурации которых зависит какие возможности предоставляет нода.

### Witness-node

С помощью них происходит обмен данными с другими нодами, они собирают транзакции и когда подходит очередь делегата (владельца сервера) сформировать блок — происходит подпись блока и его трансляция другим узлам. Блок должен быть подписан и доставлен за 3 секунды, выделенные на это делегату. Пропуск блока приводит к задержке выполнения транзакций.

Нередко делегаты держат по две ноды, основную и запасную (резервную). Часто они находятся в разных дата-центрах и не зависят друг от друга. Если с основной нодой происходит неполадка, делегат меняет ключ подписи блоков на резервный и формированием блоков будет заниматься запасная нода.\
\
Инструкция по запуску Witness-ноды доступна [здесь](/witnesses/node/guide).

### Seed-node

Основа для функционирования любой блокчейн системы — peer-to-peer (p2p) соединение и обмен данными. Сид-ноды отличаются тем, что выполняют важную роль — принимают и раздают блоки, разгружая таким образом пропускную способность всей сети и снижая отклик для близких территориально подключений. Да, экономической выгоды держать отдельную сид-ноду нет, но запуск таких нод показывает небезразличное отношение делегата к поддержке стабильности сети.

### API-node

Включение дополнительных плагинов на нодах даёт возможность предоставлять доступ к API для разработчиков и пользователей их сервисов. Такие ноды иногда называют полными, если у них включены все плагины и они хранят историю операций с первого блока. Сервера для них имеют повышенные требования к ресурсам (особенно к оперативной памяти, так как нода хранит ChainBase в RAM). Именно через API ноды происходят запросы на выдачу контента, иной информации из блокчейна, истории операций...

Примеры таких плагинов:

* **network\_broadcast\_api** — отправка транзакции в сеть;
* **database\_api** — плагин предоставляющий доступ к состоянию системы, получение данных об аккаунтах, о блоке, параметров сети;
* **account\_history** — получение списка операций связанных с аккаунтом;
* **worker\_api** — получение списка заявок, информации о заявке;
* **operation\_history** — получение информации об операциях в блоке;
* **witness\_api** — получение списка делегатов, очереди делегатов, информации о конкретном делегате и его голосуемых параметрах сети.

Инструкция по запуску API-ноды доступна [здесь](/witnesses/node/guide-api).


# Установка ноды

* [Подробный гайд](/witnesses/node/guide) запуска делегатской ноды с вкл. seed-обменом
* [Гайд](/witnesses/node/guide-api) по запуску публичной API-ноды и настройкой Nginx
* [Настройка](/witnesses/node/guide-exchange) cli\_wallet и ноды для бирж

{% hint style="info" %}
Обновляемый делегатами [список](https://wallet.golos.id/nodes) API и SEED нод.

Скомпилированные актуальные бинарники ноды и кошелька:

* `wget`[`https://files.golos.app/golosd`](https://files.golos.app/golosd)
* `wget`[`https://files.golos.app/cli_wallet`](https://files.golos.app/cli_wallet)
  {% endhint %}


# Гайд для witness/seed ноды

Рекомендованные (минимальные) системные требования:

* 4 Гб оперативной памяти и 80 Гб SSD накопителя
* Linux-система, напр. Ubuntu 18.04/20.04 + стабильный интернет&#x20;

## Устанавливаем Docker

{% code overflow="wrap" %}

```
sudo apt-get update && 
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
```

{% endcode %}

{% code overflow="wrap" %}

```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```

{% endcode %}

{% code overflow="wrap" %}

```
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

{% endcode %}

{% code overflow="wrap" %}

```
sudo apt-get update && 
sudo apt-get install docker-ce docker-ce-cli containerd.io -y
```

{% endcode %}

## Устанавливаем ноду

Скачиваем файл цепочки блоков **only block\_log** (без него синхронизация от сети seed-нод занимает около 2-3 суток), либо полный **backup witness node** (с ним запуск займёт около часа).

{% tabs %}
{% tab title="Германия 1" %}
{% code title="only block\_log" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379169-sub1@u379169-sub1.your-storagebox.de:block_log ~/home/blockchain/
```

{% endcode %}

{% code title="backup witness node" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379169-sub1@u379169-sub1.your-storagebox.de: ~/home/blockchain/
```

{% endcode %}

{% code title="password" %}

```
veAujuuVZtivnUj7
```

{% endcode %}
{% endtab %}

{% tab title="Финляндия 1" %}
{% code title="only block\_log" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379085-sub1@u379085-sub1.your-storagebox.de:block_log ~/home/blockchain/
```

{% endcode %}

{% code title="backup witness node" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379085-sub1@u379085-sub1.your-storagebox.de: ~/home/blockchain/
```

{% endcode %}

{% code title="password" %}

```
dg8NrzpYZ3gMiU7t
```

{% endcode %}
{% endtab %}

{% tab title="Германия 2" %}
{% code title="only block\_log" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379178-sub1@u379178-sub1.your-storagebox.de:block_log ~/home/blockchain/
```

{% endcode %}

{% code title="backup witness node" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u379178-sub1@u379178-sub1.your-storagebox.de: ~/home/blockchain/
```

{% endcode %}

{% code title="password" %}

```
Z8iSXLhyXsCBGqeL
```

{% endcode %}
{% endtab %}

{% tab title="Финляндия 2" %}
{% code title="only block\_log" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u378847-sub1@u378847-sub1.your-storagebox.de:block_log ~/home/blockchain/
```

{% endcode %}

{% code title="backup witness node" overflow="wrap" %}

```
rsync --progress -e 'ssh -p23' --recursive u378847-sub1@u378847-sub1.your-storagebox.de: ~/home/blockchain/
```

{% endcode %}

{% code title="password" %}

```
db3YNrkPtrdyF6id
```

{% endcode %}
{% endtab %}
{% endtabs %}

### **Генерируем ключи**

Для облегчения получения ключей, вместо запуска ноды без них, использования команды `suggest_brain_key` в cli-wallet для генерирования, правки конфига и перезапуска ноды, можно сразу сгенерировать их [здесь](https://control.viz.world/tools/keys/), или на [раз](https://cyberway.ropox.app/cyberway/keygen) / [два](https://gapi.golos.today/utils/keys).

![](https://lh6.googleusercontent.com/CiBEBEORRNyJRZDLDmgrPpqZ8k0yG6NR0doq88h26YaRpH5ioh-eOcFFT-ztCMgVA9u2PAAYnnBBOJ8wkKo10N2NYRPC7e5H3EZrdZiZOIQw_Az1lmUl6Tlut17nbMc5AroXUR5g)

Только в Public-key (публичном ключе) заменить три начальных символа `VIZ` на `GLS`. Этот ключ нам понадобится для объявления себя делегатом позднее, а Private-key (приватный ключ) уже на следующем шаге.

### **Загружаем конфиг**

Предварительно заменив значения `witness` и `private-key` на свои. \
В качестве `witness` запишем **логин без @** от своего аккаунта на Голос&#x435;**,** `private-key` тот что сгенерировали на шаге выше.

```
mkdir ~/config && echo 'p2p-endpoint = 0.0.0.0:4243
webserver-thread-pool-size = 4
webserver-http-endpoint = 0.0.0.0:8090
webserver-ws-endpoint = 0.0.0.0:8091
read-wait-micro = 500000
max-read-wait-retries = 2
write-wait-micro = 500000
max-write-wait-retries = 3
single-write-thread = true
enable-plugins-on-push-transaction = false
block-num-check-free-size = 7200
plugin = chain p2p json_rpc webserver network_broadcast_api witness database_api witness_api
clear-votes-before-block = 4294967295
store-account-metadata = false
store-memo-in-savings-withdraws = false
store-comment-extras = false
skip-virtual-ops = true
enable-stale-production = false
required-participation = 33
witness = "ЛОГИН-ДЕЛЕГАТА"
private-key = ПРИВАТНЫЙ-КЛЮЧ-НОДЫ
[log.console_appender.stderr]
stream=std_error
[log.file_appender.p2p]
filename=logs/p2p/p2p.log
[logger.default]
level=debug
appenders=stderr
[logger.p2p]
level=none
appenders=stderr' | sudo tee -a ~/config/config.ini
```

### Использование Docker-Compose

{% hint style="info" %}
Для тех кто разбирается, обратите внимание на [этот пост](https://golos.id/ru--golos/@lex/variant-zapuska-nody-s-docker-compose).
{% endhint %}

### **Запускаем контейнер**

```
sudo docker run -it \
    -p 4243:4243 \
    -v ~/config/config.ini:/etc/golosd/config.ini \
    -v ~/home/blockchain:/var/lib/golosd/blockchain \
    -v ~/wallet:/golosd \
    --log-opt max-size=500m \
    --name golosd golosblockchain/golos:latest
```

Начнётся загрузка образа ноды и реплей (наполнение файла оперативных данных `shared_memory.bin` из блоков), который будет продолжаться от пары часов до суток (в зависимости от производительности вашего сервера).&#x20;

Можно оставить окно терминала или закрыть его, подключившись позднее и зайдя в логи ноды командой:

```
sudo docker logs -f --tail 50 golosd
```

С появлением в логах ноды подобных сообщений о получении блоков, окно терминала можно закрыть (всё в порядке).

![](https://lh4.googleusercontent.com/xfrNK9kKgadic6F7mAiZ3notwNTdG1IxzMwWWtybsdox6VtV9HrXU5LLkQyLBWHPb-GLgKcv39spoG9Heavv4yTQItEQRyc01aJjCi21BfGorCxs6aGyPyYTxgkzea_8iv6QAFzd)

### Телеграм-бот о пропуске блоков

Для отслеживания работы делегатских нод и пропуска ими блоков можно использовать бот [@golos\_witness\_monitor\_bot](https://t.me/golos_witness_monitor_bot)

## **Работа с cli-wallet**

{% hint style="info" %}
Эти действия нужны лишь для первого запуска ноды.
{% endhint %}

Заходим в cli\_wallet ноды.&#x20;

```
sudo docker exec -it golosd cli_wallet \
    -w /golosd/wallet.json \
    -s ws://localhost:8091
```

Добавляем свой пароль к cli\_wallet (запишите его и сохраните):

```
set_password 123456789
```

Разблокируем доступ:

```
unlock 123456789
```

Импортируем в cli\_wallet наш приватный активный ключ аккаунта-делегата (ключ, который смотреть тут <https://golos.id/@lex/permissions>, начинается с цифры 5)**.**

```
import_key 5Js............
```

Объявляем себя делегатом, с публичным ключом GLS (который мы сгенерировали ранее в паре к приватному ключу для конфига ноды)**.**

Нужно заменить логин, ссылку на пост/аккаунт делегата + публичный ключ.

```
update_witness "ЛОГИН" "https://golos.id/@ЛОГИН" GLS............. true
```

Публикуем свой первый прайс-фид, заменив на свой логин-делегата.

```
publish_feed ЛОГИН {"quote":"1.000 GOLOS", "base":"0.500 GBG"} true
```

Для выхода из cli\_wallet вводим команду:

```
quit
```

## **Публикация прайсфидов**

Запускаем в докере ещё один контейнер, подробнее об этом скрипте можно прочитать [здесь](https://wiki.golos.id/witnesses/price-feed).

```
sudo docker run -it \
    -e NODE=ws://localhost:8091 \
    -e WITNESS=ЛОГИН-ДЕЛЕГАТА \
    -e KEY=ПРИВАТНЫЙ-АКТИВНЫЙ-КЛЮЧ \
    --log-opt max-size=500m \
    --name feed --net=container:golosd vvk123/golos-witness-tools ./update_price_feed.py --monitor
```

\* нужно заменить логин и приватный активный ключ аккаунта-делегата на свои

Пример скриншота после выполнения команды:

![](https://lh6.googleusercontent.com/zmlDvPxwhoHPAvQwz4MzO8esAFGcO26_fWM1Mvb_5eMQxavdQb6HIBwDYuPEOo_zQXfIbRup0SvM_v150D4mSJ6UCwHcO6LCS2h_ZOWnSoY5D9YrjVRyL2urxo22qWxvxGPCnx7N)

После появления логов с калькуляцией курса GBG, закрываем окно терминала.

## **Изменения в конфиге**

Заходим в конфиг командо&#x439;**:**

```
sudo nano ~/config/config.ini
```

Вносим нужные правки, нажимаем `Ctrl+O`, подтверждаем `Enter`, выходим `Ctrl+X`**.**

Перезапускаем контейнер ноды.

```
sudo docker restart golosd
```

## **Делегатские параметры**

Заходим на <https://golos.id/~witnesses> и напротив своего делегата в столбце “Параметры” нажимаем на значок настроек **(**&#x43E;писание каждого параметра возникает при наведении мышкой).

[Подробнее](https://wiki.golos.id/witnesses/median-props) о значении медианных параметров. Изменить параметры можно и через [cli\_wallet](/witnesses/node/guide#rabota-s-cli-wallet) ноды, заменив логин и выполнив команду.\
\
Параметры в порядке появления в хардфорках блокчейна:

{% tabs %}
{% tab title="16" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"account_creation_fee":"1.000 GOLOS", "maximum_block_size":65536, "sbd_interest_rate":0, "create_account_min_golos_fee":"0.100 GOLOS", "create_account_min_delegation":"1.000 GOLOS", "create_account_delegation_time":2592000, "min_delegation":"1.000 GOLOS"} true
```

{% endcode %}
{% endtab %}

{% tab title="19" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"max_referral_interest_rate":1000, "max_referral_term_sec":15552000, "min_referral_break_fee":"1.000 GOLOS", "max_referral_break_fee":"100.000 GOLOS", "posts_window":3, "posts_per_window":1, "comments_window":200, "comments_per_window":10, "votes_window":15, "votes_per_window":5, "max_delegated_vesting_interest_rate":8000, "custom_ops_bandwidth_multiplier":10, "min_curation_percent":7500, "max_curation_percent":7500, "curation_reward_curve":"square_root"} true
```

{% endcode %}
{% endtab %}

{% tab title="22" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"worker_request_creation_fee":"100.000 GBG", "worker_request_approve_min_percent":1500, "sbd_debt_convert_rate":100, "vote_regeneration_per_day":10, "witness_skipping_reset_time":21600, "witness_idleness_time":7776000, "account_idleness_time":15552000} true
```

{% endcode %}
{% endtab %}

{% tab title="23" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"min_invite_balance":"10.000 GOLOS"} true
```

{% endcode %}
{% endtab %}

{% tab title="24" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"asset_creation_fee":"500.000 GBG", "invite_transfer_interval_sec":60} true
```

{% endcode %}
{% endtab %}

{% tab title="26" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"worker_emission_percent":100, "vesting_of_remain_percent":8000, "convert_fee_percent":500, "min_golos_power_to_curate":"1000.000 GBG"} true
```

{% endcode %}
{% endtab %}

{% tab title="27" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"unwanted_operation_cost":"100.000 GOLOS", "unlimit_operation_cost":"10.000 GOLOS"} true
```

{% endcode %}
{% endtab %}

{% tab title="28" %}
{% code overflow="wrap" %}

```
update_chain_properties ЛОГИН {"min_golos_power_to_emission":"2000.000 GBG"} true
```

{% endcode %}
{% endtab %}
{% endtabs %}

## **Обновление ноды**

Ставим “пустой ключ” для ноды чтобы приостановить подпись блоков через параметры на странице <https://golos.id/@lex/witness> (заменив на свой логин).\
\
Или через [cli\_wallet](/witnesses/node/guide#rabota-s-cli-wallet) ноды командой

```
update_witness "ЛОГИН" "https://golos.id" GLS1111111111111111111111111111111114T1Anm true
```

Останавливаем докер-контейнер ноды и удаляем его

```
sudo docker stop golosd && sudo docker rm golosd
```

{% hint style="info" %}
Если в анонсе обновления было указано что нужен реплей, удаляем файл shared\_memory.bin
{% endhint %}

```
sudo rm ~/home/blockchain/shared_memory.bin
```

Останавливаем докер-контейнер скрипта прайсфида и удаляем его

```
sudo docker stop feed && sudo docker rm feed
```

Удаляем образы для ноды и скрипта прайсфида

```
sudo docker rmi golosblockchain/golos && sudo docker rmi vvk123/golos-witness-tools
```

Запускаем контейнер с новой версией

```
sudo docker run -it \
    -p 4243:4243 \
    -v ~/config/config.ini:/etc/golosd/config.ini \
    -v ~/home/blockchain:/var/lib/golosd/blockchain \
    -v ~/wallet:/golosd \
    --log-opt max-size=500m \
    --name golosd golosblockchain/golos:latest
```

После появления логов вида `handle_block "Got 0 transactions on block 34563842 by ..."`, закрываем окно терминала.&#x20;

Возвращаем публичный ключ ноды GLS.............. который ранее сбрасывали через параметры на странице <https://golos.id/@lex/witness>\
\
или через [cli\_wallet](/witnesses/node/guide#rabota-s-cli-wallet), заменив в команде ниже логин, ссылку на пост/аккаунт делегата + публичный ключ на свои:

```
update_witness "ЛОГИН" "https://golos.id/@ЛОГИН" GLS................. true
```

Возвращаем докер-контейнер скрипта публикации прайсфида (заменив логин и приватный активный ключ аккаунта-делегата на свои)

```
sudo docker run -it \
    -e NODE=ws://localhost:8091 \
    -e WITNESS=ЛОГИН-ДЕЛЕГАТА \
    -e KEY=ПРИВАТНЫЙ-АКТИВНЫЙ-КЛЮЧ \
    --log-opt max-size=500m \
    --name feed --net=container:golosd vvk123/golos-witness-tools ./update_price_feed.py --monitor
```

После появления логов с калькуляцией курса GBG, закрываем окно терминала.

## Есть вопросы?

Можно уточнить в чате делегатов <https://t.me/golos_witnesses>


# Настройка для API-ноды

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

Ниже описан вариант установки API-ноды (с хранением истории операций за неделю). Для такой, оптимальный вариант - сервер с 16 Гб оперативной памяти и 100 Гб SSD накопителя, Ubuntu 18.04/20.04.

## Устанавливаем ноду

Устанавливаем [Docker](https://wiki.golos.id/witnesses/node/guide#ustanavlivaem-docker) (если его ещё нет).

Скачиваем большую часть блоков напрямую [с сервера](https://wiki.golos.id/witnesses/node/guide#ustanavlivaem-nodu) (чтобы не тратить 2 суток на их получение и лишнюю нагрузку делегатских seed-нод).

Добавляем конфиг ноды (указанные в нём `202800` блоков = неделя). Какие плагины нужны для ваших целей, можно уточнить в чате делегатов <https://t.me/golos_witnesses>

```
mkdir ~/config && echo 'webserver-thread-pool-size = 8
webserver-http-endpoint = 0.0.0.0:8090
webserver-ws-endpoint = 0.0.0.0:8091
read-wait-micro = 500000
max-read-wait-retries = 2
write-wait-micro = 500000
max-write-wait-retries = 3
single-write-thread = true
enable-plugins-on-push-transaction = false
block-num-check-free-size = 1200
plugin = chain p2p json_rpc webserver network_broadcast_api witness database_api witness_api
plugin = social_network follow tags operation_history account_history market_history
plugin = account_by_key worker_api private_message account_notes event_plugin account_relations
clear-votes-before-block = 4294967295
history-start-block = 38000000
history-blocks = 202800
history-blacklist-ops = producer_reward
history-blacklist-ops = pow2
store-evaluator-events = true
event-blocks = 28800
comment-title-depth = 202800
comment-body-depth = 202800
comment-json-metadata-depth = 202800
follow-max-feed-size = 100
skip-virtual-ops = false
enable-stale-production = false
[log.console_appender.stderr]
stream=std_error
[log.file_appender.p2p]
filename=logs/p2p/p2p.log
[logger.default]
level=debug
appenders=stderr
[logger.p2p]
level=none
appenders=stderr' | sudo tee -a ~/config/config.ini
```

Запускаем ноду в докер-контейнере.

```
sudo docker run -it \
    -p 127.0.0.1:8090:8090 \
    -p 127.0.0.1:8091:8091 \
    -v ~/config/config.ini:/etc/golosd/config.ini \
    -v ~/home/blockchain:/var/lib/golosd/blockchain \
    --log-opt max-size=500m \
    --name golosd golosblockchain/golos:api-node
```

После загрузки докер-образа и реплея (который занимает несколько часов), с получением логов вида `handle_block "Got 0 transactions on block 35071930 by ..."` нода готова к работе.

## Устанавливаем Nginx

```
sudo apt-add-repository ppa:nginx/stable -y
```

```
sudo apt-get update
```

```
sudo apt-get install nginx -y
```

Добавляем файл для своих настроек Nginx.

```
sudo nano /etc/nginx/sites-enabled/node.conf
```

Копируем в него правила, предварительно заменив адрес `server_name` на свой субдомен/домен (не забыв привязать его в настройках DNS к нашему IP сервера). Бесплатные домены можно зарегистрировать напр. [здесь](http://www.freenom.com/ru/freeandpaiddomains.html).

```
server {
listen 80;
server_name test.lexai.host;
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8090;
}
location /ws {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8091;
proxy_read_timeout 3600;
}
}
```

Сохраняем изменения `Ctrl+O`, подтверждаем `Enter`, выходим `Ctrl+X`.

## Устанавливаем Certbot

```
sudo snap install core
```

```
sudo snap refresh core
```

```
sudo snap install --classic certbot
```

```
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```

После следующей команды потребуется ввести:

1. E-mail, на который будут отправляться уведомления о необходимости продления сертификата;&#x20;
2. Согласиться с правилами сервиса введя `A и Enter`;
3. Отказаться от рассылки `N и Enter`;
4. Подтвердить добавление сертификатов к указанным доменам вводом `Enter`;
5. Отказаться от редиректа, введя `1 и Enter`.

```
sudo certbot --nginx
```

Будут добавлены настройки в файл `node.conf`, которые можно перепроверить командой ниже и найти строки с пометкой `# managed by Certbot` в конце файла.

```
sudo nano /etc/nginx/sites-enabled/node.conf
```

Выходим из файла `Ctrl+X`.

Перезапускаем Nginx.

```
service nginx restart
```

Проверяем статус Nginx.

```
sudo systemctl status nginx.service
```

Мы запустили публичную API-ноду, к которой можно подключаться как по адресу `https://test.lexai.host` (RPC) так и `wss://test.lexai.host/ws` (WebSockets).\
\
Кроме того, если на API-ноду ожидается большое количество запросов, советуем обратить внимание на [сервис Jussi](https://golos.id/ru--golos/@lex/kesh-sloi-jussi-dlya-tekh-kto-zapustil-svoi-api-nody), который позволяет перед нодой настроить кеш-слой на базе Redis и Nginx.

При получении письма на e-mail о необходимости обновить сертификат (раз в 90 дней), это можно сделать командой:

```
sudo certbot renew
```

## Есть вопросы?

Можно уточнить в чате делегатов <https://t.me/golos_witnesses>


# Настройка ноды для бирж

## Использование готового cli\_wallet

Скачиваем cli\_wallet и устанавливаем права на файл:

```
wget https://files.golos.app/cli_wallet && chmod +x cli_wallet
```

Запускаем cli\_wallet (список альтернативных публичных [API-нод](https://wallet.golos.id/nodes)):

```
./cli_wallet -s wss://api.golos.id/ws --rpc-http-endpoint 127.0.0.1:8094 --rpc-http-allowip 127.0.0.1
```

Все **параметры запуска** cli\_wallet можно посмотреть командой`./cli_wallet --help`

В примере выше заданы:&#x20;

`--rpc-http-endpoint 127.0.0.1:8094`\
`Endpoint for wallet HTTP RPC to listen on`

`--rpc-http-allowip 127.0.0.1`\
`Allows only specified IPs to connect to the HTTP endpoint`

Возможно вместо запуска cli\_wallet с помощью screen будет удобно использовать режим демона, добавив опцию:

`-d [ --daemon ]`\
`Run the wallet in daemon mode`

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

```
set_password 123456

unlock 123456

import_key 5JX..........
```

Примеры команд к cli\_wallet [описаны ниже](/witnesses/node/guide-exchange#primery-komand-k-cli_wallet-cherez-curl).

## Самостоятельная сборка cli\_wallet

Собрать cli\_wallet можно и с исходного кода за 5 начальных шагов [этой инструкции](/developers/hardforks/hf18_instruction#razdel_4-iznachalnaya-ustanovka-blokcheina).

Подключиться к cli\_wallet (список альтернативных публичных [API-нод](https://wallet.golos.id/nodes)):

```
/usr/local/bin/cli_wallet \
  --wallet="/var/lib/golosd/wallet.json" \
  --server-rpc-endpoint="wss://api.golos.id/ws" \
  --rpc-http-endpoint="127.0.0.1:8094" \
  --rpc-http-allowip="127.0.0.1"
```

## Запуск ноды блокчейна с docker-образа

Устанавливаем [Docker](https://wiki.golos.id/witnesses/node/guide#ustanavlivaem-docker) (если его ещё нет).

[Скачиваем файл](https://wiki.golos.id/witnesses/node/guide#ustanavlivaem-nodu) цепочки блоков (без него синхронизация от seed-нод блокчейна занимает более суток).

Добавляем актуальный файл конфигурации ноды (предварительно поменяв аккаунт отслеживания`track-account` и срок хранения истории `history-blocks`, 864000 блоков x 3 секунды = месяц).

```
echo 'webserver-thread-pool-size = 8
webserver-http-endpoint = 0.0.0.0:8090
webserver-ws-endpoint = 0.0.0.0:8091
read-wait-micro = 500000
max-read-wait-retries = 2
write-wait-micro = 500000
max-write-wait-retries = 3
single-write-thread = true
enable-plugins-on-push-transaction = false
shared-file-size = 2G
block-num-check-free-size = 1200
plugin = chain p2p json_rpc webserver network_broadcast_api database_api operation_history account_history account_by_key
history-start-block = 42000000
history-blocks = 864000
track-account = rudex
clear-votes-before-block = 4294967295
store-account-metadata = false
store-comment-extras = false
skip-virtual-ops = true
enable-stale-production = false
mining-threads = 0
[log.console_appender.stderr]
stream=std_error
[log.file_appender.p2p]
filename=logs/p2p/p2p.log
[logger.default]
level=debug
appenders=stderr
[logger.p2p]
level=none
appenders=stderr' | sudo tee -a ~/config.ini
```

Запускаем контейнер:

```
sudo docker run -d \
    -p 127.0.0.1:8090:8090 \
    -p 127.0.0.1:8091:8091 \
    -p 127.0.0.1:8094:8094 \
    -v ~/config.ini:/etc/golosd/config.ini \
    -v ~/blockchain:/var/lib/golosd/blockchain \
    -v ~/wallet:/golosd \
    --name golosd golosblockchain/golos:latest
```

Начнётся загрузка образа ноды и реплей (наполнение данных `shared_memory.bin` из файла цепочки блоков), который будет продолжаться несколько часов в зависимости от производительности сервера.

Посмотреть логи командой:

```
sudo docker logs -f --tail 50 golosd
```

Запуск приложения cli\_wallet внутри контейнера ноды:

```
sudo docker exec -ti -d golosd cli_wallet \
  --wallet="/golosd/wallet.json" \
  --server-rpc-endpoint="ws://localhost:8091" \
  --rpc-http-endpoint="0.0.0.0:8094" \
  --rpc-http-allowip="172.17.0.1"
```

## Примеры команд к cli\_wallet через curl

Установка на кошелёк пароля и разблокировка:

```
curl --data '{"jsonrpc": "2.0", "method": "set_password", "params": ["123456"], "id": 1}' http://127.0.0.1:8094
```

```
curl --data '{"jsonrpc": "2.0", "method": "unlock", "params": ["123456"], "id": 1}' http://127.0.0.1:8094
```

Импортирование приватного активного ключа в кошелёк:

```
curl --data '{"jsonrpc": "2.0", "method": "import_key", "params": ["5JVFFWRLwz6JoP9kguuRFfytToGU6cLgBVTL9t6NB3D3BQLbUBS"], "id": 1}' http://127.0.0.1:8094
```

Список добавленных в кошелёк аккаунтов:

```
curl --data '{"jsonrpc": "2.0", "method": "list_my_accounts", "params": [], "id": 1}' http://127.0.0.1:8094
```

Получение информации об аккаунте:

```
curl --data '{"jsonrpc": "2.0", "method": "get_account", "params": ["rudex"], "id": 1}' http://127.0.0.1:8094
```

Перевод/трансфер токенов:

```
curl --data '{"jsonrpc": "2.0", "method": "transfer", "params": ["rudex","test","1.000 GOLOS","",true], "id": 1}' http://127.0.0.1:8094
```

Запрос истории последних 50 трансферов где получателем был аккаунт (иные варианты фильтра истории [описаны тут](/developers/hardforks/sf18.4_release#filtraciya-zaprashivaemoi-informacii-ob-operaciyakh-iz-istorii-akkaunta)):

```
curl --data '{"jsonrpc": "2.0", "method": "filter_account_history", "params": ["rudex",-1,50,{"direction":"receiver","select_ops":["transfer_operation"]}], "id": 1}' http://127.0.0.1:8094
```

Получение информации об операциях в блоке:

```
curl --data '{"jsonrpc": "2.0", "method": "get_block", "params": ["30000000"], "id": 1}' http://127.0.0.1:8094
```

Получение операций из блока вместе с виртуальными и trx\_id:

```
curl --data '{"jsonrpc": "2.0", "method": "get_ops_in_block", "params": ["30000000","false"], "id": 1}' http://127.0.0.1:8094
```

Описание команд к cli\_wallet также есть [здесь](/developers/api/cli-wallet) или можно сформировать формат пользуясь сервисом [gapi.golos.today](https://gapi.golos.today/api/)


# Настройка ElasticSearch

https\://golos.id/@lex/vnutrennii-poisk-na-golose-naidyotsya-vsyo

## Установка ElasticSearch ([ссылка](https://www.elastic.co/guide/en/elasticsearch/reference/current/deb.html))

```
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
```

```
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list
```

```
sudo apt-get update && sudo apt-get install elasticsearch
```

### Добавляем настройки в конфиг

Добавить в конфиг `/etc/elasticsearch/elasticsearch.yml`

```
network.host: 0.0.0.0
xpack.security.enabled: true
discovery.type: single-node 
http.cors.enabled : true
http.cors.allow-origin: "*"
http.cors.allow-headers: Content-Type,Authorization
```

Перезапуск для применения настроек

```
sudo service elasticsearch restart
```

### Устанавливаем пароли на доступы

```
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive
```

В конфиг ноды позднее нужно добавить пароль заданный к роли **elastic** (для примера 123456). Перезапуск для применения настроек

```
sudo service elasticsearch restart
```

### Добавляем read-only роль `golosclient`

```
curl -u elastic:123456 -XPOST 'localhost:9200/_xpack/security/role/golosclient_readonly_role' \
-H 'Content-Type: application/json' \
-d'{"indices":[{"names":"*","privileges":["read"]}]}'
```

### Добавляем read-only пользователя `golosclient`

```
curl -u elastic:123456 -XPOST localhost:9200/_xpack/security/user/golosclient \
-H 'Content-Type: application/json' \
-d'{"roles":["golosclient_readonly_role"],"password":"golosclient"}'
```

Перезапуск для применения настроек

```
sudo service elasticsearch restart
```

## Добавляем параметры к ноде

К списку плагинов дописываем `elastic_search`

В конфиг ноды добавляем параметры:

```
elastic-search-uri = http://172.17.0.1:9200
elastic-search-login = elastic
elastic-search-password = 123456
elastic-search-versions-depth = 10
elastic-search-skip-comments-before = 2019-01-01T00:00:00
```

где `elastic-search-uri` прописан с учётом того что нода будет запускаться через Docker, а пароль к пользователю elastic заданный на [этом шаге](/witnesses/node/elasticsearch#ustanavlivaem-paroli-na-dostupy).

Перезапускаем ноду с её реплеем, индекс ElasticSearch должен наполняться.

## Структура и примеры

Количество элементов в индексе

```
curl -u golosclient:golosclient -XGET https://betasearch.golos.today/blog/post/_count?pretty
```

Пример запроса поста из базы

```
curl -u golosclient:golosclient -XGET https://betasearch.golos.today/blog/post/lex.vnutrennii-poisk-na-golose-naidyotsya-vsyo?pretty
```

Пример запроса статистики ElasticSearch

```
curl -u elastic:123456 -XGET "http://localhost:9200/_stats?pretty"
```

Mapping всех типов индекса blog:

```
curl -u elastic:123456 -XGET "http://localhost:9200/blog/_mapping?pretty"
```

Ответ

```
{
  "blog" : {
    "mappings" : {
      "properties" : {
        "author" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "body" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "category" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "created" : {
          "type" : "date"
        },
        "depth" : {
          "type" : "long"
        },
        "donates" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "donates_uia" : {
          "type" : "long"
        },
        "id" : {
          "type" : "long"
        },
        "json_metadata" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "net_rshares" : {
          "type" : "long"
        },
        "parent_author" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "parent_permlink" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "permlink" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "root_author" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "root_permlink" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "root_title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "tags" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "total_votes" : {
          "type" : "long"
        }
      }
    }
  }
}
```


# Нода с отладкой GDB

Установка ноды на сервере с ОС Ubuntu 18.04

Бывает, что из-за ошибок демон golosd вылетает с сообщением Segmentation fault или Aborted, в папке /var/lib/golosd появляется core dumped. При этом больше никакой информации. В таком случае пригодится отладка через [gdb](https://ru.wikipedia.org/wiki/GNU_Debugger).

Устанавливаем необходимые пакеты:

```
sudo apt-get update
```

```
sudo apt-get install -y \
        autoconf \
        automake \
        autotools-dev \
        bsdmainutils \
        build-essential \
        cmake \
        doxygen \
        git \
        ccache \
        libboost-all-dev \
        libreadline-dev \
        libssl-dev \
        libtool \
        ncurses-dev \
        pbzip2 \
        pkg-config \
        python3 \
        python3-dev \
        python3-pip \
        runit
```

```
sudo pip3 install gcovr
```

Копируем исходные файлы для сборки ноды из github:

```
git clone https://github.com/golos-blockchain/chain-node.git && cd chain-node
```

```
git submodule update --init --recursive -f
```

Задаём значения переменных и конфигурируем проект:

```
mkdir build && cd build
```

```
cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_GOLOS_TESTNET=FALSE \
    -DBUILD_SHARED_LIBRARIES=FALSE \
    -DLOW_MEMORY_NODE=FALSE \
    -DCHAINBASE_CHECK_LOCKING=FALSE \
    ..
```

Запуск сборки с установкой демона в `/usr/local/`, исполнив:

```
make -j $(nproc) && sudo make install
```

## Подготовка файлов

```
mkdir -p ~/chain-node/build/programs/golosd/witness_node_data_dir/blockchain
```

```
sudo cp ~/chain-node/share/golosd/snapshot5392323.json ~/chain-node/build/programs/golosd/ && 
sudo cp ~/chain-node/share/golosd/seednodes ~/chain-node/build/programs/golosd/witness_node_data_dir/ && 
sudo cp ~/chain-node/share/golosd/config/config_witness.ini ~/chain-node/build/programs/golosd/witness_node_data_dir/config.ini
```

Возможно понадобится прописать сид-ноды в конфиг:\
`p2p-seed-node = golos1.lexai.host:4243`\
`p2p-seed-node = golos2.lexai.host:4243`

Копируем в папку `.../golosd/witness_node_data_dir/blockchain` бэкап файлов блоклогс и шаред-мемори, чтобы не терять время на синхронизацию сети (возможно скачать [здесь](https://wiki.golos.id/witnesses/node/guide#ustanavlivaem-nodu)).

## Запуск GDB

Устанавливаем отладчик gdb

```
sudo apt-get install gdb -y
```

Переходим в папку проекта

```
cd ~/chain-node/build/programs/golosd
```

Запускаем демон через gdb

```
gdb ./golosd
```

На вопрос *Quit this debugging session? (y or n), отменяем вводом **n***

Включаем сохранение лога (в файл gdb.txt) рядом с файлом запуска

```
set logging on
```

Подтверждаем запуск

```
run
```


# Медианные параметры

Ряд параметров блокчейна являются голосуемыми, т.е. делегаты подают свои значения, из которых потом формируются консенсусные значения.

Медианные параметры сети доступны на <https://explorer.golos.id> или на [https://gapi.golos.today/api/database\_api/get\_chain\_properties](https://gapi.golos.today/steemjs/api/database_api/get_chain_properties)

## Курс GBG/GOLOS

Данный курс отвечает за внутренние конвертации GBG-GOLOS и начисления вознаграждений.

Обновление курса происходит 1 раз за период `STEEMIT_FEED_INTERVAL_BLOCKS`.

* Происходит вычисление текущего медианного курса следующим образом:
  1. Проверяется количество опубликованных ценовых фидов в текущем раунде подписи блоков.&#x20;
  2. Список фидов сортируется по значению.
  3. Берётся курс, который оказался в середине отсортированного списка.&#x20;
* Текущее значение медианного курса попадает в условную таблицу медианных курсов, которая хранит курсы за промежуток времени `STEEMIT_FEED_HISTORY_WINDOW` (3.5 дня).
* Таблица с этими курсами сортируется и уже из неё берётся значение, которое находится в середине.
* Проверяется, что получившееся значение не меньше минимально возможной цены GBG/GOLOS, которая является ограничителем размера долга GBG. Минимальная цена вычисляется по формуле `min_price = 9 * sbd_supply.amount / current_supply.amount`
* Это значение (либо min\_price) и становится текущим действующим медианным курсом, по которому происходят операции конвертаций.

#### Некоторые следствия

* Делегаты с устаревшими или сильно завышенными/заниженными прайсфидами мало влияют на медианный курс, так как оказываются по краям отсортированного списка
* Медианный курс меняется плавно, в течении 3.5 дней
* Можно условно предсказать, куда стремится медиана, глядя на самое последние значение из истории опубликованных медиан <https://gapi.golos.today/steemjs/api/witness_api/get_feed_history>

## Начальные параметры

Помимо курса, делегаты голосуют и за многие другие параметры, в них используется более простой механизм:

* Берутся все значения параметра, опубликованные делегатами в текущем раунде подписи блоков;
* Список сортируется по значению параметра;
* Берётся значение, которое оказалось в середине отсортированного списка;
* Получившееся значение вступает в силу немедленно.

### account\_creation\_fee

Размер комиссии в токенах GOLOS за создание аккаунта без делегирования *(fee поступает в фонд сообщества)*.

### maximum\_block\_size

Максимально допустимый размер блока в сети блокчейна (в байтах).

### sbd\_interest\_rate

Размер годового процента по GBG, выплачиваемого держателям этих токенов на сейф-балансах.

### **create\_account\_min\_golos\_fee**

Размер комиссии в токенах GOLOS, требуемый для создания аккаунта с делегированием *(fee поступает в фонд сообщества)*.

### **create\_account\_min\_delegation**

Минимально возможное количество Силы Голоса при создании аккаунта с делегированием.

### **create\_account\_delegation\_time**

Время «заморозки» делегированной Силы Голоса при создании аккаунта с делегированием (в секундах).

### **min\_delegation**

Минимально возможное количество Силы Голоса для делегирования с аккаунта на аккаунт.

## Параметры с 19 ХФ

### **max\_referral\_interest\_rate**

Макс. процент выплат рефереру от доходов реферала.

### **max\_referral\_term\_sec**

Макс. срок получения выплат рефереру.

### **min\_referral\_break\_fee**

Мин. сумма комиссии для отключения привязки реферала к рефереру.

### **max\_referral\_break\_fee**

Макс. сумма комиссии для отключения привязки реферала к рефереру.

### **posts\_window**

Длительность интервала/окна для постов в минутах.

### **posts\_per\_window**

Количество постов за интервал.

### **comments\_window**

Длительность интервала/окна для комментариев в минутах.

### **comments\_per\_window**

Количество комментариев за интервал.

### **votes\_window**

Длительность интервала/окна для апвоутов (лайков/дизлайков) в минутах.

### **votes\_per\_window**

Количество апвоутов за интервал.

### **max\_delegated\_vesting\_interest\_rate**

Макс. процент отчислений от кураторских для инвесторов делегирующих свою Силу Голоса.

### **custom\_ops\_bandwidth\_multiplier**

Повышающий коэффициент "расходования" пропускной способности для отправки операций `custom_json`.

### **min\_curation\_percent**

Минимальный размер процента кураторских.

### **max\_curation\_percent**

Максимальный размер процента кураторских.

### **curation\_reward\_curve**

Кривая кураторского вознаграждения.

~~**auction\_window\_size**~~**&#x20;(устарел)**\
Длительность штрафного окна при голосовании (в секундах).

~~**allow\_distribute\_auction\_reward**~~**&#x20;(устарел)**\
Распределение штрафа из штрафного окна в пользу других кураторов.

~~**allow\_return\_auction\_reward\_to\_fund**~~**&#x20;(устарел)**\
Распределение штрафа из штрафного окна в фонд вознаграждени&#x439;**.**

## Параметры с 22 ХФ

~~**worker\_reward\_percent**~~**&#x20;(выкл**, см. [worker\_emission\_percent](/witnesses/median-props#worker_emission_percent)**)**\
Процент от эмиссии в пул воркеров.

~~**witness\_reward\_percent**~~**&#x20;(выкл**, перенесен в конфи&#x433;**)**\
Процент от эмиссии в пул делегатов.

~~**vesting\_reward\_percent**~~**&#x20;(выкл**, см. [vesting\_of\_remain\_percent](/witnesses/median-props#vesting_of_remain_percent)**)**\
Процент от эмиссии в пул вестинга/на Силу Голоса.

### worker\_request\_creation\_fee

Размер комиссии в GBG за подачу заявки воркером в фонд сообщества.

### worker\_request\_approve\_min\_percent

Процент от общей СГ системы, необходимый для одобрения заявки воркера.

### sbd\_debt\_convert\_rate

Процент от общего кол-ва GBG для ежедневной конвертации в GOLOS при долге более 20%.

### vote\_regeneration\_per\_day

Степень регенерации батарейки - кол-во полных 100% апвоутов в день.

### witness\_skipping\_reset\_time

Срок пропуска блоков, после которого ключ делегата сбрасывается и нода не участвует в подписании (в секундах).

### witness\_idleness\_time

Срок с подписи последнего блока делегатом, после которого все голоса с него обнуляются (в секундах).

### account\_idleness\_time

Срок неактивности аккаунта, после которого отменяется делегирование и запускается понижение СГ (в секундах).

## Параметры с 23 ХФ

~~**claim\_idleness\_time**~~ (**выкл,** в 27 ХФ)\
Длительность окна/временного цикла для востребования пользователем своей доли от эмиссии (в секундах).

### min\_invite\_balance

Минимальный баланс инвайта/чека для создания (в случае активации инвайта на регистрацию аккаунта, размер параметра является fee и списывается в фонд сообщества).

## Параметры с 24 ХФ

### asset\_creation\_fee

Размер комиссии в GBG за создание ассета/тикера токена в 5 символов и более (4 символа x10 от параметра, 3 символа x50 от параметра).

### invite\_transfer\_interval\_sec

Защита от спама трансферов с чека на чек, пауза (в секундах) между такими переводами.

## Параметры с 26 ХФ

### worker\_emission\_percent

Процент от эмиссии в пул воркеров.

### vesting\_of\_remain\_percent

Процент распределения оставшегося в пул вестинга и общий пул (после вычета % в пул воркеров и 15% в пул делегатов).

### convert\_fee\_percent

Процент комиссии по внутренней конвертации GOLOS в GBG.

### min\_golos\_power\_to\_curate

Минимальная сумма СГ (в GBG), с которой пользователь начнёт получать процент за курирование контента.

~~**negrep\_posting\_window**~~ (**выкл**, см. [unlimit\_operation\_cost](#unlimit_operation_cost))\
Длительность интервала/окна в минутах для постов/комментариев/апвоутов пользователей с отрицательной репутацией.

~~**negrep\_posting\_per\_window**~~ (**выкл**, см. [unlimit\_operation\_cost](#unlimit_operation_cost))\
Количество постов/комментариев/апвоутов за интервал.

## Параметры с 27 ХФ

### unwanted\_operation\_cost

Размер комиссии за отправку нежелательных операций (если получатель заблокировал отправителя или выбрал опцию не беспокоить).

### unlimit\_operation\_cost

Размер комиссии за отправку операций при отрицательной репутации и сверх лимитов post/comment/vote-window.

## Параметры с 28 ХФ

### min\_golos\_power\_to\_emission

Минимальная сумма СГ (в GBG), с которой пользователь начнёт получать долю от эмиссии на TIP-баланс, минуя накопительный CLAIM-баланс.


# Скрипты для price feed

Для публикации прайсфидов GBG/GOLOS

## golos-witness-tools на Python (от [@vvk](https://golos.id/@vvk))

* [Проект на github](https://github.com/bitfag/golos-witness-tools)
* [Анонс](https://golos.id/golostools/@vvk/anons-novogo-skripta-obnovleniya-price-feed-i-proekta-golos-witness-tools) + пост об [обновлении ](https://golos.id/golos/@vvk/golos-witness-tools-bitshares)скрипта с поддержкой BitShares
* Не требует наличия cli\_wallet
* Удобен для запуска из cron
* Возможность работы в виде docker-контейнера

Пример запуска скрипта к ноде в докер-контейнере есть [здесь](https://wiki.golos.id/witnesses/node/guide#publikaciya-praisfidov).

## setfeed на JS (от [@jackvote](https://golos.id/@jackvote))

Подробнее на <https://golos.id/ru--golos/@jackvote/paket-dlya-delegatov>

[Вариант](https://github.com/avral/setfeed) с его запуском через Docker (от [@avral](https://golos.id/@avral))


