4. Capability Tutorial

[Previous << 3. Resource Contract Tutorial](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)
[Next >> 5.1 Non-Fungible Token Tutorial Part 1](https://qiita.com/flowcadence/items/ee22ed2ce344620c79da)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#cadenceの言語仕様を学ぶ

<h1 id="Overview">Overview</h1>

:::note warn
💡 TIP
このチュートリアルのスターターコードを Flow Playground で開きます。これは、前回のチュートリアルと同じコードです。
https://play.flow.com/47d92bae-5234-463c-ae14-3dbd452a004f
チュートリアルでは、このコードとやり取りするために、さまざまな操作を行うよう求められます。
:::
:::note
ACTION
アクションが必要な指示は、常にこのような吹き出しボックス内に記載されます。 ハイライトされたアクションは、コードを実行するために必要なすべてですが、言語の設計を理解するためには、残りの部分も読むことが必要です。
:::
このチュートリアルは、[前回の`Resource`チュートリアル](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)を前提としています。 このチュートリアルを始める前に、アカウント、トランザクション、リソース、および署名者(signer)がベーシックフィールドタイプとどのように連携するかを理解しておく必要があります。 このチュートリアルでは、アカウントとリソースの理解を前提としています。

[Capability](https://qiita.com/flowcadence/items/85e1aaf7e41d1134fa6c)と[Entitlement](https://qiita.com/flowcadence/items/572df270135946f5290e#entitlements)を使用してリソースとやり取りする方法を学習します。

Cadenceでは、リソースは構造体やクラスと同様に複合型(composite type)ですが、いくつかの特別なルールがあります。
* リソースの各インスタンスは、厳密に1つの場所にのみ存在でき、コピーすることはできません。
* リソースは、アクセス時に明示的に1つの場所から別の場所に移動する必要があります。
* また、リソースは関数実行の終了時にスコープ外に出ることはできず、明示的にどこかに保存するか、破棄する必要があります。

<h1 id="Use-Cases for Capabilities and Entitlements">Use-Cases for Capabilities and Entitlements</h1>

現実的な状況(real-world context)でリソースへのアクセスを拡大するために、機能(Capability)と権限(Entitlement)を使用したい理由を見てみましょう。

実際のユーザーのアカウントや保存されたオブジェクトには、さまざまなレベルのアクセス範囲やプライバシーが必要な関数やフィールドが含まれます。例えば、ユーザー間でトークンを交換できるアプリを開発しているとします。トークンをアカウントから引き出す(withdraw)機能は、トークンの所有者のみがアクセスできるようにしたいと考えるでしょう。しかし、アプリでは誰でもトークンを預けられる(deposit)ようにすべきです。

機能(Capability)と権限(Entitlement)は、所有資産へのアクセスを詳細に制御することを可能にします。 これによって、ユーザーは、アカウントや所有物の機能のうち、どの機能に自分自身、信頼する友人、一般ユーザーがアクセスできるかを指定することができます。

たとえば、ユーザーは自分の友人に、自分のお金を使って何かを購入してもらいたいと考えるかもしれません。この場合、その友人にアカウントのその部分のみへのアクセス権を与える権限を付与することができます。

別の例としては、ユーザーが取引アプリを初めて認証する際に、ユーザーのアカウントの取引機能にアプリがアクセスできるようにするCapabilityオブジェクトをユーザーに要求し、アプリが毎回ユーザーに署名を求める必要がないようにすることができます。

このチュートリアルでは、以下のことを行います。
1. トランザクションを使用して作成したリソースとやり取りする
2. リソースのアクセス範囲を拡張するCapabilityを作成する
3. Capabilityを通じてリソースとやり取りするスクリプトを実行する

<h1 id="Accessing-Resources-with-Capabilities">Accessing Resources with Capabilities</h1>

このチュートリアルを開始する前に、`HelloWorld`スマートコントラクトがアカウント`0x06`にデプロイされている必要があります。これは、[一つ前のリソーススマートコントラクトチュートリアル](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)と同様です。

:::note
ACTION
`HelloWorldResource.cdc`という名前のファイルがあるアカウント`0x06`タブを開きます。`HelloWorldResource.cdc`には以下のコードが含まれているはずです。
:::
```ruby:HelloWorldResource-2.cdc
access(all) contract HelloWorld {

    /* Declare a resource that only includes one function. */
    access(all) resource HelloAsset {

        /* A transaction can call this function to get the "Hello, World!"
           message from the resource. */
        access(all) fun hello(): String {
            return "Hello, World!"
        }
    }

    /* We're going to use the built-in create function to create a new instance
       of the HelloAsset resource */
    access(all) fun createHelloAsset(): @HelloAsset {
        return <-create HelloAsset()
    }
}
```

:::note 
ACTION
このコードをアカウント`0x06`にデプロイするには、`Deploy`ボタンを使用します。
:::
:::note 
ACTION
`Create Hello`トランザクションをクリックし、署名者(signer)として`0x06`を指定して送信します。
:::
上記のスマートコントラクトとトランザクションは、このチュートリアルで使用するリソースの作成・保存を行います。スマートコントラクトとトランザクションの詳細については、[前回のチュートリアル](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)を参照してください。
<h1 id="Creating-Capabilities-and-References-to-Stored-Resources">Creating Capabilities and References to Stored Resources</h1>

ストレージにアクセスするには、アカウントの所有者の明示的な許可が必要になります。機能(Capability)により、アカウントの所有者は、アカウントに保存されているオブジェクトの特定のフィールドや関数へのアクセスを許可することができます。（詳細は以下で説明します）

次のトランザクションでは、`issue`関数を使用して新しい機能(Capability)を作成します。これにより、`HelloAsset`リソースオブジェクト(リソースインスタンス)へのリンクが作成されます。次に、このリンクをアカウントのパブリックスペースに公開し、他のユーザーがアクセスできるようにします。

次に、誰でもそのリンクを使用して、そのオブジェクトの参照([Reference](https://qiita.com/flowcadence/items/115d12a5deafc732636d))を借りて`hello()`関数を呼び出すことができることを試します。このトランザクションで何が起こっているのかの詳細な説明は、トランザクションコードの下にあります。もし分からなくなったら、読み進めてください。

:::note 
ACTION
`Create Link`（リンクの作成）という名前のトランザクションを開きます。
`Create Link`には以下のコードが含まれています。
:::
```ruby:create_link.cdc
import HelloWorld from 0x06

/* This transaction issues a new capability for the HelloAsset resource
   in storage and publishes it

   Other accounts and scripts can use this public capability
   to create a reference to the private object to be able to
   access its fields and call its methods. */

transaction {
  /* We use `auth(IssueStorageCapabilityController, PublishCapability) &Account` to 
     ensure that the only thing that this transaction is allowed to do with the signer's account
     is issue and publish capabilities */
  prepare(account: auth(IssueStorageCapabilityController, PublishCapability) &Account) {

    /* Create a capability by linking the capability to
       an object in account storage at the specified path
       The capability allows access to the object of the type specified
       without needing to actually possess the object */
    let capability = account.capabilities.storage.issue<&HelloWorld.HelloAsset>(/storage/HelloAssetTutorial)

    /* Publish the capability so it is accessible to all */
    account.capabilities.publish(capability, at: /public/HelloAssetTutorial)

    /* Use the capability's borrow method to create a new reference
       to the object that the capability links to
       We use optional chaining "??" to get the value because
       result of the borrow could fail, so it is an optional.
       If the optional is nil,
       the panic will happen with a descriptive error message */
    let helloReference = capability.borrow()
      ?? panic("Could not borrow a reference to the HelloAsset capability. This could be"
                .concat("because the resource is not stored or the capability wasn't published.")
                .concat("Run the Create Hello transaction again to store the resource"))

    /* Call the hello function using the reference
       to the HelloAsset resource. */
    log(helloReference.hello())
  }
}
```
:::note 
ACTION
アカウント`0x06`がトランザクション署名者として選択されたままになっていることを確認します。
`Send`ボタンをクリックしてトランザクションを送信(実行)します。
:::
このトランザクションでは、prepareフェーズで以下を行います。
1. アカウントのパス`/storage/HelloAssetTutorial`に保存されているオブジェクト`HelloWorld.HelloAsset`に対する機能群(Capability)を`account.capabilities.storage.issue`メソッドを使用して作成します。
2. アカウントパス`/public/HelloAssetTutorial`にCapabilityを保存します。
3. `borrow`メソッドを使用して、リンクしたオブジェクトへの参照(`helloReference`と呼ぶ)を作成します。
4. 作成した参照、`helloReference`を使用して、`hello()`関数を呼び出します。

コンソールに再び「`Hello, World`」と表示されるはずです。`HelloAsset`オブジェクトのメソッドを呼び出せることに混乱されるかもしれません。実際にストレージから読み込んで制御する必要がないのに呼び出せるのです！本当ならこれは、アカウントの`/storage/`ドメインに保存されており、プライベートであるべきです。

これは、`HelloAsset` オブジェクトの [Capability](https://qiita.com/flowcadence/items/85e1aaf7e41d1134fa6c)を作成したためです。Capabilityは、他の言語におけるポインタのようなものですが、よりきめ細かい制御が可能です。
<h1 id="Capability-Based-Access-Control">Capability Based Access Control</h1>

[Capability](https://qiita.com/flowcadence/items/b70151356f4e548f2c91)により、オブジェクトの所有者は、プライベートなオブジェクトのどの機能が他のユーザーに公開されるかを指定することができます。この概念に馴染みのある方であれば、アカウントのAPIのようなものと考えてください。

アカウントの所有者は、収集品やお金のように、プライベートなオブジェクトをストレージに保管していますが、それでも、アカウント内の収集品を他のユーザーにも見られるようにしたい場合や、特定の資産の預金機能に誰でもアクセスできるようにしたい場合もあるでしょう。これらのオブジェクトはデフォルトでプライベートストレージに保管されるため、所有者は、完全なコントロールを維持しながら、これらのアクセスを開放するために何らかの措置を講じる必要があります。この目的のために、私たちは機能群(Capability)を作成します。

例えば、`HelloAsset`のオーナーは、他のユーザーに`hello`メソッドを呼び出せるようにしたいと考えるかもしれません。これが、機能（capability）の目的です。機能群(Capability)は、リンクが作成された際に指定された型を持つ、アカウントのストレージ内のオブジェクトへのリンクを表します。

この機能(Capability)を持つ他のユーザーは、この機能(Capability)がリンクされているオブジェクトを移動または削除できないことに注意してください。 彼らは、オーナーが`issue`メソッドの型指定および権限レベルで明示的に宣言したフィールドのみにアクセスできます（後述）。

Capability自体には意味のある機能はありませんが、すべての権限(Capability)には借`borrow`メソッドがあり、これは機能群(Capability)がリンクされているオブジェクトへの参照を作成します。この参照は、参照の所有者が実際のオブジェクトを持っているかのように、参照先のオブジェクトのフィールドの読み取りやメソッドの呼び出しに使用されます。

これはフィールドとメソッドへのアクセスのみを許可するものであることに注意してください。元のオブジェクトの直接的なコピー、移動、または修正は許可されません。

このトランザクションで何が起こっているのかを分解してみましょう。

まず、`/storage/` 内のプライベートな`HelloAsset` オブジェクトに対するCapabilityを発行します。
```ruby
    let capability = account.capabilities.storage.issue<&HelloWorld.HelloAsset>(/storage/HelloAssetTutorial)
```
Capabilityを作成するには、`Account.capabilities.issue()` メソッドを使用して、ストレージ内のオブジェクトに新しいCapabilityを発行します。 `<>` に含まれる型は、そのCapabilityが表す参照型です。 これは、このCapabilityから参照を借用した人は誰でも、`<>` の型と権限によって指定されるフィールドとメソッドにアクセスできることを意味します 指定された型は、リンク先のオブジェクトの型のサブタイプでなければなりません。つまり、リンク先のオブジェクトにないフィールドや関数は含まれていないということです。

参照は、`&`記号で参照されます。ここでは、このCapabilityは`HelloAsset`オブジェクトを参照するので、`<&HelloWorld.HelloAsset>`を型として指定し、`HelloAsset`オブジェクトのすべてにアクセスできるようにします

`issue`関数の引数には、リンク先のストレージ内のオブジェクトへのパス(補足: つまりポインタが指す先のインスタンスの場所)を指定します。機能(Capability)が発行されると、`Account.Capabilities`内にその機能(Capability)用の[Capability コントローラ](https://qiita.com/flowcadence/items/b70151356f4e548f2c91#accountcapabilities)が作成され、機能(Capability)の作成者は機能(Capability)に対してきめ細かい制御を行うことができます。

機能(Capability)は通常、`/storage/`ドメイン内のオブジェクトにリンクされますが、`Account`オブジェクト用に作成することもできます。Account Capabilityについては、このチュートリアルでは取り上げません。

機能(Capability)を設定した後、どこかに保存するか、この場合は`account.capabilities.publish()` メソッドを使用してアカウントのパブリックセクションに保存します。呼び出し側は、保存する機能(Capability)と保存先となるパブリックパスを指定します。

機能(Capability)からオブジェクトを参照するには、機能(Capability)の`borrow` メソッドを使用します。
```ruby
let helloReference = capability.borrow()
    ?? panic("Could not borrow a reference to the hello capability")
```
このメソッドは、`issue`関数の中で`<>`で指定した型として参照を作成します。参照を借用している間、参照の借用が失敗する可能性があるため、オプショナルチェイニング([optional chaining](https://qiita.com/flowcadence/items/d15aeb14b6bbddd9e717#accessing-fields-and-functions-of-composite-types-using-optional-chaining))を使用します。参照は、対象のストレージスロットが空の場合、すでに借用されている場合、または要求された型が機能(Capability)によって許可されているものより大きい場合、`nil`になる可能性があります。呼び出し元が問題をより正確に把握できるように、わかりやすいエラーメッセージを表示してパニック(panic)を起こします。

さらに、リソースオブジェクト(インスタンス)の所有者は、保存時に作成された機能(Capability)に対して、Capability Controllerの`delete`メソッドを使用することで、自身が作成した機能(Capability)を効果的に[取り消す](https://qiita.com/flowcadence/items/b70151356f4e548f2c91#revoking-capabilities)ことができます。

さらに、ストレージ内の参照オブジェクト（リソースのインスタンス）が移動された場合、そのストレージのパスから作成された機能(Capability)は無効になります。

言語リファレンスには、機能(Capability)に関するより[詳細なドキュメント](https://qiita.com/flowcadence/items/b70151356f4e548f2c91)があります。

これで、`/public/Hello`でパブリックなCapabilityを使って参照を借用すれば、誰でも`HelloAsset`オブジェクトの`hello()`メソッドを呼び出せるようになりました!（次のセクションで説明します）

最後に、借用した参照を使って`hello()`メソッドを呼び出します。
```ruby
/* Call the hello function using the reference to the HelloAsset resource */
log(helloReference.hello())
```
トランザクション実行の終了時には、`helloReference`の値は失われますが、実際のリソースそのものではないため、失われても問題ありません。

次のセクションでは、機能(Capability)がスクリプトのアカウントへのアクセスをどのように拡張できるかを見ていきます。
<h1 id="Executing-Scripts">Executing Scripts</h1>

スクリプトは、Cadenceにおける非常にシンプルなトランザクション型であり、ブロックチェーンへの書き込みは実行できず、アカウントまたはスマートコントラクトの状態を読み取るのみです。

スクリプトを実行するには、`access(all) fun main()` と呼ばれる関数を記述します。スクリプトを実行するには、[Execute Script] ボタンをクリックします。スクリプトの結果はコンソール出力に表示されます。

:::note 
ACTION
 `Get Greeting`のファイル を開きます。
`Get Greeting` は以下のようになっているはずです。
:::
```ruby:get_greeting.cdc
import HelloWorld from 0x06

access(all) fun main(): String {

    /* Cadence code can get an account's public account object
       by using the getAccount() built-in function. */
    let helloAccount = getAccount(0x06)

    /* Borrow the public capability from the public path of the owner's account */
    let helloReference = helloAccount.capabilities
        .borrow<&HelloWorld.HelloAsset>(/public/HelloAssetTutorial)
        ?? panic("Could not borrow a reference to the HelloAsset capability")

    /* The log built-in function logs its argument to stdout. */
    return helloReference.hello()
}
```
このスクリプトの動作は以下の通り:
1. `getAccount`を使用してパブリックな`Account`参照を取得し、それを変数`helloAccount`に割り当てます。
2. `Create Link`トランザクションで得たCapabilityから`borrow`メソッドを使用して参照を借用し、それを変数`helloReference`に割り当てます。
3. `helloReference`から`hello()`関数の結果を呼び出し元に返します。
```ruby
let helloAccount = getAccount(0x06)
```
`&Account`参照(reference)は、ネットワーク上のすべてのユーザーが利用できますが、アカウントの`/public/`ドメインから読み取れる関数のみにアクセスできます。

そして、スクリプトは`Create Link`で作成された機能(Capability)を拝借(borrow)します。
```ruby
/* Borrow the public capability from the public path of the owner's account */
let helloReference = helloAccount.capabilities
    .borrow<&HelloWorld.HelloAsset>(/public/HelloAssetTutorial)
    ?? panic("Could not borrow a reference to the HelloAsset capability")
```
アカウントに保存されている機能(Capability)を利用するには、`account.capabilities.borrow()`関数を使用します。`borrow()`は、機能(Capability)の対象となるストレージオブジェクトへの参照を返します。機能(Capability)が存在しない場合や機能(Capability)の対象となるストレージパスに値が保存されていない場合、または指定された型で値を借用できない場合、`borrow` は`nil` を返します。

その後、スクリプトは参照を使用して`hello()`関数を呼び出し、結果を返します。

スクリプトを実行して、正しく動作することを確認してみましょう。

:::note 
ACTION
プレイグラウンド(Playground)の`Execute`ボタンをクリックします。
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/9cc45b40-0a13-2b4d-1ba4-131dc35e70a3.png)
このような出力結果になるはずです。
```
> Result > "Hello, World"
```
よくできました！ スクリプトは正常に実行されました。

スクリプトの本当に素晴らしい機能のひとつは、オンチェーンのものを実際に変更できないにもかかわらず、あらゆるアカウントのプライベートストレージやオブジェクトにアクセスできることです。これにより、スクリプトはチェーンの完全な状態(full state)を把握力がさらに高まり、また、実際に変更を加えることができないため、安全性も確保されます。また、オンチェーンのものはすべて公開されているため、ブロックチェーンプログラミング言語にとって、これは論理的な機能です。

スクリプトは、組み込みの`getAuthAccount()`関数を使用して、アカウントのアドレスの`&Account`参照を取得できます。
```ruby
view fun getAuthAccount<T: &Account>(_ address: Address): &T
```
呼び出し側は、アクセスしたいアカウントのどの部分に対して、どの権限(Entitlement)を必要とするかを`<>`に指定する必要があります。以下に例を示します。
```ruby
access(all) fun main(address: Address) {
    let entitledAccount = getAuthAccount<auth(BorrowValue) &Account>(address)
}
```
アカウントの詳細については、[言語リファレンス](https://qiita.com/flowcadence/items/5ddbb79fe8438850cf57)を参照してください。
<h1 id="Reviewing-Capabilities">Reviewing Capabilities</h1>

このチュートリアルでは、Cadenceのリソースの考えを広げ、機能(Capability)を使用してリソースへのアクセス範囲を拡大し、より多くの[アカウントストレージAPI](https://qiita.com/flowcadence/items/129d58ae7cb962056c6c)のユースケースをカバーしました。

リソースを含んだスマートコントラクトをデプロイし、そのリソースへのアクセスを許可する機能(Capability)を作成しました。この機能(Capability)を使用して、borrowメソッドで参照を作成し、その参照を使用してリソースの`hello()`関数を呼び出しました。最後に、スクリプトを使用して同じ機能(Capability)の借用と参照の作成を行い、スクリプトからリソースの`hello()`関数を呼び出せるようにしました。これは重要なことです。なぜなら、機能(Capability)を使用せずにスクリプトからアカウントストレージにアクセスすることはできないからです。

チュートリアルを完了したので、以下のことが出来るシンプルなCadenceプログラムを書くための基本的な知識が得られました。
* スマートコントラクトにリソースを実装する
* アカウントのリソースへのアクセスを許可する機能(Capability)を作成する
* 署名済みトランザクションとスクリプトの両方を使用してリソースとやり取りする

スマートコントラクトを自由に変更して、異なるリソースを作成したり、利用可能な[アカウントストレージAPI](https://qiita.com/flowcadence/items/129d58ae7cb962056c6c)を試したり、スマートコントラクトから異なる関数を実行する新しいトランザクションやスクリプトを記述したりすることができるようになりました。 [Capabilityベースのアクセス制御ページ](https://qiita.com/flowcadence/items/b70151356f4e548f2c91)を参照して、Capabilityでできることについてさらに詳しく確認してください。

Cadence を使用してより複雑なアプリケーションを構築する方向性は正しいので、アプリケーションが複雑化してきた今こそ、[Cadence Best Practices ドキュメント](https://qiita.com/flowcadence/items/bc0dad9850d2d6eaf7d2)と[Anti-patterns ドキュメント](https://qiita.com/flowcadence/items/80a8b5310d2b6ad383ad)を確認する絶好のタイミングです。

翻訳元

https://cadence-lang.org/docs/tutorial/capabilities

***
<b>[Previous << 3. Resource Contract Tutorial](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (4. Capability Tutorial)

<b>[Next >> 5.1 Non-Fungible Token Tutorial Part 1](https://qiita.com/flowcadence/items/ee22ed2ce344620c79da)</b>