script (⏱,💰)

script (⏱,💰)

NG#6 - ストレージレイアウト

このタスクは、契約の状態変数のストレージに関するものです。指定された位置に特定の値を直接スマートコントラクトのストレージに書き込むために、Solidity の sstore に似た方法を使用する必要があります。

タスクをダウンロードすると、storage_write_syscallを使用して指定されたスロット位置に felt252 を書き込む必要があることがわかります。両方のパラメータは felt252 のタイプです。

fn write(ref self: ContractState, slot_index: felt252, value: felt252) {
  let storageAddress = slot_index.try_into().unwrap();
  storage_write_syscall(0, storageAddress, value);
}

StarkNet 公式ドキュメントCairo bookには関連する内容の説明があります。sn_keccak に相当する関数がどれであるかは明示されていませんが、ワークスルーには指示があります。

Cairo では、スロットアドレスは変数名から計算されるため、Solidity とは異なり連続していません。これにより、プロパティの名前が同じであれば、スロットアドレスも同じになるため、コントラクトのロジックのアップグレードが容易になります。

私のアプローチは、ローカルでのテストを書くことで、テストに合格した後にスロットのアドレスと値を表示し、starkli invoke write [slot_index] [value]を使用して回答することです。これにより、直接コントラクト関数を呼び出すことがより簡単になり、別途ハックコントラクトを書く必要はありません。

テストロジックには、starknet-foundryを使用し、次のコードを使用してコントラクトのデプロイをシミュレートすることができます。

use src::contracts::catacombs::{ICatacombsDispatcher, ICatacombsDispatcherTrait};
use snforge_std::{declare, ContractClassTrait};

#[test]
fn test_1() {
    let contract = declare('Catacombs');
    let contract_address = contract.deploy(@ArrayTrait::new()).unwrap();
    let dispatcher = ICatacombsDispatcher { contract_address };
...

felt252#

最初の entry_code は、felt252 を表す文字列です。write 内で直接書き込むことができますが、表示するためには 16 進数に変換して starkli コマンドに渡す必要があります。

u256#

2 番目のサブタスクは、10 の 40 乗の u256 を書き込むことです。累乗の書き方と u256 のストレージ方法に関わる問題です。

公式のコアライブラリに関連する演算子は見つかりませんでしたが、alexandriaというサードパーティのライブラリに実装があります。ただし、最も簡単な方法は、10 の 40 乗を直接 10000000000000000000000000000000000000000_u256 として書き込むことです。

u256 は low と high の 2 つの部分に分かれてストレージされます。公式ドキュメントによると、struct の最初の要素は sn_keccak に保存され、次に sn_keccak+1 が続きます。したがって、2 つの位置を計算し、2 つのトランザクションを提出して u256.low と u256.high に書き込む必要があります。

map#

3 番目の問題は、LegacyMap::<u256, bool> を書き込むことです。これは Solidity の mapping に似たもので、ドキュメントに詳細な説明があります。Map の場合、スロットの位置の計算方法は h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)です。

キーが u256 であるため、2 つの位置を占有する必要があるため、2 回ハッシュする必要があります。

ハッシュには core::pedersen::pedersen関数が使用されます。

渡される bool 値に対応する felt252 は 0 と 1 であり、3 つのインデックス位置に 1 を書き込む必要があります。

struct#

#[derive(Copy, Drop, Serde, starknet::Store)]
struct Chest {
    is_open: bool,
    owner: starknet::ContractAddress
}

4 番目の問題は、Chest 構造体を書き込むことです。実際、2 番目の問題で struct の位置の計算方法を既に知っています。ただし、この問題の唯一の問題は、StarkNet のコントラクトアドレスを felt252 に変換する方法です。ソースコードで対応するメソッドを見つけました。

結論#

この問題の主なポイントは、StarkNet のストレージレイアウトであり、難しいものではありません。ドキュメントを理解すれば簡単に解決できます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。