-
Notifications
You must be signed in to change notification settings - Fork 276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: authenticate personal accounts by ID #4411
Conversation
/// A new account should be automatically registered when being a destination of a transfer of numeric asset e.g. "rose" | ||
/// | ||
/// # Scenario | ||
/// | ||
/// 0. alice@wonderland: domain owner | ||
/// 0. alice -> new carol ... ok (domain owner) | ||
/// 0. carol -> new dave ... err (permission denied) | ||
/// 0. grant `CanRegisterAccountInDomain` permission to carol | ||
/// 0. carol -> new dave ... ok (authorized) | ||
#[test] | ||
fn asset_numeric() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test tells the main goal of this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This transfer permissions concerns me a bit.
As regular user i probably don't care if person i' trying to transfer assets is registered or not.
Can we do the following?
Transfer to any address is always allowed (what about mint and burn?), but to actually make use of this assets (e.g. transfer them to someone else) you have to register an account.
Thus by registering account you claim ownership of this assets.
Since accounts are identified by public key only owner of the private key can register the account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have a point, I will consider it. If this discussion is controversial or things get too complicated, we may split the 2nd commit into a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the point is the domain membership screening.
How should a new account apply for and be allowed to join a domain?
In terms of authority, there will be a gap between transferring one's own asset to a new account and registering a new account, especially in "private domain".
So as you pointed out, the admission process should be managed by a different authority than the sender of the first transaction that mentioned the account.
One idea is that each domain has its own admission policy as a trigger that "activates" a new account in response to the account creation event.
Admission policies may vary from domain to domain e.g.
- No screening
- Wait for approval of the domain owner
- Wait for approvals of m of n domain members
In any case, as I implied, I'm going to create a new issue on this and remove the 2nd commit from this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can preserve our current behavior and to register an account you have to be domain owner or have corresponding permission.
So anyone (with permission) can make transfer/mint/burn assets to certain pub key (even if destination not yet registered).
Then some authority need to register an account to activate it*.
After that owner of corresponding secret key can start using this account (this would be checks that account is registered and transaction signature is correct).
If owner of secret key would try to make a transfer before being regestred transfer would be rejected.
- in case of public blockchain could be owner of secret key itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to be in agreement that there will be two types of account registration, so to speak, provisional and full registration.
Is it your opinion that since the current auto-registration is full registration, it should be weaken to provisional one and the existing registration should be utilized as full registration?
If so, does provisional registration require permission?
If it cannot be executed without the same permission as full registration, then there would be no motive for them to split into two.
Or do we need dedicated permission for provisional registration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it your opinion that since the current auto-registration is full registration, it should be weaken to provisional one and the existing registration should be utilized as full registration?
Yeah, exactly
If so, does provisional registration require permission?
Imo it shouldn't require any additional permissions.
pub struct AccountId { | ||
/// [`Account`]'s [`Domain`](`crate::domain::Domain`) id. | ||
/// [`Domain`](crate::domain::Domain) that the [`Account`] belongs to. | ||
pub domain_id: DomainId, | ||
/// [`Account`]'s name. | ||
pub name: Name, | ||
/// Sole signatory of the [`Account`]. | ||
pub signatory: PublicKey, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this ID spec, the same signatory could have accounts in multiple domains, but I'm not sure if that's a good idea.
My first thought was to move account.id.domain_id
to account.domain_id
, but I decided it would not pay for the large impact on the current world and event structure. Opened #4410
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My first thought was to move
account.id.domain_id
toaccount.domain_id
if we want to disallow accounts with the same public key across different domains, this is the way to go about it. since I see Domains
as rather isolated somewhat akin to tenancy in databases. The nice advantage of moving domain_id
out of AccountId
is that it would reduce memory footprint of iroha.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core/src/smartcontracts/isi/mod.rs
Outdated
/// Validate and execute an additional instruction `T` during `Self` execution. | ||
/// FIXME This means going backwards from execution phase to validation phase, which is contrary to current design principles | ||
trait BackValidate<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a kind of compromise because it goes against the current design principle that all validations should be done prior to any execution.
On the other hand, what if during the transfer execution, the account registration executes without any validation?
In that case, transfer could be abused to bypass the validation for account registration.
For example, an attacker could spam a small amount of assets, create a large number of insignificant accounts, and take up memory space.
Account reaping may be effective in such cases, as it is for other public chains
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it is not the responsibility of iroha_core
to create destination account if it doesn't exist, it is executor's responsibility. I would move all this logic into default executor and iroha_core
should plainly reject all instructions that operate on non-existing accounts. In other words, default executor should check whether destination account exists and if not first execute Register<Account>
which will go through the regular validation process (since validation is done in executor)
If you do this you wouldn't have the problem you are describing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will also remove the need to differentiate between full and provisional account registrations as was discussed here because now executor will check whether the authority
has the permission to register new account and either make full registration or reject the transaction. No loopholes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mversic my initial concern was exactly about demanding registration permissions when i.e. making transfer.
Imo we shouldn't require such permissions on transfer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. IMO, in any case iroha_core
should reject this transfer if destination doesn't exist. It is up to the executor to create missing destination before doing the transfer. We can make the default executor not require any permissions when creating a provisional account, but it has to create it before executing the transfer
I guess accounts will then have a flag to indicate whether they are provisional or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Erigara could you be more specific why the Map<AccountId, Asset>
Map<AccountId, Assets>
etc. would achieve an equivalent of provisional accounts?
I understand all we have to do to apply e.g. transfer instruction would be modifying the map only.
I'm not sure it is relevant to the following, but
it reminded me of what I called @nodomain
approach, which represents being provisional by being under "nodomain".
Why I rejected this approach was because it seemed obviously unreasonable to replace e.g. @wonderland
with @nodomain
and remember the original @wonderland
and later modify @nodomain
to @wonderland
.
But an evil here might be non-separation of the account identification and the domain membership.
If they were separated, being under "nodomain" (and being provisional) would have been equal to account.domain_id: None
.
This approach might rather work well with the shallow objects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mversic my understanding so far is that core passes the execution of the provisional account registration to executor, who does all-or-nothing validation depending on whether it is permissioned or permissionless.
Before we go any further, I'd like to reach some agreement on whether permission ed/less is characteristic of chain or domain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you be more specific why the
Map<AccountId, Asset>
etc. would achieve an equivalent of provisional accounts?
On transfer we would update entry in Map<AccountId, Asset>
with such operation we don't need to check if destinationAccountId
is registered or not or access any fields of Account
.
So in case of when account is not registered this destination AccountId
would be kinda dangling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case we still need something indicates if the source account is active or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is no need for provisional registration we can check that source account is registered and it should be enough, shouldn't it?
Pull Request Test Coverage Report for Build 8595871540Details
💛 - Coveralls |
/// A new account should be automatically registered when being a destination of a transfer of numeric asset e.g. "rose" | ||
/// | ||
/// # Scenario | ||
/// | ||
/// 0. alice@wonderland: domain owner | ||
/// 0. alice -> new carol ... ok (domain owner) | ||
/// 0. carol -> new dave ... err (permission denied) | ||
/// 0. grant `CanRegisterAccountInDomain` permission to carol | ||
/// 0. carol -> new dave ... ok (authorized) | ||
#[test] | ||
fn asset_numeric() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This transfer permissions concerns me a bit.
As regular user i probably don't care if person i' trying to transfer assets is registered or not.
Can we do the following?
Transfer to any address is always allowed (what about mint and burn?), but to actually make use of this assets (e.g. transfer them to someone else) you have to register an account.
Thus by registering account you claim ownership of this assets.
Since accounts are identified by public key only owner of the private key can register the account.
pub struct AccountId { | ||
/// [`Account`]'s [`Domain`](`crate::domain::Domain`) id. | ||
/// [`Domain`](crate::domain::Domain) that the [`Account`] belongs to. | ||
pub domain_id: DomainId, | ||
/// [`Account`]'s name. | ||
pub name: Name, | ||
/// Sole signatory of the [`Account`]. | ||
pub signatory: PublicKey, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My first thought was to move
account.id.domain_id
toaccount.domain_id
if we want to disallow accounts with the same public key across different domains, this is the way to go about it. since I see Domains
as rather isolated somewhat akin to tenancy in databases. The nice advantage of moving domain_id
out of AccountId
is that it would reduce memory footprint of iroha.
6f39591
to
c321539
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall no objections, LGTM (except for Kagami UI).
45189ee
to
0eb152b
Compare
Going to fix this issue |
BREAKING CHANGE: - change `AccountId` from "name@domain" to "multihash@domain" - make account signatory single - make transaction signature single - remove query `FindAccountsByName` closes issue hyperledger-iroha#2085 Signed-off-by: Shunkichi Sato <[email protected]>
|
Description
[feature] #2085: Authenticate personal accounts by ID
This is a milestone for the following commit. The inclusion of the public key in the ID allows the ID to match the verifying key of the signature. This makes it possible to authenticate transactions and queries with the ID alone.
api-changes
: single signatory account, single signature transactionapi-changes
: remove queryFindAccountsByName
config-changes
: client configaccount.id
changes toaccount.domain_id
test_samples
utility for tests[feature] #2085: Auto-register destination account on transferIncludes registration of the destination account in the transfer execution. The main use case is described in testauto_register_account::on_transfer::asset_numeric
Linked issue
transaction.signature
andtransaction.payload.authority
#4410Benefits
As long as you know the address (account ID), you can send without worrying whether the destination account is already registered on the chain.
However, the current design requires the sender to be authorized to register a new account within the domain. See #4411 (comment)
Drawbacks
name@domain
notation will be temporary lostChecklist
CONTRIBUTING.md