Solanaでプログラムを使った計算結果を取得する
Solangを読んでいたら不思議なコードに出会いました。
/// Simply returns the current value of our `bool`.
function get() public view returns (bool) {
return value;
}
Solanaのプログラム(スマートコントラクト)で値を取得する???
プログラムはデータをアカウントに書き込むために使用するのであって、Read用途では使えない認識でした。(アカウントに書き込む、トランザクションログを出力する、成功/失敗のステータスコードを返すだけできる認識)
SolangはSolidityで書けるようになるだけであり、基本的にはSPLで書かれているコードと同じような実行をするはずです。
そこで、コードを追いかけてどう実現しているのか調べてみましょう。
solana-developers/program-examples
solana-developersのprogram-examplesを見るといくつかSolangの例があります。
今回はその中のシンプルなアカウントを扱うaccount-data
を動かしていきましょう。(SolangのInstallationは完了している前提です)
IDLを確認する
$ anchor build
上記コマンドを実行するとtarget/
以下にいくつかファイルが生成されます。
その中のIDLを確認してみましょう。
{
"version": "0.0.1",
"name": "account_data",
"instructions": [
{
"name": "new",
"accounts": [
{
"name": "dataAccount",
"isMut": true,
"isSigner": true,
"isOptional": false
},
{
"name": "payer",
"isMut": true,
"isSigner": true,
"isOptional": false
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false,
"isOptional": false
}
],
"args": [
{
"name": "space",
"type": "u16"
},
{
"name": "name",
"type": "string"
},
{
"name": "housenumber",
"type": "u8"
},
{
"name": "street",
"type": "string"
},
{
"name": "city",
"type": "string"
}
]
},
{
"name": "get",
"accounts": [
{
"name": "dataAccount",
"isMut": false,
"isSigner": false,
"isOptional": false
}
],
"args": [],
"returns": {
"defined": "AddressInfo"
}
},
{
"name": "getAddressInfoSize",
"accounts": [
{
"name": "dataAccount",
"isMut": false,
"isSigner": false,
"isOptional": false
}
],
"args": [],
"returns": "u256"
}
],
"types": [
{
"name": "AddressInfo",
"type": {
"kind": "struct",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "houseNumber",
"type": "u8"
},
{
"name": "street",
"type": "string"
},
{
"name": "city",
"type": "string"
}
]
}
}
],
"metadata": {
"address": "eMzAsf1MokLZEZVVe7NpJyJLW2F15bME7sYrr3XMJJK"
}
}
Anchorでプログラムを作成したさいと同様にInstructionの定義が書かれたIDLが生成されました。
つまり、これはSolang独自の何かでではなく、Solanaのプログラムとしてデータを取得する方法があるということです。
(本来は.soのリバースエンジニアリングで〜とかで確定すべきですけど、その元気はなかった)
テストコードから解析する
今度はIDLを利用するクライアント側から見てみましょう。
ここで呼び出しているview()
で値の取り出しを行っているようです。
このview
メソッドはanchor
側に定義されています。
このメソッドは下記の流れで実行されます
-
simulateFn
を実行する - 戻り値で
Program return: ${programId}
から始まる行を取得する - 2の対象の行をデコードして、IDLで定義した型に変換する
simurateFn
ではprovider!.simulate
が呼び出されており、
最終的にconnection.simulateTransaction
が呼ばれる形になります。
つまり、simulateTransaction
を実行するとプログラムの実行ログが出力され、それを取得してデコードすることで、プログラムで計算した結果を取得できるようになるということですね!
おわりに
強い。(確信)
たぶん、これがSolangじゃなければトランザクションのログはログなので、そう使うものじゃないんだよ?と言ってしまいそうになるぐらいには強さに満ち溢れていますね。
手法としては面白いし、何かで活用できる気はするのですが、多用していいかは少し迷います。
Discussion