accounts
accounts copied to clipboard
PublicKeys Are Not Tied To AccountInfo
My state defines the participants via PublicKey.
data class MyState(
val id: String,
val partyA: PublicKey,
val partyB: PublicKey,
val status: Status,
override val linearId: UniqueIdentifier = UniqueIdentifier()
) : LinearState {
override val participants: List<AbstractParty> get() = listOf(partyA, partyB).map { AnonymousParty(it) }
The contract checks that they aren't the same identity:
val outputState = tx.outputsOfType<MyState>().single()
"PartyA and PartyB cannot be the same identity." using (outputState.partyA != outputState.partyB)
I get the key during the flow with:
val partyAKey = subFlow(RequestKeyForAccount(partyAAccountInfo.state.data)).owningKey
val partyBKey = subFlow(RequestKeyForAccount(partyBAccountInfo.state.data)).owningKey
If I pass the same account info to the flow for PartyA and PartyB you would expect that partyAKey
would be the same as partyBKey
and the contract would pick up the issue.
However, what happens is that a fresh key is generated every single time meaning that different keys are created for the same account and the contract can't tell if they are the same.
The RequestKeyForAccount
flow does:
// The account is hosted on the initiating node. So we can generate a key and register it with the identity
// service locally.
return if (hostSession.counterparty == ourIdentity) {
createKeyForAccount(accountInfo, serviceHub)
Which then goes to the confidential identity utils which generates the fresh key every single time:
@CordaInternal
fun createKeyForAccount(accountInfo: AccountInfo, serviceHub: ServiceHub) : AnonymousParty {
val newKey = serviceHub.keyManagementService.freshKey(accountInfo.identifier.id)
registerKeyToParty(newKey, serviceHub.ourIdentity, serviceHub)
return AnonymousParty(newKey)
}
The key should be cached and tied to the account.
This may be added in the future. But for now, this is left to the user to implement.
If you wish to do this, you should use a hibernate entity to store this data off ledger.
This is by design for the time being. Cheers
Can you explain a use case where the current design works and linking a single public key to an account does not work?
Yes, imagine that account ABC has been deactivated by the hosting node, and you do not contact them, you run the risk of moving states to a key that is no longer valid.
Or the situation where a private key has been deleted or lost.
On Wed, 18 Sep 2019, 16:09 opticyclic, [email protected] wrote:
Can you explain a use case where the current design works and linking a single public key to an account does not work?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/corda/accounts/issues/50?email_source=notifications&email_token=AAVWIPRNXYO63CS4D4H6EKLQKJAEPA5CNFSM4IXYJSO2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD7AM4QY#issuecomment-532729411, or mute the thread https://github.com/notifications/unsubscribe-auth/AAVWIPVZAC5CUWGFCAQOIDLQKJAEPANCNFSM4IXYJSOQ .
The code above says // The account is hosted on the initiating node.
so you don't run that risk.
In the other logic branch in that function (when the account is on another node) don't you request the key anyway? Then in your flow don't you need to send the transaction to the other node that is hosting the account to sign?
So I can't see how you run the risk of moving states to a key that is invalid since the hosting node is always involved so will know if the key is invalid.
I don't really see how the private key be deleted or lost either. Isn't it stored in the database? Are you talking about database corruption? In that case, wouldn't you just mark that key as invalid and generate a new one?
Assuming you still disagree with my point, how do you propose checking that the accounts involved are not the same in the contract if we can't rely on comparing the public key?
I believe the OP's use-case is actually a common requirement - i also landed here looking for a similar pattern, i.e. one with the ability to apply (in)equality checks on identities of ContractState.participants
within Contract.verify
.
I also realise this can only be an application-level concern for the time being and considering the extra plumbing required, but couldn't this repo document the steps or possible approach needed to attach the necessary information in a state and let the community find reusable implementation patterns for it?
What is the pattern then if you want to make the state implement QueryableState
and then query on one of the accounts?
If you only have the name of the account you will always get a different key back and it wont be queryable.