# 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
);
```
