この記事は Hello World あたたたた Advent Calendar 2025 の記事です。
今日はSolidityで Hello World あたたたた を実装して解説していきます。
そもそも「Hello World あたたたた」が何かは 1日目の記事 をご覧ください。
Solidity / ブロックチェーン特有の前提
Solidityはブロックチェーンで使用される言語で、一般的なプログラミング言語とは異なる制約が存在します。
このため、お題の あたたたた とは以下の点で異なっているのでご了承ください。
- ループ部分はトランザクション発行で代替する。
- 出力するのは該当トランザクションで決定した文字のみとする。
以下、今回関係している制約を簡単に記載します。
※それ以外にもコントラクトなど、ブロックチェーンを前提とした記載がありますが、説明は他に譲ります。
無限ループは書けない
1回の関数呼び出し(トランザクション)は 必ず有限時間で終了する必要があります。
- 無限ループ → ガス切れ → トランザクション失敗
- 「繰り返す処理」は 複数回のトランザクションで表現する
完全な乱数はオンチェーンでは作れない
オンチェーンだけで改ざん不能な完全な乱数を生成することはできません。
今回は学習用途として、ブロック情報と状態を組み合わせた疑似乱数を使います。
コーディング例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloAtatatata {
event Output(string text);
uint256 private nonce;
// 疑似乱数の生成
function getRandom() internal returns (uint256) {
nonce++;
return uint256(
keccak256(abi.encodePacked(block.prevrandao, block.timestamp, msg.sender, nonce))
);
}
// 変数 hako に空の配列を用意
string[] private hako;
function run() public {
// Solidityで無限ループになる可能性がある処理は書けないため以下は無し
// - 変数 running に true をセット
// - running が true なら繰り返す
// - running に false をセット
// 0か1をランダムに決める
bool x = getRandom() % 2 == 0;
// もし0なら
// 変数 char に「あ」をセット
// その他なら
// 変数 char に「た」をセット
string memory char = x ? unicode"あ" : unicode"た";
// 画面に char を出力
emit Output(char);
// char を hako に追加
if (hako.length < 5) {
hako.push(char);
} else {
// 6文字目以降は、循環して終端5文字のみを保持する
hako[0] = hako[1];
hako[1] = hako[2];
hako[2] = hako[3];
hako[3] = hako[4];
hako[4] = char;
// もし 最後の 5 文字が「あたたたた」なら
if (
keccak256(abi.encodePacked(hako[0], hako[1], hako[2], hako[3], hako[4])) ==
keccak256(abi.encodePacked(unicode"あたたたた"))
) {
// "お前はもう死んでいる" を出力
revert(unicode"お前はもう死んでいる");
}
}
}
}
コードと文法の解説
変数の宣言・代入
Solidity では、変数を使う前に 型と宣言キーワードを書く必要があります。
string[] private hako;
bool x = true;
string memory char = unicode"あ";
- Solidity では型を書く必要がある(
string/boolなど) -
=は代入(右の値を左の変数に入れる) - 文字列は
"で囲む(日本語を使う場合はunicode"..."と書く) -
[]は配列を表す -
stringや配列は 参照型 のため、memoryなど保存場所に関する指定を行う -
memoryは関数の実行中だけ使われる一時的な変数で、実行が終わると消える -
boolやuintなどは 値型 のため、保存場所を指定する必要がない -
privateはコントラクトの外から参照できないことを意味する
「型」「保存場所」「可視性」が明示されることは Solidity の特徴です。
状態を使って「繰り返し」を表現する
このコントラクトでは、run() を呼ぶごとに「あ」または「た」を 1 文字だけ生成します。
function run() public {
...
}
Solidity では無限ループを書くことができません。
そのため、トランザクションを発行するたびに hako を更新して状態を保持することで、ループ相当の動作とします。
条件判定(if / else)
if (hako.length < 5) {
hako.push(char);
} else {
hako[0] = hako[1];
// snip
}
-
<や==は比較演算子 - Solidity ではブロックを
{}で表す - 複数の条件を評価したい場合は
else ifを使う
文字の出力(Output)
event Output(string text);
string memory char = x ? unicode"あ" : unicode"た";
emit Output(char);
- Solidityでは、画面に直接文字を表示することはできない
- 代わりに イベント(event)を発行して出力する
-
emitはイベントを発行するためのキーワード(Outputはサンプルで命名したイベント名) -
emitされたイベントは トランザクションログに記録される
トランザクションのlogsに以下のような出力が行われます。(Output(unicode"た")の例)
[
{
"from": "0x9B2A3840420401351628668FCFB97xxxxxxxxxxx",
"topic": "0xe75f2b39d184b4b99d3a5a16c5aa6940f3ffe06f8e799a27757xxxxxxxxxxxxx",
"event": "Output",
"args": {
"0": "た"
}
}
]
最後の5文字の比較
if (
keccak256(abi.encodePacked(hako[0], hako[1], hako[2], hako[3], hako[4])) ==
keccak256(abi.encodePacked(unicode"あたたたた"))
) {
revert(unicode"お前はもう死んでいる");
}
-
hakoには直近5文字を保持している - stringは
==で比較できないため、abi.encodePackedでバイト列に変換、結果をkeccak256でハッシュにして比較している -
revertを使っているが本来はOutputを使うところ-
revertするとそのトランザクション自体が失敗として扱われるため、今回のサンプルとしてはRemixで確認がしやすいため、このようにしている
-
疑似乱数の生成
ブロックチェーン上では、完全な乱数は作れません。そのため Solidity では 疑似乱数を使います。
uint256 private nonce;
function getRandom() internal returns (uint256) {
nonce++;
return uint256(
keccak256(abi.encodePacked(block.prevrandao, block.timestamp, msg.sender, nonce))
);
}
-
block.prevrandaoは直近ブロック由来のランダム値 -
block.timestampはブロックの生成時刻 -
msg.senderは関数を呼び出したアドレス -
nonceは毎回変化させるためのカウンタとして使用 -
keccak256はハッシュ関数で、入力が少し変わるだけで結果も大きく変化する
Solidity の概要と歴史
Solidityは、Ethereumをはじめとするブロックチェーン上で スマートコントラクトを書くために設計されたプログラミング言語です。
ブロックチェーン上で実行されるため、単なる計算だけでなく 資産の管理やルールの自動執行を担います。
DeFi(分散型金融)や NFT、DAO など、Ethereum エコシステムの中核を支える言語として広く使われています。
Solidity の特徴
- スマートコントラクト専用に設計された言語
- ブロックチェーン上でプログラムが実行される
- 状態は改ざんできず、透明性が高い
- 実行にはガス(手数料)がかかる
- JavaScript や C 系言語に似た文法
- DeFi、NFT、DAO などの分野で広く利用されている
Solidity の歴史
Solidity は、Ethereum の誕生とともに生まれた比較的新しい言語です。
Ethereum が「ブロックチェーン上でプログラムを動かす」という概念を実現するために開発されました。
現在ではEthereum 以外のEVM互換チェーン(Base、Polygon、BSC、Avalanche など)でも使われています。
- 開発元:Ethereum プロジェクト
- 初版公開:2014 年
- 主な用途:スマートコントラクト開発
- 対象環境:Ethereum Virtual Machine(EVM)
個人的なコメント
Hello Worldレベルしか触ったことがなかったですが、書き始めて「ループが書けない」点で少し躓きましたが、結果的に少し変わった題材を紹介できてよかったかなと思います。
おまけ:サンプルコードの確認方法
サンプルコードの確認には、Remixを使用しました。
2025/12/13現在ですが、以下の手順で確認しています。
!!注意!!間違ってもメインネットにつないで実行しないでください!
- Remixを開く。Web上でIDEが開きます
- Create ボタンを押して Create new file を選んで、 Create black で新規ファイルを作成します
- サンプルコードを貼りつけます
- Compile ボタンを押します
- 左端にある Deploy & run transactions のアイコンを押してデプロイを行うためのペインを開きます
- Environment が Remix VM (Osaka) になっていることを確認
-
Deploy ボタンを押します
- Deployed Contracts にデプロイしたコントラクトが表示されます
- ログも表示されているはずです
- コントラクトで run ボタンを押すと、サンプルコードの
runが実行されます- 何度か押しながらログを確認するとトランザクションが失敗するはずです
- ログの内容を見ると
お前はもう死んでいるはずです
