- Witness Key: Only allows update signing key and publish price feed
- Trading Key: Only allows limit orders (arguments restricted to desired markets), update margin position and transfers (arguments restricted to certain accounts)
- Proposal Update Key: Approve proposals (2FA comes to mind)
This BSIP will be split into two parts that will be voted on serparately (see Milestones section). All of the above keys are possible with Milestone 1. Milestone 2 allows statefull restrictions (e.g. allow market orders up to some amount for every month), Milestone 3 gives finer control of how to combine restrictions. Milestone 2 and 3 will be put up for voting if Milestone 1 proves successful.
Custom active permission is a list of `custom active authorities`. A `custom active authority` contains an `operation_id`, an `authority` (just like with active permission) and `restrictions` than can be used to restrict arguments and is only valid a certain time period (`valid_from` and `valid_to`). When handling incoming signed transactions, the backend checks for each operation if there is a `custom active authority` for any of its required accounts. Check for every required account of the transaction if all its belonging operations have at least one positively matched `custom active authority` (match means its `authority` is granted through present signatures, same `operation_id`, now is within `valid_to` and `valid_from` and none of the `restrictions` is violated), and if so grant the active authority of the corresponding account.
All descriptions in this section are on a pseudo/prosa level and no recommendation how it can best be implemented or serialized. They are meant to facilitate the understanding. If anything in the looping process or order of evaluation is unsuitable for actual implementation, changes can be made accordingly as long the same functionality is achieved.
Note: This assumes `custom_active_permission` is stored in a separate index. Actual implementation details left to the implementer, as long as every `custom_active_permission` can be assigned to exactly one account.
is called a restriction, that can assert itself positively (passed) or negatively (violated). All restrictions are evaluated per default with `AND` logic to determine if the whole list has asserted positively.
Statefull assert, only `int` type arguments. When the authority is created, `interval_began` is set to `valid_from` from its custom active authority and `max_cumsum` to `0`. Incoming operations are first tried to match all stateless asserts,
and if all passes continue with statefull asserts. If `now > interval_began + interval_in_sec`, then set `max_cumsum = 0` and set `interval_began = now`.
The assert that needs to pass is now `current_cumsum + incoming value <= max_cumsum`. If all `asserts` of this `custom_active_authority` pass, update `current_cumsum = current_cumsum + incoming value`.
Statefull assert, only `int` type arguments. Analogue to `limit`, but `interval_began` is initially set to `month(valid_from)` and set to `month(now)` on update, additionally the time assert is `month(now) >= interval_began + interval_in_months` (include logic for month overflow when year changes).
Stateless assert, only for dictionary type objects. The data list contains restrictions that all must pass, the reference for the `argument` of the child restriction is nested into the attributes of the parent dictionary type object. Allows nesting of `attribute_assert`.
Stateless assert, only for dictionary type objects. The data is a list of restrictions lists, i.e.
`data = [ [restriction 1, restriction 2], [restriction 3, restriction 4], ... ]`. If one of the restrictions sub-lists in data passes as whole, this restriction passes.
When a signed transaction arrives and before the backend evaluates if all necessary authorities are present through the signatures, do the following:
- iterate over required accounts and for each account, iterate over all operations within the transactions that require the active authority of this account
- iterate the `custom_active_authorities` of said account
- if a `custom_active_authority` is found that matches , remember that and stop iterating the authorities and continue until all operations are checked
- if the account has a `custom active authority` match for every operation in the transaction that requires it, then grant the `active authority` of said account. If no match is found, treat as if no authority was given
Note:
- A `custom_active_authority` can only grant the `active authority` of the corresponding account, nothing more
### Modification to the backend
* Add a new index or extend the account object to store custom active permission are assigned to an account and contain a list of custom active authorities. Multiple custom active authority entries are possible for one operation
* If the active authority of the account is updated, all custom active authorities need to be confirmed in the update. Every unconfirmed one is deleted otherwise
* Provide operations: `install_custom_active_authority`, `update_custom_active_authority`, `delete_custom_active_authority` to allow changing the custom active permission (3 operation to allow custom transaction fees and avoid having to send the complete list of all authorities for every update)
* Operation-specific authorities (if present) must be evaluated in incoming transactions
* Additional committee parameters may be needed to limit the extend of usage of this feature
Notes: The implementation must not differentiate on which operation the custom active authority is applied, all operations are treated in same fashion
### Economics
Adding a custom active authority means increased effort for the backend, and with a stateful one also the need for more storage. Proposed transaction fees:
-`install_custom_active_authority`: Tied to the duration of the custom active authority.
Normal accounts can only create custom active authoritites with a duration of maximum 1 year. LTM can do any duration and also unlimited, but the transaction fee is capped at duration of 2 years.
-`update_custom_active_authority` and `delete_custom_active_authority`: Similar to `account_update`
# Milestones
We propose do split the implmentation into two milestones. Each milestone will be voted on as a separate BSIP:
1. Implementation of basic functionaliy to allow custom active permissions and authorities, including `any`, `none` and `lt, le, gt, ge` and `attribute_assert``asserts`. If deemed necessary by developpers, reduce to only allow one key or one account for every `custom active authority`
2. Implement stateful asserts `limit` and `limit_monthly`
3. Implement `logical_or`
This approach allows as well to add other asserts at a later stage (with a new BSIP).
# Discussion
To be found in the [issue](https://github.com/bitshares/bitshares-core/issues/1061) and [pull request](https://github.com/bitshares/bsips/pull/86).
# Examples
These examples are for illustration and no specification of actual serialization.
Assume `asset_update_operation`. All attributes of its `options` must be filled on update call. This assert can not be used to realize a "may only change attribute xzy of `options`". This would require that the logic knows which of the arguments are reflected on-chain and it knows how to query it for every operation that contains `options`. If `options` are to be restricted with this assert, all values that should not change would need be fixated by defining an `any` assert for those attributes, while having e.g. a `lt` assert for the one attribute that is allowed to change.
The custom active authority should be put that transfer transaction sending funds away from A can be signed with key K as long as the receiver is B. More concrete, the authority would look like
Bad publicity in terms of security can have very negative effect on the BTS value. This BSIP allows that traders can e.g. use a trading key, witnesses can use their witness key and a faucet can use a faucet key. If then for some reason the key or witness/faucet server becomes compromised, such a key can do little harm to the account holders, minimizing the risk.
This BSIP opens up a lot of use-cases as presented in Motivation section. The intention is to not alter any existing logic of the permission system, which reduces the risk of malfunctioning.