script (⏱,💰)

script (⏱,💰)

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

ng6 スタート

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

タスクをダウンロードすると、指定されたスロット位置に felt252 を書き込むためにstorage_write_syscallを使用する必要があることがわかります。両方のパラメータは 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 に相当する関数がどれであるかは明示されていませんが、workthrough のタスクにも指示があります。

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 構造体を書き込むことです。実際の問題は、StarkNet のコントラクトアドレスを felt252 に変換する方法です。ソースコードで対応するメソッドを見つけました。

まとめ#

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

ng6 エンド

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