アカウントライブラリ(Accounts library)

Cordaのアカウントとは

Corda 4.3以前では、Stateの参加者が利用できるデータタイプはAbstractParty、つまりPartyAnonymousPartyのみでした。そのため、各参加者は自分のCordaノードを実行する必要があり、高い運用コストが発生していました。

Accounts Libraryはこの問題を解決します。このライブラリは、CordaノードのVaultを、ホストされているアカウントに関連付けられた論理的なサブセットに分割する方法を提供します。アカウントは CordaX500Name を持っていませんが、ホスティングノードが所有するアカウントに関連付けられています。

デザイン

アカウントとは、単純に[AccountInfo]というタイプのStateで、以下の属性を持っています。

  • Party host :これはアカウントをホストしているノードで、PublicKeysをホストノードにマッピングするために使用されます。
  • String name :これはユーザ名に似ています。Account ライブラリは、AccountInfo.name がすべてのホストノードで一意であることを保証します。
  • UniqueIdentifier identifier: ライブラリは AccountInfo.identifier がネットワーク内で一意であることを保証します。これは128ビットのランダムなIDです。このアカウントIDは、CordaがPublicKeyをアカウントにマッピングする際に使用されます。
    Untitled.png

Corda ノードのアカウントは、同じ UUID に割り当てられた PublicKey の集まりです。この UUIDAccountInfo ステートの linearId です (上で説明しています)。これらの PublicKeysContractStates に参加するために使用することができます。ContractStateを含むトランザクションが台帳にコミットされると、そのContractState`は、そのPublicKeyを持つアカウントによって所有または参加されていると言えます。

鍵とプライバシーに関する検討事項

Cordaでアカウントを使用することを検討する際に、重要な点を説明します。

  1. *取引の署名は、アカウントではなく、Corda のノードの法的な ID で行われます。(

    アカウントをホストしているノードは、そのアカウントの公開鍵とペアとなる秘密鍵を所有しています。トランザクションは、必要に応じて、そのアカウントを所有するCordaノードによって署名されます。ネットワークレベルでは、トランザクションはホストノードのリーガルアイデンティティに解決されます。)

  2. ノードのオペレータはすべてのStateを見ることができます
  3. CorDapp内のデータへのアクセスの制限は開発者の責任であり、その実装はCordaの範囲外です。

アカウントの利用方法:代表的なワークフロー

CorDappにAccounts libraryを追加

ルートの build.gradle に以下を追加します。

buildscript {
ext {
accounts_release_group = 'com.r3.corda.lib.accounts'
accounts_release_version = '1.0'
confidential_id_release_group = "com.r3.corda.lib.ci"
confidential_id_release_version = "1.0"
}
}

dependencies {
cordapp "$confidential_id_release_group:ci-workflows:$confidential_id_release_version"
cordapp "$accounts_release_group:accounts-contracts:$accounts_release_version"
cordapp "$accounts_release_group:accounts-workflows:$accounts_release_version"
}

task deployNodes() {
nodeDefaults {
cordapp("$accounts_release_group:accounts-contracts:$accounts_release_version")
cordapp("$accounts_release_group:accounts-workflows:$accounts_release_version")
}
}

そして、contract/build.gradleworkflows/build.gradleにもこれらを追加します:

dependencies {
// in contracts build.gradle
cordaCompile "$accounts_release_group:accounts-contracts:$accounts_release_version"

// in workflows build.gradle
cordaCompile "$confidential_id_release_group:ci-workflows:$confidential_id_release_version"
cordaCompile "$accounts_release_group:accounts-workflows:$accounts_release_version"
}

新規アカウントの作成(例:AccountInfoのState)

// Create account by invoking flow via RPC.
val accountInfo: StateAndRef<AccountInfo> = rpcProxy.startFlow(::CreateAccount, "Roger's account").returnValue.getOrThrow()

// Create account by using sub flow (from inside a flow).
val accountInfo: StateAndRef<AccountInfo> = subFlow(CreateAccount("Roger's account"))

// The AccountService provides access to triggering Account related flows from within a Corda Service.
val accountInfo: StateAndRef<AccountInfo> = accountService.createAccount("Roger's account").getOrThrow()

IDまたは名前でアカウントを検索

新しいアカウントを作成したら、次の方法を使用して、 AccountServiceを使用して、名前またはアカウントIDでAccountInfoを取得できます。

fun accountInfo(id: UUID): StateAndRef<AccountInfo>?
fun accountInfo(name: String): List<StateAndRef<AccountInfo>>?

アカウントは、次のflowを使用して名前とアカウントIDで検索することもできます。:

subFlow(AccountInfoByName(id: UUID)): StateAndRef<AccountInfo>?
subFlow(AccountInfoByUUID(name: String)): List<StateAndRef<AccountInfo>>?

アカウントの公開鍵をリクエストする

アカウントにはデフォルトの公開鍵が付属していません。 したがって、アカウントと取引したり、アカウントを使用したりする前に、ホスティングノードに公開鍵を要求する必要があります。

// Requestor flow.
// Assumption is that we already have the AccountInfo.
val accountInfo: StateAndRef<AccountInfo> = accountService.accountInfo("Some account name")
val newKey: AnonymousParty = subFlow(RequestKeyForAccountFlow(accountInfo = accountInfo,
hostSession = initiateFlow(accountInfo.state.data.host)
))

// Responder flow.
subFlow(SendKeyForAccountFlow(otherSideSession))

注:RequestKeyForAccountFlowが呼び出されると、常に新しい公開鍵が生成されます

アカウントの新しい公開鍵を生成する必要は必ずしもなく、古い公開鍵は再利用できます。これは、CorDappのニーズによって異なります。 次に例を示します。

// retrieve the public keys associated with the account ID
val accountKeys = accountService.accountKeys(accountInfo.identifier.id)
return if (accountKeys.isEmpty()) {
// generate a new key if no other keys are found
subFlow(RequestKeyForAccount(accountInfo))
} else {
// return an AnonymousParty reusing an old one
AnonymousParty(accountKeys.first())
}

アカウントを別のノードと共有する

トランザクションを開始する前に、 AccountInfosを必要とするCordaノードとアカウントを共有することが重要です。 アカウントを他のノードと共有するには、次のようにします。

// party is another Corda node <Party>
subFlow(ShareAccountInfo(account, party))

アカウントIDでVaultを照会します

Vaultにクエリを実行して、指定したアカウントIDに関連付けられているStateを返すことができます。 アカウントIDが不明な場合、またはStateが見つからない場合、クエリは空のリストを返します。

rpcProxy.vaultQueryByCriteria(
QueryCriteria.VaultQueryCriteria(externalIds = listOf(accountId)), StateClass::class.java
)

serviceHub.vaultService.queryBy(
QueryCriteria.VaultQueryCriteria(externalIds = listOf(accountId)),StateClass::class.java
)

トランザクションへの署名

秘密鍵を持つ唯一のエンティティであるため、ホスティングノードのみがトランザクションに署名できます。 では、Cordaアカウントではどのように機能しますか?

// retrieve the public key of the account from its AccountInfo. 
// This returns an AnonymousParty.
val account : AnonymousParty = subFlow(RequestKeyForAccount(accountInfo))

// initially sign the transaction using the public key of the account
val partiallySignedTx : SignedTransaction = serviceHub.signInitialTransaction(txBuilder,listOf(account.owningKey))

signInitialTransactionは、アカウントの公開鍵からホスティングノードの秘密鍵を取得します。

CollectSignatureFlowを使用してリモートアカウントの署名を収集する必要がある場合は、そのホスティングノードのIDを取得してから、それとのセッションを開く必要があります。

// retrieve the identity of the hosting node of the remote account
val remoteHost : Party? = serviceHub.identityService.partyFromKey(remote-account.owningKey)

// open the session with the hosting node
val session : FlowSession = initiateFlow(remoteHost)

// call the CollectSignatureFlow using this session
subFlow(CollectSignaturesFlow(partiallySignedTx, session))

もっと詳しく知る

この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています