villagerHの日記

勉強したことや苦労した事などを書き綴ります

Solidityの乱数生成

フロントエンド側からmethodが呼べるようになったのでコントラクト側に戻り
ゲームのロジック部分を作り始めて乱数が欲しくなったところ軽く詰まったので記録。

簡単な乱数が取得できれば良いのでCryptoZombiesに習いハッシュ値から乱数を取得する形で行きます。

CryptoZombiesは以下のような形になっています。

function randMod(uint _modulus) internal returns(uint) {
    randNonce++;
    return uint(keccak256(now, msg.sender, randNonce)) % _modulus;
}

now(現在日時),msg.sender(アドレス),randNonce(使い捨て数値)からハッシュ値を求めてその値から必要な範囲の数値を取り出して乱数値として生成していますね。

基本的にはこれを使いまわして以下の形で実装しました。

function randMod(uint _randNonce, uint _modulus) internal returns(uint) {
    return uint(keccak256(now, msg.sender, _randNonce)) % _modulus;
}

randNonceの使い方だけちょっと変えましたがロジック的には全く変わっていません。

solidityの0.5.0からkeccak256の仕様変更が入ったらしく、上記のコードだとコンパイル時に怒られます。

TypeError: Wrong argument count for function call: 3 arguments given but expected 1. This function requires a single bytes argument. Use abi.encodePacked(...) to obtain the pre-0.5.0 behaviour or abi.encode(...) to use ABI encoding.

パラメータはbytes型しか受け付けなくなったらしく上記のコードはもちろん、uint投げたりしても怒られました。

エラー文にもありますがabi.encodePakedを通してやるとbytesに変換してくれるようです。
なのでコードを以下に変更。

function randMod(uint _randNonce, uint _modulus) internal returns(uint) {
    return uint(keccak256(abi.encodePaked(now, msg.sender, _randNonce))) % _modulus;
}

コンパイルが通って無事に乱数取得処理が完成しました!