Skip to content

Commit cf733fd

Browse files
authored
Merge pull request #167 from VIZ-Blockchain/agent-access
HF15: agent access — delegate listed operations to an agent account
2 parents e0cc159 + b4b63eb commit cf733fd

27 files changed

Lines changed: 1600 additions & 2 deletions

File tree

‎@l10n/ru/docs/plugins/database-api.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,18 @@ json_rpc::plugin, chain::plugin
394394

395395
---
396396

397+
### `get_agent_permissions(account)`
398+
399+
Возвращает агентов принципала (HF15, [агент-доступ](../protocol/operations/agent-access.md)), по порядку имён. Не больше 16 строк, без пагинации. Истёкшие строки отдаются с `expired: true`: они ничего не дают и удаляются при следующей выдаче принципала.
400+
401+
```json
402+
{ "method": "database_api.get_agent_permissions", "params": ["alice"] }
403+
```
404+
405+
**Возвращает:** массив `agent_permission_api_object` — `account`, `agent_name`, `agent_key`, `operations`, `expiration`, `addons`, `expired`.
406+
407+
---
408+
397409
## Коды ошибок
398410

399411
| Код | Значение |
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Агент-доступ (HF15)
2+
3+
Аккаунт (**принципал**) может завести **агентов**: именованные публичные ключи, которым разрешено отправлять заданный список операций от его имени. Агент — не аккаунт, а запись у принципала. Собственные ключи принципала никому не передаются, агент отзывается одной операцией.
4+
5+
Типичные случаи: торговый бот, который ставит в прогнозных рынках; сервис, который делает выплаты переводами; ключ, который внешний сервис (например vizhub) принимает для входа и своих действий.
6+
7+
---
8+
9+
## `set_agent_permission_operation` (ID 105)
10+
11+
**Подпись:** `active` аккаунта `account`. До HF15 отвергается.
12+
13+
| Поле | Тип | Описание |
14+
|------|-----|----------|
15+
| `account` | `account_name_type` | Принципал |
16+
| `agent_name` | `string` | Имя агента, уникально у принципала; `[a-z0-9_-]`, непустое |
17+
| `agent_key` | `public_key_type` | Ключ агента; обязателен при выдаче, при отзыве не проверяется |
18+
| `operations` | `flat_set<string>` | Wire-имена операций, которые может подписывать ключ (`transfer`, `pm_place_bet`, …) |
19+
| `expiration` | `time_point_sec` | `1970-01-01T00:00:00` = бессрочно; время в прошлом = отзыв |
20+
| `addons` | `flat_set<string>` | Метки для внешних сервисов (напр. `vizhub`); до 10 штук, каждая короче 64 байт, без `,`. Нода их хранит, но не толкует: в цепи они ничего не дают |
21+
| `extensions` | `extensions_type` | Всегда `[]` |
22+
23+
Выдача (бот может ставить и переводить, vizhub принимает его ключ):
24+
25+
```json
26+
["set_agent_permission", {
27+
"account": "alice",
28+
"agent_name": "trade-bot",
29+
"agent_key": "VIZ6MyX5QiXAXRZk7SYCiqpi6Mtm8UbHWDFSV8HPpt7FJyahCnc2T",
30+
"operations": ["pm_place_bet", "transfer"],
31+
"expiration": "2027-01-01T00:00:00",
32+
"addons": ["vizhub"],
33+
"extensions": []
34+
}]
35+
```
36+
37+
Агент только с addons (ключ для внешнего сервиса, без операций цепи):
38+
39+
```json
40+
["set_agent_permission", {
41+
"account": "alice",
42+
"agent_name": "hub-login",
43+
"agent_key": "VIZ7…",
44+
"operations": [],
45+
"expiration": "1970-01-01T00:00:00",
46+
"addons": ["vizhub"],
47+
"extensions": []
48+
}]
49+
```
50+
51+
Отзыв — оба списка пусты (ключ можно передать нулевой `VIZ1111111111111111111111111111111114T1Anm`):
52+
53+
```json
54+
["set_agent_permission", {
55+
"account": "alice", "agent_name": "trade-bot",
56+
"agent_key": "VIZ1111111111111111111111111111111114T1Anm",
57+
"operations": [], "expiration": "1970-01-01T00:00:00", "addons": [], "extensions": []
58+
}]
59+
```
60+
61+
Повторная выдача по тому же имени заменяет ключ, операции, addons и срок (смена ключа = перевыдача).
62+
63+
## Правила
64+
65+
- **Не делегируются никогда:** `set_agent_permission`, `proposal_create`, `proposal_update`, `proposal_delete`, `account_update`, `recover_account`, `change_recovery_account`, `set_account_price`, `set_subaccount_price`, `target_account_sale`. Виртуальные операции и устаревшие алиасы (писать `validator_update`, а не `witness_update`) отвергаются.
66+
- **Один ключ — один агент:** ключ, уже привязанный к другому имени того же принципала, отвергается.
67+
- **Не больше 16 агентов** на принципала. Выдача сначала удаляет его истёкших агентов.
68+
- **Когда подпись агента засчитывается:** транзакции не нужны master- и regular-подписи, собственные ключи принципала её не подписывают, агент жив (срок не истёк, список операций не пуст), его список покрывает **каждую** операцию транзакции, которой нужна подпись, и его ключ есть среди подписей. Через вложенные `account_auths` доступа нет.
69+
- **Удаление:** все агенты принципала стираются при смене master, смене active, восстановлении аккаунта, прямой продаже и закрытии аукциона. Смена только regular их не трогает.
70+
71+
## Чтение агентов
72+
73+
`database_api.get_agent_permissions(account)` — см. [database_api](../../plugins/database-api.md#get-agent-permissions-account).

‎docs/.vitepress/config.mts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface SidebarLabels {
4242
virtualOperations: string;
4343
operations: string;
4444
accounts: string;
45+
agentAccess: string;
4546
transfersVesting: string;
4647
validators: string;
4748
content: string;
@@ -127,6 +128,7 @@ const en: SidebarLabels = {
127128
virtualOperations: 'Virtual Operations',
128129
operations: 'Operations',
129130
accounts: 'Accounts',
131+
agentAccess: 'Agent Access',
130132
transfersVesting: 'Transfers & Vesting',
131133
validators: 'Validators',
132134
content: 'Content',
@@ -212,6 +214,7 @@ const ru: SidebarLabels = {
212214
virtualOperations: 'Виртуальные операции',
213215
operations: 'Операции',
214216
accounts: 'Аккаунты',
217+
agentAccess: 'Агент-доступ',
215218
transfersVesting: 'Переводы и вестинг',
216219
validators: 'Валидаторы',
217220
content: 'Контент',
@@ -297,6 +300,7 @@ const zhCN: SidebarLabels = {
297300
virtualOperations: '虚拟操作',
298301
operations: '操作',
299302
accounts: '账户',
303+
agentAccess: 'Agent Access',
300304
transfersVesting: '转账与质押',
301305
validators: '验证人',
302306
content: '内容',
@@ -439,6 +443,7 @@ function buildSidebar(t: SidebarLabels, prefix: string): DefaultTheme.SidebarIte
439443
{ text: t.awards, link: p('/protocol/operations/awards') },
440444
{ text: t.subscriptions, link: p('/protocol/operations/subscriptions') },
441445
{ text: t.accountMarket, link: p('/protocol/operations/account-market') },
446+
{ text: t.agentAccess, link: p('/protocol/operations/agent-access') },
442447
{ text: t.predictionMarkets, link: p('/protocol/operations/prediction-markets') },
443448
{ text: t.proposals, link: p('/protocol/operations/proposals') },
444449
],

‎docs/plugins/database-api.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,18 @@ Returns account namespace registrations available for sale (subaccount creation
394394

395395
---
396396

397+
### `get_agent_permissions(account)`
398+
399+
Returns the agents of a principal (HF15 [agent access](../protocol/operations/agent-access.md)), ordered by agent name. At most 16 rows, no paging. Expired rows are returned with `expired: true`: they grant nothing and are removed on the principal's next grant.
400+
401+
```json
402+
{ "method": "database_api.get_agent_permissions", "params": ["alice"] }
403+
```
404+
405+
**Returns:** Array of `agent_permission_api_object` — `account`, `agent_name`, `agent_key`, `operations`, `expiration`, `addons`, `expired`.
406+
407+
---
408+
397409
## Error Codes
398410

399411
| Code | Meaning |
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Agent Access (HF15)
2+
3+
An account (the **principal**) can register **agents**: named public keys that may broadcast a listed set of operations on the principal's behalf. An agent is not an account — it is a record on the principal. The principal's own keys are never shared, and one operation revokes the agent.
4+
5+
Typical uses: a trading bot that places prediction-market bets, a service that pays out transfers, or a key an external service (for example vizhub) accepts for its own login and actions.
6+
7+
---
8+
9+
## `set_agent_permission_operation` (ID 105)
10+
11+
**Auth:** `active` of `account`. Rejected before HF15.
12+
13+
| Field | Type | Description |
14+
|-------|------|-------------|
15+
| `account` | `account_name_type` | Principal |
16+
| `agent_name` | `string` | Agent name, unique per principal; `[a-z0-9_-]`, non-empty |
17+
| `agent_key` | `public_key_type` | Agent key; required when granting, ignored on revoke |
18+
| `operations` | `flat_set<string>` | Wire names of operations the key may sign (`transfer`, `pm_place_bet`, …) |
19+
| `expiration` | `time_point_sec` | `1970-01-01T00:00:00` = perpetual; a past time revokes |
20+
| `addons` | `flat_set<string>` | Off-chain scopes for external services (e.g. `vizhub`); at most 10, each shorter than 64 bytes, no `,`. The node stores them but never interprets them: they grant nothing on chain |
21+
| `extensions` | `extensions_type` | Always `[]` |
22+
23+
Grant (bot may bet and transfer, vizhub accepts its key):
24+
25+
```json
26+
["set_agent_permission", {
27+
"account": "alice",
28+
"agent_name": "trade-bot",
29+
"agent_key": "VIZ6MyX5QiXAXRZk7SYCiqpi6Mtm8UbHWDFSV8HPpt7FJyahCnc2T",
30+
"operations": ["pm_place_bet", "transfer"],
31+
"expiration": "2027-01-01T00:00:00",
32+
"addons": ["vizhub"],
33+
"extensions": []
34+
}]
35+
```
36+
37+
Addon-only agent (a key for an external service, no chain operations):
38+
39+
```json
40+
["set_agent_permission", {
41+
"account": "alice",
42+
"agent_name": "hub-login",
43+
"agent_key": "VIZ7…",
44+
"operations": [],
45+
"expiration": "1970-01-01T00:00:00",
46+
"addons": ["vizhub"],
47+
"extensions": []
48+
}]
49+
```
50+
51+
Revoke — both lists empty (the key may be the null key `VIZ1111111111111111111111111111111114T1Anm`):
52+
53+
```json
54+
["set_agent_permission", {
55+
"account": "alice", "agent_name": "trade-bot",
56+
"agent_key": "VIZ1111111111111111111111111111111114T1Anm",
57+
"operations": [], "expiration": "1970-01-01T00:00:00", "addons": [], "extensions": []
58+
}]
59+
```
60+
61+
Re-issuing by the same name replaces the key, operations, addons and expiration (key rotation = re-issue).
62+
63+
## Rules
64+
65+
- **Never delegable:** `set_agent_permission`, `proposal_create`, `proposal_update`, `proposal_delete`, `account_update`, `recover_account`, `change_recovery_account`, `set_account_price`, `set_subaccount_price`, `target_account_sale`. Virtual operations and deprecated aliases (use `validator_update`, not `witness_update`) are rejected.
66+
- **One key, one agent:** a key already bound to another agent name of the same principal is rejected.
67+
- **At most 16 agents** per principal. A grant first removes the principal's expired agents.
68+
- **When an agent signature counts:** the transaction needs no master or regular authority, the principal's own keys do not already sign it, the agent is live (not expired, operation list non-empty), its list covers **every** operation of the transaction that needs a signature, and its key is among the signatures. No reach through nested `account_auths`.
69+
- **Wipes:** all agents of the principal are removed on master change, active change, account recovery, direct sale and auction close. A regular-only change keeps them.
70+
71+
## Reading agents
72+
73+
`database_api.get_agent_permissions(account)` — see [database_api](../../plugins/database-api.md#get-agent-permissions-account).

‎libraries/chain/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ add_library(graphene_chain ${VIZ_LIBRARY_TYPE}
6363
pm/parimutuel.cpp
6464
pm/leverage.cpp
6565
pm_evaluator.cpp
66+
agent_evaluator.cpp
6667
pm_process_markets.cpp
6768

6869
include/graphene/chain/pm/lmsr_q96.hpp

0 commit comments

Comments
 (0)