more details on attribute_assert and where permission is stored

bsip53
Stefan Schießl 2018-07-30 08:34:41 +02:00 committed by GitHub
parent d5e6f75ae9
commit 15a0514894
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 32 additions and 21 deletions

View File

@ -49,7 +49,10 @@ All descriptions in this section are on a pseudo/prosa level and no recommendati
A `custom_active_permission` looks like follows (in JSON-like/pseudo for clarification):
```
custom_active_permission = list of custom_active_authority items
custom_active_permission = {
account_id, // account that is assigned to this permission
authorities = list of custom_active_authority items
}
custom_active_authority = {
valid_from, // timestamp when this is active, defaults to now
valid_to, // timestamp when this is invalid, defaults to 1 year
@ -58,9 +61,7 @@ custom_active_authority = {
asserts // see below
}
```
Note: This assumes `custom_active_permission` is stored within `account_object`. Actual implementation details left to the implementer, as long as every `custom_active_permission` can be assigned to exactly one account.
#### Wording
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.
A `custom active permission` contains a list of `custom active authority`. `Custom active authority` can match an operation of an incoming, signed transaction. The wording *matching* refers to:
- `operationid` is equal to the id of the incoming operation
@ -71,10 +72,12 @@ A `custom active permission` contains a list of `custom active authority`. `Cust
### Asserts
The `asserts` is a list of `assert_objects` that are all together evaluated with `and` logic to evaluate a match
The `asserts` field is a list of restrictions consisting of argument to assert mappings.
An tuple of `(argument_identifier, assert_object[, logical_link])` is called a restriction on an argument.
All asserts within one restriction are evaluated per default with `and` logic, `or` logic can be put by specifying the `logical_link`. The `asserts` field is specified as follows:
```
asserts = list of (argument_identifier, assert_object) tuples
argument_identifier = // target unknown, can be argument of operation, or in a nested dictionary like struct
asserts = list of (argument_identifier, [list of assert_object], logical_link) tuples
argument_identifier = // target variable, can be argument of operation, or attribute in case of nesting
assert_object = {
function, // functionid to do the assert
data, // stores data specific to the chosen function
@ -90,11 +93,18 @@ List of possible asserts are:
| `lt, le, gt, ge` | `comparative` | stateless |
| `limit` | [`max_cumsum`, `interval_in_sec`] | [`current_cumsum`, `interval_began`] |
| `limit_monthly` | [`max_cumsum`, `interval_in_months`] | [`current_cumsum`, `interval_began`] |
| `attribute_assert` | `attribute_to_assert` = [(`attribute_identifier`, `any assert_objects`)] | stateless |
| `attribute_assert` | `attribute_to_assert` = [list of restrictions] | stateless |
There is no implicit type conversion when attempting to assert, incompatible type means assert failure. If required, a field can be added that stores the assumed type of the argument (if conversion fails, assert fails). If an argument has no asset, it is unrestricted and may be given (or not for optional arguments) with any value.
Following cases must hold for a restriction:
- if there is no value given (e.g. an optional argument, or nested value not given), the assert passes (no change, no violation)
- if the expected type of the argument does not match the given type (no implicit type conversion), assert fails
- if the assert fails, the restriction fails
In the following we list possible `asserts`. Mentioning `argument value` refers to the value of the argument of the operation specified `argument` in `assert_object`. The logic does not differentiate if an `argument` is optional or mandatory. All asserts imply: If the `argument` is given, it must pass the `assert`. If the `argument` is not given, assert is implicitly passed.
Note:
- If required a field can be added that stores the assumed type of the argument
- If arguments are given by the operation that have no restriction they can have any value
In the following we list possible `assert_objects`. Mentioning `argument value` refers to the value of the argument of the operation specified by `argument_identifier` of a restriction. . All asserts imply: If the `argument` is given, it must pass the `assert`. If the `argument` is not given, assert is implicitly passed.
#### `any`
Stateless assert, all argument types. `Argument value` must be equal to one of values in the data list
@ -123,10 +133,10 @@ The assert that needs to pass is now `current_cumsum + incoming value <= max_cum
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).
#### `attribute_assert`
Stateless assert, only for dictionary type objects. The `attribute_to_assert` list contains mappings between attributes and asserts that they must fulfill, if present in the dictionary. Allows nesting of `attribute_assert`.
Stateless assert, only for dictionary type objects. The `attribute_to_assert` list contains restrictions that all must assert positively. Allows nesting of `attribute_assert`.
Note:
- 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 a `any` assert for those attributes, while having e.g. a `lt` assert for the one attribute that is allowed to change.
#### Example: Nested arguments like `options`
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.
#### Example: Simple transfer
Assume account A and B and some unrelated key K. Furthermore A has a custom active authority in the following way:
@ -152,12 +162,6 @@ That has the consquence now that a transfer transaction sending funds away from
Note: This is just an illustration of a possible serialization, not a specification of the serialized format.
### Economics
Adding a custom active authority means increased effort for the backend, and with a stateful one also the need for more storage.
We propose that the transaction fee for the creation is tied to the duration of the custom active authority.
Furthermore, 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.
### Outline of handling incoming transactions
When a signed transaction arrives and before the backend evaluates if all necessary authorities are present through the signatures, do the following:
@ -185,14 +189,21 @@ Since the required accounts is Account A, and the given accounts is also Account
the transaction is executed.
### Modification to the backend
* Extend the account object to store custom active permission that includes a list of custom active authorities. Multiple custom active authority entries are possible for one operation
* 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
* Extend `account_update` or create a new operation to allow changing the custom active permission
* 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: