仮想通貨のなんやかや

仮想通貨のなんやかやを書いていきます

Crypto Zombieレッスン4-4翻訳

ちょっとわかりにくかったので整理のために翻訳してみる

cryptozombies.io

cryptozombies.io

Chapter4: 乱数

よし!次はバトルロジックに向かおう

すべての良いゲームは、何らかのランダム性が必要だ。

なので、どうやってSolidityでランダム性のある数を生み出すかを見ていきましょう

 

本当のことを言うと、それはできない。いや、少なくとも安全にはできない。

では、なぜそうなのかを見ていこう

乱数をkeccak256で生み出す

Solidityでもっとも良いランダム性をうむソースコードはkeccak256ハッシュ関数を用いることです。

以下のようなコードで乱数を生み出すことができます

// Generate a random number between 1 and 100:

uint randNonce = 0;

uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;

randNonce++;

uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;

  まず、今のタイムスタンプmsg.sender(送り手のアドレス)を利用して、その後nonceをインクリメントします(一つの数字は、一回だけ使われます。なので、hash関数を全く同じパラメータで2回呼び出せないようになっています) keccakを用いて、パラメータをランダムハッシュに変換します、その後hashをuintに変換し、%100を利用して、最後の二桁だけを取り出すことで、0-100までの間のランダムの数字を取得できる仕組みです

この方法は、不正を働こうとするノードからの攻撃に対して脆弱です

Ethereumにおいて、あるcontract上である関数を呼ぶとき、あなたは、それをあるノードあるいは複数のノードにtransactionとしてネットワーク上にブロードキャストします。 ネットワーク上でそのノードは、transactionの塊を集めて、最初にProof of Workの数学的問題を解こうとします。 そのtransactionのグループを、他のネットワークに対してblockとして、そのPoWと一緒に公開します。   一度あるノードがPoWをとくと、他のノードはそのPoWを解くことをやめて、他のノードのtransactionのリストが正しいことを承認します。そして、そのblockを受け入れて、次のブロックを解き始めます

これは我々の乱数を悪用可能な状態にしています

例えば、コイントスcontractを考えてみましょう。(表が出れば二倍に、裏が出れば、全部失う。) 上の関数を使って、表と裏を表現しましょう( random >= 50ならば表、 random < 50 ならば裏)

もしこのコードを動かしたとして、transaction自分のノードだけに公開し共有しないということができます。そして、コイントスの関数を走らせて、勝つか負けるかを見ることができ、自分で解いている次のブロックのtransactionに含めないことを選択することができます。そして、これを最後に勝利するまで続けることができ、次のブロックを解いて、利益を得られるのです。

一体どうすれば、Ethereum上で、乱数を安全に生成できるのでしょうか?

blockchainの中身は完全にすべての参加者に公開されているので、とても難しい問題です。そしてその回答はこのチュートリアルの範囲を超えています。 StackOverflowのスレッドでいくつか野愛でを見ることができます 一つのアイデアは、oracleを使ってEthereumのblockchainの外側から乱数にアクセスする方法です。

もちろん、何万ものネットワーク上のEthereumのnodeが次のblockを解こうと競い合っているので、自分が次のブロックを解ける可能性はとてつもなく低いです。 とても多くの時間や計算するためのリソースをこの悪用に用いることになります。 しかし、もしこの報酬が十分に大きければ(例えば、一回勝つと100,000,000$もらえるとしたら)、攻撃するに値します。

この乱数生成はEthereum上では安全ではありませんが、私たちのランダム関数が多額の金銭を必要としない限り、ゲームのユーザーはそれを攻撃するのに十分なリソースを持たないでしょう。

我々は、単純なゲームをデモの目的でこのチュートリアルでは作っているにすぎないですし、実際のお金が関わるわけではないので、完全に安全ではないと知りながら、このシンプルな実装を使うことを受け入れることにしましょう

未来のLessonでは、oracles(安全にEthereumの外側からデータをひっぱってくる方法)で安全な乱数をblockchainの外側から生成する方法をカバーするかもしれません。

テストコードを書いてみよう

乱数を制せ牛る関数を実装しましょう。我々のバトルの結果を決めるものです(完全には安全ではありませんが)

  1. randNonceをuint型で定義し、0をsetしましょう
  2. randModと言う名前の関数を作りましょう。internal関数で、uint型の_modulusを一つ受け取って、uint`を返り値として返します。
  3. 関数は、最初にrandNonceをインクリメントすべきです(randNonce++を利用して).
  4. 最後に、(ワンラインで、) keccak256ハッシュをnowmsg.sederrandNonceを使って生成し、uintにキャストして計算します。そして、%_modulusとして値を返却します(すごい!もしうまくいかなかったら上の説明をみてください。ロジックはとても似ています)