Nobiq
Nobiq

実例で読む: PulseCheck

実物のコードをまるごと1本読み解く総復習

総復習の回です。Nobiq Lab の動作確認に実際に使われているコントラクト PulseCheck を、まるごと 1 本読み解きます。ここまでの 8 回分の知識で、実物のコードがぜんぶ読めることを確かめましょう。

PulseCheck 全文

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract PulseCheck {
    uint256 public pulseCount;
    address public lastCaller;
    uint256 public lastPulseAt;

    event Pulse(address indexed caller, uint256 count, uint256 timestamp);

    function ping() external {
        pulseCount += 1;
        lastCaller = msg.sender;
        lastPulseAt = block.timestamp;
        emit Pulse(msg.sender, pulseCount, block.timestamp);
    }
}

PulseCheck(パルスチェック)=「脈拍の確認」。ping を呼ぶたびに「誰が・何回目・いつ」を記録する、生存確認のためのコントラクトです。自販機でいえば「押すと日時と累計が記録されるだけの点検ボタン」ですね。

上から読んでいく

骨格(第1回の知識)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract PulseCheck {

見慣れた 3 点セット。ひとつ気づきましたか? バージョンが ^0.8.19 です。これは「0.8.19 以降(0.9 未満)なら OK」という意味なので、書かれた当時のまま。Lab のコンパイラ(0.8.20)でも問題なく動きます。^ の意味が、実物でこうして効いてくるわけです。

状態変数(第2回の知識)

uint256 public pulseCount;
address public lastCaller;
uint256 public lastPulseAt;

整数 2 つと住所 1 つ。初期値を書いていないので、0 と「誰でもない住所」から始まります。public なので、デプロイ後の実行画面には読み取りボタンが 3 つ並ぶはず——第2回でやったとおりです。

イベント宣言(第5回の知識)

event Pulse(address indexed caller, uint256 count, uint256 timestamp);

「Pulse というお知らせを、押した人・累計・時刻と一緒に出します」。

ここで新しい言葉がひとつ: indexed(インデックスド)。「この項目であとから検索できるようにしておいて」という印です。indexed を付けた項目(ここでは caller)は、「この住所の人が押した Pulse だけを一覧で出す」といった絞り込みに使えます。イベント 1 つにつき 3 個まで付けられます。今は「検索用の印」とだけ覚えれば OK です。

関数(第3・4回の知識)

function ping() external {

引数なし・戻り値なしの関数。可視性が external です——第4回の表に出てきた「外から呼ぶ専用」。ping は外の世界から押してもらうためのボタンで、コントラクト内部から使う予定がないので、external が選ばれています(public でも動きますが、用途を宣言する意味で external の方が意図が明確です)。

手順の中身(第3・5回の知識+新出1つ)

pulseCount += 1;
lastCaller = msg.sender;
lastPulseAt = block.timestamp;
emit Pulse(msg.sender, pulseCount, block.timestamp);
  • pulseCount += 1; — 累計を 1 増やす(第5回の buy と同じ)
  • lastCaller = msg.sender; — いま操作した人の住所を記録(第3回)
  • lastPulseAt = block.timestamp;新出: block.timestamp は「いまの時刻」が自動で入っている特別な変数です(msg.sender の仲間)。厳密には「この操作が取り込まれたブロックの時刻」で、同じブロックに入った操作はみんな同じ値になります。単位は 1970 年からの経過秒数(UNIX 時間)という整数で、日付に直すのはアプリ側の仕事です
  • emit Pulse(...) — 3 つの値を載せてお知らせを発行(第5回)

つまり ping は「累計+1 → 押した人を記録 → 時刻を記録 → お知らせ発行」。たった 4 行に、この講座でやったことがぎゅっと詰まっています。

読解チェックリスト

自力で答えられたら合格です。

  1. ping を 3 回呼ぶと pulseCount() は何を返す?(→ 3)
  2. lastCaller() に入っているのは誰の住所?(→ 最後に ping した人。Lab では代行送信者、第4回の注記参照)
  3. Pulse イベントで検索に使えるのはどの項目?(→ indexed が付いた caller)

今回覚えたこと(新出は3つだけ)

  • indexed = イベント項目に付ける「検索用の印」
  • block.timestamp = いまの時刻(UNIX 秒)が入っている特別な変数
  • external の実際の使いどころ = 外から呼ぶ専用ボタンの意図表明

次回は最終回。自分だけのコントラクトを設計から作ります。

:::tip Lab でやってみる PulseCheck を写してデプロイし、①ping を実行 → ログの [event] Pulse(caller=..., count=1, timestamp=...) を確認 ②pulseCount()lastCaller()lastPulseAt() を読んで、イベントの値と一致することを確かめましょう。timestamp の数字を日付に直すと「いま」になっているはずです(検索サイトで「unix time 変換」と調べてみてください)。操作方法: コントラクトを動かす :::