Accounts in corda - corda

Corda as a platform, how handles whether the person wants to do transfer an asset from one account to another is the owner of the account or not?
Or some other user who have access to node can also access to any account present on node.

If you look at AccountInfo state which is the core of the accounts library; it has an attribute host, that's the node that hosts the account (the node where the account was created).
The host is the Party that signs on behalf of the account, by signing with its key.
So for instance if the host is the initiator of the flow, then they can sign on behalf of the account like this: (first you call accountKey = RequestKeyForAccount(); then getServiceHub().signInitialTransaction(txBuilder, accountKey.getOwningKey()); .
Now, in general when an initiator calls CollectSignaturesFlow so that the responding nodes sign; every node that responds will check the requested keys in the transaction and sign that transaction with all the keys that are requested and it owns.
Following the point above, if the initiator wants to collect the signatures of 10 accounts that are hosted on another node; you don't need 10 FlowSession's with the host node, you create only one FlowSession and pass it to CollectSignaturesFlow. The node (which is the host of the 10 accounts) will see in the responder flow that all 10 requested keys are owned by it, so it will sign with all 10 keys (meaning the host node signed on behalf of the 10 accounts).
If those 10 accounts were hosted on different nodes (let's say 5 accounts on PartyA and 5 account on PartyB); then you have to create 2 FlowSession's (one for PartyA which will sign on behalf of 5 accounts, and one for PartyB which will sign on behalf of the other 5).
Now back to your original question:
If you are using the Tokens SDK:
If you are using the ready flows (e.g. MoveFungibleTokens()); then only the node that hosts the "from-account" can initiate the flow. This way the node that hosts the account signs the move transaction; which requires (by contract) the signature of the current holder (i.e "from-account"), and since the node that initiated the flow hosts that account, it can sign on behalf of it. The ready move flow (MoveFungibleToken()) doesn't have a CollectSignaturesFlow() call inside of it, meaning you cannot start that flow to move tokens that belong to an account that's not hosted on the initiating node, because that flow doesn't collect signatures of other nodes, so it cannot collect the signature of the "from-account" (i.e. the current holder of the tokens) because it's hosted on a different node.
So the only way to use a flow to move accounts of a "from-account" that's not hosted on the initiating node, is by creating a flow yourself which will use the utility functions of the Tokens SDK (e.g. addMoveFungibleTokens()) and then take care of collecting the signature of the "from-account" using CollectSignaturesFlow where the host signs the transaction in the responding flow.
If you're not using the Tokens SDK, then like in the last point above; you have to create a transaction manually and make sure that you collect the signature of the "from-account" by calling the CollectSignaturesFlow where the host of the account signs on its behalf in the responder flow.

Related

Using the Corda account-based model, can I ascertain whether a transaction signer matches an account persisted on the state?

I am experimenting with Hash Time-Lock Contracts in Corda, using the Corda account-based model. It seems to me that, to transact with an account, you must always obtain an Anonymous Party to serve as its public key, via subflow RequestKeyForAccount. And it seems that you will always obtain a different key each time you RequestKeyForAccount, even for the same account.
Assuming the above statements are correct, I am finding it impossible to implement the contract, as the contract must be able to identify whether the public key invoking it belongs to the "locker" or the "lockee" party. The Anonymous Party will always be different, and will never match either the "locker" or the "lockee," because it will be different every time I invoke RequestKeyForAccount.
I have also tried tackling the problem in a different way, by storing "locker" account and "lockee" account in my persisted state - but, the contract does not have access to the account that is invoking it. It has access to the signers - which are AbstractParties. The account invoking the transaction does not seem obtainable.
Bottom line, I cannot implement a contract that tries to ascertain whether the account invoking it matches a particular account stored within the associated state, due to the random anonymized values returned by RequestKeyForAccount; and due to the inaccessibility of account when all I can access are the signers of the transaction, i.e. AbstractParties. I'd appreciate if somebody can tell me if I am off-base in any of my statements.
Always remember that Accounts in Corda are only logical entities. They do not sign transactions and they do not invoke flows in the cordapp. It's their hosting node that does it on behalf of the accounts they own.
So, as also stated in training.corda.net, if you want to restrict access to certain states to a particular account, you have to manage it outside of Corda (for example, create a RPC user that is linked to an account at application level, with the needed restrictions):
Data access restrictions, i.e. restricting users (i.e. Corda accounts) to interact only with states that they own, is the CorDapp developer's responsibility as implementing them is outside of Corda’s scope.

Does Corda node support the concept of an organization and users in the organization?

Does Corda node support the concept of an organization and users in the organization? The ORG user must have visibility to transactions of the node. And is it possible to add users within this Organization who can be part of selected transactions?
Yes, you can do it with Corda. I see two ways:
Use the Account library. Accounts are "logical" entities, i.e. subset of the node's vault. An ORG can be the Corda node and the users can be accounts owned by the node, which has complete visibility of the transactions. You can add as many accounts as you want. Note that an account only has public keys, the private keys are owned by the Corda node owner of the accounts. The flows are effectively ran by the Corda node, not by the Account themselves who are just effectively states that only have a name and a set of public keys (but not a X.509 identity, so they are not registered to the network. Only the Corda node is). A typical use case of this is a Group Company X (i.e the Corda node) who owns some Subsidiary Companies (its accounts). More info: https://training.corda.net/libraries/accounts-lib/ and https://github.com/corda/accounts/blob/master/docs.md
Use the Business Network Membership: https://docs.corda.net/docs/corda-os/4.8/business-network-membership.html. In this case you have different Corda nodes connected to the same network, and a subset of these node share a "logical" network, which is made at application level in which you can set the roles and memberships. In pratice, this is a cordapp shared between them where there are states that identify an organization and its rules.
These two above are ways to effectively create "organizations". In Corda then you also have the Observer parties, who are parties that just want to be notified of some transactions without effectively be part of them.

How the UUID of a corda account is unique across the network?

How the uniqueness of a corda accounts is maintained across the network. As far as I know a corda account has the following features
* name (Unique inside the Node)
* UUID (Unique across the network)
* Host (which hosts the account)
So from above 3 how will a Node ensures that there is no accounts with same UUID in a network? or how a Node generates a UUID when a new request to create an account comes? is there a place in network map to hold the account info?
You can safely assume that the account uuid will be unique across the network as uuid's provide 128 bits of entropy, and because of this its highly unlikely that someone else will have the same uuid within the network.
A new account can be created using inbuilt CreateAccount flow. The node generates and assigns a uuid to this account using UUID.randomUUID().
Account discovery is different than node discovery which uses a network map. Once the account is created it is expected by the node either to share this account info with the counterparty using inbuilt flow ShareAccountInfo or alternatively the counterparty can request account info using inbuilt flow RequestAccountInfoFlow.
Hope that helps.

Can an Anonymous User Access the Blockchain?

Do you have to be a known party on the network to make a transaction?
Can an anonymous user off the network interact with the blockchain?
When joining the network, a node needs to obtain a network certificate provided by the network's doorman. This certificate ties the node to a specific real-world identity. When messaging other nodes, a node must use this certificate to allow the receiving nodes to verify who they are transacting with.
However, suppose a node is working with other nodes to build a transaction. Although the node must reveal its identity to the other nodes they are building the transaction with, it can choose to identify itself in the transaction being built using an anonymous one-time public key, rather than a real-world identity.
This means that the node's identity is not stored on the ledger for all to see, and is only known to the nodes with whom the transaction was originally built.
You can also imagine scenarios where even though the node's identity is well-known, the identity of the actual user is not. For example, a node representing an auction house may place a bid on the behalf of an anonymous user.

Understanding How to Store Web Push Endpoints

I'm trying to get started implementing Web Push in one of my apps. In the examples I have found, the client's endpoint URL is generally stored in memory with a comment saying something like:
In production you would store this in your database...
Since only registered users of my app can/will get push notifications, my plan was to store the endpoint URL in the user's meta data in my database. So far, so good.
The problem comes when I want to allow the same user to receive notifications on multiple devices. In theory, I will just add a new endpoint to the database for each device the user subscribes with. However, in testing I have noticed that endpoints change with each subscription/unsubscription on the same device. So, if a user subscribes/unsubscribes several times in a row on the same device, I wind up with several endpoints saved for that user (all but one of which are bad).
From what I have read, there is no reliable way to be notified when a user unsubscribes or an endpoint is otherwise invalidated. So, how can I tell if I should remove an old endpoint before adding a new one?
What's to stop a user from effectively mounting a denial of service attack by filling my db with endpoints through repeated subscription/unsubscription?
That's more meant as a joke (I can obvioulsy limit the total endpoints for a given user), but the problem I see is that when it comes time to send a notification, I will blast notification services with hundreds of notifications for invalid endpoints.
I want the subscribe logic on my server to be:
Check if we already have an endpoint saved for this user/device combo
If not add it, if yes, update it
The problem is that I can't figure out how to reliably do #1.
I will just add a new endpoint to the database for each device the user subscribes with
The best approach is to have a table like this:
endpoint | user_id
add an unique constraint (or a primary key) on the endpoint: you don't want to associate the same browser to multiple users, because it's a mess (if an endpoint is already present but it has a different user_id, just update the user_id associated to it)
user_id is a foreign key that points to your users table
if a user subscribes/unsubscribes several times in a row on the same device, I wind up with several endpoints saved for that user (all but one of which are bad).
Yes, unfortunately the push API has a wild unsubscription mechanism and you have to deal with it.
The endpoints can expire or can be invalid (or even malicious, like android.chromlum.info). You need to detect failures (using the HTTP status code, timeouts, etc.) when you try to send the push message from your application server. Then, for some kind of failures (permanent failures, like expiration) you need to delete the endpoint.
What's to stop a user from effectively mounting a denial of service attack by filling my db with endpoints through repeated subscription/unsubscription?
As I described above, you need to properly delete the invalid endpoints, once you realize that they are expired or invalid. Basically they will produce at most one invalid request. Moreover, if you have high throughput, it takes only a few seconds for your server to make requests for thousands of endpoints.
My suggestions are based on a lot of experiments and thinking done when I was developing Pushpad.
Another way is to have a keep alive field on you server and have your service worker update it whenever it receives a push notification. Then regularly purge endpoints which haven't been responded to recently.

Resources