- Concepts_Overview
- What is Casper?
- Design
- Economics
- アカウントと暗号鍵
- キー(Key)の型への理解
- Transactions(トランザクション)
- トランザクションのライフサイクル
- グローバルステート
- スマートコントラクト
- 認証鍵
- コールスタックへの理解
- Dictionaries(辞書)
- Binary Serialization Standardバイナリシリアライズ規格
- dAppsについて
- Glossary(用語集)
Dictionaries(辞書)
Casper Networkでは、Keyにデータセットを格納できるようになりました。以前は、URefがグローバルステートにデータを格納する為の唯一の手段でした。Urefへの持続的なアクセスを維持するには、AccountもしくはContractのコンテキスト内に格納することになります。コントラクトの場合は、URefを持続的に使い続けていくことで、アソシエイトNamedkeys構造体の拡張に繋がるでしょう。
NamedKeys内に格納されているデータの個々の値の変更にはNamedKeysデータ構造全体の非直列化を必要とし、それによってガスコストが増加するのでネガティブなインパクトを与えることになります。更には、データ構造体にマップされた大きいサブセットを格納しているユーザーは、マイナーもしくは単一の更新がマップ構造の完全な復元処理を必要とする同様の根深いコピー問題に直面し、これもまたガスコストの増加に繋がります。
この問題に対する解決策としてCasperプラットフォームはDictionary(辞書)機能をユーザーに提供し、より効率よくスケーラブルなデータの集約を可能にしています。
殆どの場合、辞書はデータストレージより整った形状となっています。格納されたデータの書き換えを、コストを抑えて柔軟に対応します。
Seed(シード) URefs
Dictionary(辞書)内のアイテムは、グローバルステートにあるユニークなdictionary address下に保存された個々の記録として存在しています。言い換えると、指定したdictionaryに紐づいたアイテムは、同じシードURefを共有しているか相互に独立したものか、となります。Dictionaryアイテムは、URef下には保存されておらず、dictionary keyの生成にのみ使用されています。
各dictionaryアイテムは、グローバルステートにスタンドアローンで存在しており、通常は、シードURefを参照せずして直接的にdictionary keyに使用しています。
Dictionariesの利用
Dictionariesは、NamedKeysでの格納が難しい大きなサイズのデータの格納に出来しています。
新規dictionary(辞書)の作成は、とてもシンプルかつCasper Networkに送信されたトランザクションのコンテキスト内で完結できます。関連するコードは、casper_contractクレート内にあります。辞書を作成することで、その時点でのコンテキストの名前付き鍵内にある関連するシードURefも保存できます。
開発者は、辞書を作成する際は常にコンテキストを考慮してください。Contractのコンテキスト内での辞書の作成を推奨しています。
Accountのコンテキスト内で辞書を作成し、関連するアクセス権をContractに渡すことは可能だが、この手法は、潜在的なセキュリティ問題の起因となり得ます。第三者がCntractを使用する場合、辞書へのアクセス権を付与した状態でAccountを初期化する方法は良策ではないでしょう。改善案として、それらのアクセス権を削除する追加のDeployを送信することも可能だが、Contractのコンテキスト内で辞書を作成する方が好ましいです。
辞書は、NamedKeysのサイズを劇的に大きくせずして、コンテキスト内にてコントラクトによる追加データの格納を可能にします。コントラクトのNamedKeysが大きくなりすぎた場合、システムの限界に達し予期せぬコントラクトの機能不全が起こり得ます。
辞書のアイテムキーは、64バイト長以上にはなりません。
辞書の実用例
Casper CEP-78 Enhanced NFT 規格には、いくつかの実用的な辞書のアプリケーションがあります。
辞書を使用したシンプルな例としては、CEP-78で使用している approve があります。
CEP-78 Page Systemにて使用されているより高度な辞書機能では、トークンの所有権の追跡を行える辞書シリーズを使用しています。これらの辞書は、ルックアップモードを返す基盤を形成しており、アカウントやコントラクトが保有しているトークンのリストをユーザーにて簡単に参照可能としています。
コントラクトのコンテキスト内での辞書作成
下記のコードスニペットは、最も基本的な辞書の作成例を示しています。
casper_contract::contract_api::storage::new_dictionary(dict_name)下記の例では、”ledger”という辞書をコントラクトのコンテキスト内で作成する方法です。このインスタンスでは、initエントリーポイントで作成され資金調達のお財布(パース)への寄付をトラックする為に、辞書を使用しています。自身のコントラクト内で辞書を使用する如何なる場合でも、初期化するエントリーポイント内にセットアップしてください。
#[no_mangle]
pub extern "C" fn init() {
let fundraising_purse = system::create_purse();
runtime::put_key("fundraising_purse", fundraising_purse.into());
// Create a dictionary to track the mapping of account hashes to number of donations made.
storage::new_dictionary("ledger").unwrap_or_revert();
}辞書へのエントリーの書込み
dictionary(辞書)の作成後は、下記コードを用いてエントリーの追加を行います。
storage::dictionary_put(dictionary_uref, &dictionary_item_key, value);dictionary_urefは、辞書の作成過程の途中で構築されるシードURefを参照します。Keyは、辞書アイテムのユニークな識別子となり、値は辞書内に保存されるデータとなります。
上述した通り、これらの辞書アイテムはシードURefを必要とせず、固有の鍵としてグローバルステートに存在します。個々の鍵アドレスを知っている場合は、始めにシードURefを認識するプロセスを踏む必要はありません。
下記機能が辞書にエントリーを追加してくれます。アイテムが既に存在している場合、エントリーポイントが鍵で保存したり参照した値の更新を行います。この場合は、コードによって作成された寄付の数が保存されます。どのRustの構成でも辞書アイテムの下に保存されますが、大きな構造での値の更新時(例:a list)は、構造全体がアップデートの一部として上書きされます。大きな構造の更新では、辞書アイテムへ構造を書込みするコスト全てが発生します。
最初のセクションは、新しい辞書アイテムを適切な辞書に割り当てるためにLEDGERシードURefを取得しています。
fn update_ledger_record(dictionary_item_key: String) {
// Acquiring the LEDGER seed URef to properly assign the dictionary item.
let ledger_seed_uref = *runtime::get_key("ledger")
.unwrap_or_revert_with(FundRaisingError::MissingLedgerSeedURef)
.as_uref()
.unwrap_or_revert();2つめのセクションでは、dictionary_getを使用してLEDGER dictionary内でのエントリーの読取りを行います。エントリーがグローバルステートに存在していない場合は、エントリーを作成します。既に存在している場合は、エントリーがdictionary_putオペレーションを使用してその時点での値を更新します。上述した通り、エントリー内での変更の大きさに関わらず、辞書全体のエントリーが上書きされなくてはならずそれに伴いコストが発生します。
// This identifies an item within the dictionary and either creates or updates the associated value.
match storage::dictionary_get::<u64>(ledger_seed_uref, &dictionary_item_key).unwrap_or_revert()
{
None => storage::dictionary_put(ledger_seed_uref, &dictionary_item_key, 1u64),
Some(current_number_of_donations) => storage::dictionary_put(
ledger_seed_uref,
&dictionary_item_key,
current_number_of_donations + 1u64,
),
}
}JSON-RPCを使用したアイテムを辞書から読み取る方法
Casperプラットフォームは、辞書アイテム検索の意味をいくつか提供しています。それらについては、DictionaryIdentifier JSON-RPC型にて説明しています。以下は、Casper clientを使用した辞書アイテムのクエリ方法について説明しています。
コントラクトの名前付き鍵を用いたContractNamedKey ルックアップ(検索)
コントラクトの名前付き鍵を使用した辞書アイテムの読取りは、以下のパラメータを必要とします。
- Node Address – Casper Network上のIPとノードのポート。下記の例では、ノードのアドレスは、ローカルのNCTLネットワークに向いています。
- State Root Hash – 読み取ろうとしているCasperネットワークが管理している辞書アイテムのある時点でのステートルートハッシュ
- Contract Hash – 辞書を参照しているコントラクトのNamedKeys(名前付き鍵)のコントラクトハッシュ
- Dictionary Name – コントラクトのNamedKeysに格納された文字列としての辞書の名前
- Dictionary Item Key – 文字列として読み取る特殊な辞書アイテムキー
casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--contract-hash hash-09c8fa7c1441ae7c1cbe27ae3a722fd4ffc5290315f8546454454c1b9f85c842 \
--dictionary-name <String> \
--dictionary-item-key <String>辞書のシードURefを介したURef ルックアップ
辞書のシードURefを使用した辞書アイテムの読取りには、上記のとおりNodeアドレスとステートルートハッシュ、辞書のアイテムキーが必要となります。ただ、コントラクトハッシュや辞書名は必要ありません。その代わり、以下が必要となります。
- Seed URef – 参照用の辞書 Seed(シード) URef
casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--dictionary-item-key <String> \
--seed-uref uref-90b4a8d936b881d3b45b73a102adb2b652181d75c76b7547ae9d1bb213f8db6b-007ユニークな辞書アイテムキーを介した辞書のルックアップ
読み取り先の辞書アイテムキーの辞書アドレスが既知であるイベントでは、以下のCasperクライアントコマンドを使用して直接それを読みに行くことが可能です。
casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--dictionary-address dictionary-<string>