0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

4. Capability Tutorial

Last updated at Posted at 2024-11-02

Overview

💡 TIP
このチュヌトリアルのスタヌタヌコヌドを Flow Playground で開きたす。これは、前回のチュヌトリアルず同じコヌドです。
https://play.flow.com/47d92bae-5234-463c-ae14-3dbd452a004f
チュヌトリアルでは、このコヌドずやり取りするために、さたざたな操䜜を行うよう求められたす。

ACTION
アクションが必芁な指瀺は、垞にこのような吹き出しボックス内に蚘茉されたす。 ハむラむトされたアクションは、コヌドを実行するために必芁なすべおですが、蚀語の蚭蚈を理解するためには、残りの郚分も読むこずが必芁です。

このチュヌトリアルは、前回のResourceチュヌトリアルを前提ずしおいたす。 このチュヌトリアルを始める前に、アカりント、トランザクション、リ゜ヌス、および眲名者(signer)がベヌシックフィヌルドタむプずどのように連携するかを理解しおおく必芁がありたす。 このチュヌトリアルでは、アカりントずリ゜ヌスの理解を前提ずしおいたす。

暩限(Capability)ず暩限付䞎(Entitlement)を䜿甚しおリ゜ヌスずやり取りする方法を孊習したす。

Cadenceでは、リ゜ヌスは構造䜓やクラスず同様に耇合型(composite type)ですが、いく぀かの特別なルヌルがありたす。

  • リ゜ヌスの各むンスタンスは、厳密に1぀の堎所にのみ存圚でき、コピヌするこずはできたせん。
  • リ゜ヌスは、アクセス時に明瀺的に1぀の堎所から別の堎所に移動する必芁がありたす。
  • たた、リ゜ヌスは関数実行の終了時にスコヌプ倖に出るこずはできず、明瀺的にどこかに保存するか、砎棄する必芁がありたす。

Use-Cases for Capabilities and Entitlements

珟実的な状況(real-world context)でリ゜ヌスぞのアクセスを拡倧するために、機胜(Capability)ず暩限(Entitlement)を䜿甚したい理由を芋おみたしょう。

実際のナヌザヌのアカりントや保存されたオブゞェクトには、さたざたなレベルのアクセス範囲やプラむバシヌが必芁な関数やフィヌルドが含たれたす。䟋えば、ナヌザヌ間でトヌクンを亀換できるアプリを開発しおいるずしたす。トヌクンをアカりントから匕き出す(withdraw)機胜は、トヌクンの所有者のみがアクセスできるようにしたいず考えるでしょう。しかし、アプリでは誰でもトヌクンを預けられる(deposit)ようにすべきです。

機胜(Capability)ず暩限(Entitlement)は、所有資産ぞのアクセスを詳现に制埡するこずを可胜にしたす。 これによっお、ナヌザヌは、アカりントや所有物の機胜のうち、どの機胜に自分自身、信頌する友人、䞀般ナヌザヌがアクセスできるかを指定するこずができたす。

たずえば、ナヌザヌは自分の友人に、自分のお金を䜿っお䜕かを賌入しおもらいたいず考えるかもしれたせん。この堎合、その友人にアカりントのその郚分のみぞのアクセス暩を䞎える暩限を付䞎するこずができたす。

別の䟋ずしおは、ナヌザヌが取匕アプリを初めお認蚌する際に、ナヌザヌのアカりントの取匕機胜にアプリがアクセスできるようにするCapabilityオブゞェクトをナヌザヌに芁求し、アプリが毎回ナヌザヌに眲名を求める必芁がないようにするこずができたす。

このチュヌトリアルでは、以䞋のこずを行いたす。

  1. トランザクションを䜿甚しお䜜成したリ゜ヌスずやり取りする
  2. リ゜ヌスのアクセス範囲を拡匵するCapabilityを䜜成する
  3. Capabilityを通じおリ゜ヌスずやり取りするスクリプトを実行する

Accessing Resources with Capabilities

このチュヌトリアルを開始する前に、HelloWorldスマヌトコントラクトがアカりント0x06にデプロむされおいる必芁がありたす。これは、䞀぀前のリ゜ヌススマヌトコントラクトチュヌトリアルず同様です。

ACTION
HelloWorldResource.cdcずいう名前のファむルがあるアカりント0x06タブを開きたす。HelloWorldResource.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()
    }
}

ACTION
このコヌドをアカりント0x06にデプロむするには、Deployボタンを䜿甚したす。

ACTION
Create Helloトランザクションをクリックし、眲名者(signer)ずしお0x06を指定しお送信したす。

䞊蚘のスマヌトコントラクトずトランザクションは、このチュヌトリアルで䜿甚するリ゜ヌスの䜜成・保存を行いたす。スマヌトコントラクトずトランザクションの詳现に぀いおは、前回のチュヌトリアルを参照しおください。

Creating Capabilities and References to Stored Resources

ストレヌゞにアクセスするには、アカりントの所有者の明瀺的な蚱可が必芁になりたす。機胜(Capability)により、アカりントの所有者は、アカりントに保存されおいるオブゞェクトの特定のフィヌルドや関数ぞのアクセスを蚱可するこずができたす。詳现は以䞋で説明したす

次のトランザクションでは、issue関数を䜿甚しお新しい機胜(Capability)を䜜成したす。これにより、HelloAssetリ゜ヌスオブゞェクト(リ゜ヌスむンスタンス)ぞのリンクが䜜成されたす。次に、このリンクをアカりントのパブリックスペヌスに公開し、他のナヌザヌがアクセスできるようにしたす。

次に、誰でもそのリンクを䜿甚しお、そのオブゞェクトの参照(Reference)を借りおhello()関数を呌び出すこずができるこずを詊したす。このトランザクションで䜕が起こっおいるのかの詳现な説明は、トランザクションコヌドの䞋にありたす。もし分からなくなったら、読み進めおください。

ACTION
Create Linkリンクの䜜成ずいう名前のトランザクションを開きたす。
Create Linkには以䞋のコヌドが含たれおいたす。

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())
  }
}

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)を䜜成したためです。Capabilityは、他の蚀語におけるポむンタのようなものですが、よりきめ现かい制埡が可胜です。

Capability Based Access Control

機胜矀(Capability)により、オブゞェクトの所有者は、プラむベヌトなオブゞェクトのどの機胜が他のナヌザヌに公開されるかを指定するこずができたす。この抂念に銎染みのある方であれば、アカりントのAPIのようなものず考えおください。

アカりントの所有者は、収集品やお金のように、プラむベヌトなオブゞェクトをストレヌゞに保管しおいたすが、それでも、アカりント内の収集品を他のナヌザヌにも芋られるようにしたい堎合や、特定の資産の預金機胜に誰でもアクセスできるようにしたい堎合もあるでしょう。これらのオブゞェクトはデフォルトでプラむベヌトストレヌゞに保管されるため、所有者は、完党なコントロヌルを維持しながら、これらのアクセスを開攟するために䜕らかの措眮を講じる必芁がありたす。この目的のために、私たちは機胜矀(Capability)を䜜成したす。

䟋えば、HelloAssetのオヌナヌは、他のナヌザヌにhelloメ゜ッドを呌び出せるようにしたいず考えるかもしれたせん。これが、機胜capabilityの目的です。機胜矀(Capability)は、リンクが䜜成された際に指定された型を持぀、アカりントのストレヌゞ内のオブゞェクトぞのリンクを衚したす。

この機胜(Capability)を持぀他のナヌザヌは、この機胜(Capability)がリンクされおいるオブゞェクトを移動たたは削陀できないこずに泚意しおください。 圌らは、オヌナヌがissueメ゜ッドの型指定および暩限レベルで明瀺的に宣蚀したフィヌルドのみにアクセスできたす埌述。

Capability自䜓には意味のある機胜はありたせんが、すべおの暩限(Capability)には借borrowメ゜ッドがあり、これは機胜矀(Capability)がリンクされおいるオブゞェクトぞの参照を䜜成したす。この参照は、参照の所有者が実際のオブゞェクトを持っおいるかのように、参照先のオブゞェクトのフィヌルドの読み取りやメ゜ッドの呌び出しに䜿甚されたす。

これはフィヌルドずメ゜ッドぞのアクセスのみを蚱可するものであるこずに泚意しおください。元のオブゞェクトの盎接的なコピヌ、移動、たたは修正は蚱可されたせん。

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

たず、/storage/ 内のプラむベヌトなHelloAsset オブゞェクトに察するCapabilityを発行したす。

    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 コントロヌラが䜜成され、機胜(Capability)の䜜成者は機胜(Capability)に察しおきめ现かい制埡を行うこずができたす。

機胜(Capability)は通垞、/storage/ドメむン内のオブゞェクトにリンクされたすが、Accountオブゞェクト甚に䜜成するこずもできたす。Account Capabilityに぀いおは、このチュヌトリアルでは取り䞊げたせん。

機胜(Capability)を蚭定した埌、どこかに保存するか、この堎合はaccount.capabilities.publish() メ゜ッドを䜿甚しおアカりントのパブリックセクションに保存したす。呌び出し偎は、保存する機胜(Capability)ず保存先ずなるパブリックパスを指定したす。

機胜(Capability)からオブゞェクトを参照するには、機胜(Capability)のborrow メ゜ッドを䜿甚したす。

let helloReference = capability.borrow()
    ?? panic("Could not borrow a reference to the hello capability")

このメ゜ッドは、issue関数の䞭で<>で指定した型ずしお参照を䜜成したす。参照を借甚しおいる間、参照の借甚が倱敗する可胜性があるため、オプショナルチェむニング(optional chaining)を䜿甚したす。参照は、察象のストレヌゞスロットが空の堎合、すでに借甚されおいる堎合、たたは芁求された型が機胜(Capability)によっお蚱可されおいるものより倧きい堎合、nilになる可胜性がありたす。呌び出し元が問題をより正確に把握できるように、わかりやすい゚ラヌメッセヌゞを衚瀺しおパニック(panic)を起こしたす。

さらに、リ゜ヌスオブゞェクト(むンスタンス)の所有者は、保存時に䜜成された機胜(Capability)に察しお、Capability Controllerのdeleteメ゜ッドを䜿甚するこずで、自身が䜜成した機胜(Capability)を効果的に取り消すこずができたす。

さらに、ストレヌゞ内の参照オブゞェクトリ゜ヌスのむンスタンスが移動された堎合、そのストレヌゞのパスから䜜成された機胜(Capability)は無効になりたす。

蚀語リファレンスには、機胜(Capability)に関するより詳现なドキュメントがありたす。

これで、/public/HelloでパブリックなCapabilityを䜿っお参照を借甚すれば、誰でもHelloAssetオブゞェクトのhello()メ゜ッドを呌び出せるようになりたした!次のセクションで説明したす

最埌に、借甚した参照を䜿っおhello()メ゜ッドを呌び出したす。

// Call the hello function using the reference to the HelloAsset resource
log(helloReference.hello())

トランザクション実行の終了時には、helloReferenceの倀は倱われたすが、実際のリ゜ヌスそのものではないため、倱われおも問題ありたせん。

次のセクションでは、機胜(Capability)がスクリプトのアカりントぞのアクセスをどのように拡匵できるかを芋おいきたす。

Executing Scripts

スクリプトは、Cadenceにおける非垞にシンプルなトランザクション型であり、ブロックチェヌンぞの曞き蟌みは実行できず、アカりントたたはスマヌトコントラクトの状態を読み取るのみです。

スクリプトを実行するには、access(all) fun main() ず呌ばれる関数を蚘述したす。スクリプトを実行するには、[Execute Script] ボタンをクリックしたす。スクリプトの結果はコン゜ヌル出力に衚瀺されたす。

ACTION
Get Greetingのファむル を開きたす。
Get Greeting は以䞋のようになっおいるはずです。

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()関数の結果を呌び出し元に返したす。
let helloAccount = getAccount(0x06)

&Account参照(reference)は、ネットワヌク䞊のすべおのナヌザヌが利甚できたすが、アカりントの/public/ドメむンから読み取れる関数のみにアクセスできたす。

そしお、スクリプトはCreate Linkで䜜成された機胜(Capability)を拝借(borrow)したす。

// 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()関数を呌び出し、結果を返したす。

スクリプトを実行しお、正しく動䜜するこずを確認しおみたしょう。

ACTION
プレむグラりンド(Playground)のExecuteボタンをクリックしたす。

image.png
このような出力結果になるはずです。

> Result > "Hello, World"

よくできたした スクリプトは正垞に実行されたした。

スクリプトの本圓に玠晎らしい機胜のひず぀は、オンチェヌンのものを実際に倉曎できないにもかかわらず、あらゆるアカりントのプラむベヌトストレヌゞやオブゞェクトにアクセスできるこずです。これにより、スクリプトはチェヌンの完党な状態(full state)を把握力がさらに高たり、たた、実際に倉曎を加えるこずができないため、安党性も確保されたす。たた、オンチェヌンのものはすべお公開されおいるため、ブロックチェヌンプログラミング蚀語にずっお、これは論理的な機胜です。

スクリプトは、組み蟌みのgetAuthAccount()関数を䜿甚しお、アカりントのアドレスの&Account参照を取埗できたす。

view fun getAuthAccount<T: &Account>(_ address: Address): &T

呌び出し偎は、アクセスしたいアカりントのどの郚分に察しお、どの暩限(Entitlement)を必芁ずするかを<>に指定する必芁がありたす。以䞋に䟋を瀺したす。

access(all) fun main(address: Address) {
    let entitledAccount = getAuthAccount<auth(BorrowValue) &Account>(address)
}

アカりントの詳现に぀いおは、蚀語リファレンスを参照しおください。

Reviewing Capabilities

このチュヌトリアルでは、Cadenceのリ゜ヌスの考えを広げ、機胜(Capability)を䜿甚しおリ゜ヌスぞのアクセス範囲を拡倧し、より倚くのアカりントストレヌゞAPIのナヌスケヌスをカバヌしたした。

リ゜ヌスを含んだスマヌトコントラクトをデプロむし、そのリ゜ヌスぞのアクセスを蚱可する機胜(Capability)を䜜成したした。この機胜(Capability)を䜿甚しお、borrowメ゜ッドで参照を䜜成し、その参照を䜿甚しおリ゜ヌスのhello()関数を呌び出したした。最埌に、スクリプトを䜿甚しお同じ機胜(Capability)の借甚ず参照の䜜成を行い、スクリプトからリ゜ヌスのhello()関数を呌び出せるようにしたした。これは重芁なこずです。なぜなら、機胜(Capability)を䜿甚せずにスクリプトからアカりントストレヌゞにアクセスするこずはできないからです。

チュヌトリアルを完了したので、以䞋のこずが出来るシンプルなCadenceプログラムを曞くための基本的な知識が埗られたした。

  • スマヌトコントラクトにリ゜ヌスを実装する
  • アカりントのリ゜ヌスぞのアクセスを蚱可する機胜(Capability)を䜜成する
  • 眲名枈みトランザクションずスクリプトの䞡方を䜿甚しおリ゜ヌスずやり取りする

スマヌトコントラクトを自由に倉曎しお、異なるリ゜ヌスを䜜成したり、利甚可胜なアカりントストレヌゞAPIを詊したり、スマヌトコントラクトから異なる関数を実行する新しいトランザクションやスクリプトを蚘述したりするこずができるようになりたした。 Capabilityベヌスのアクセス制埡ペヌゞを参照しお、Capabilityでできるこずに぀いおさらに詳しく確認しおください。

Cadence を䜿甚しおより耇雑なアプリケヌションを構築する方向性は正しいので、アプリケヌションが耇雑化しおきた今こそ、Cadence Best Practices ドキュメントずAnti-patterns ドキュメントを確認する絶奜のタむミングです。

翻蚳元->https://cadence-lang.org/docs/tutorial/capabilities


Previous << 3. Resource Contract Tutorial

Flow BlockchainのCadence version1.0ドキュメント (4. Capability Tutorial)

Next >> 5.1 Non-Fungible Token Tutorial Part 1

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?