Plasmaについて学ぶ
BlockChainのトリレンマ
- トリレンマ どれも好ましくないが、その中から1つを選択肢しなければいけない状態
現状のEthereumの問題
1秒間に 10 - 15transaction程度しか処理できない 遅い!!
なぜか
- decentralization(分散化)を維持する必要があるから
- 全ての人が、transaction を検証しているから
- そもそもtransactionの数が多い
- blockが伝播するまでwaitしておく必要があるから
ETHにおけるトリレンマ
分散を維持するために処理速度を犠牲にしているから
分散 - 拡張性 - 安全性 の 3つの内、どれかを犠牲にしなければいけない
もう少し具体
Scalability(拡張性) と Decantralization(分散) を優先すると、Security が犠牲になる -> Blockの生成が早いと、forkの確率が上がり、reorg(再編成)の可能性が上がる -> データ量が増えると、miningできるnodeが限られてくるので、集中化する
ScalabilityとSecurityを優先すると、Decantralizationが犠牲になる -> PoA(信頼できる人のみがブロックを作成できる)などを採用すると、minerへのtrustが必要になる
Side Chain を用いた改善案
Salabilityを改善するための方針
- 自分に関係のあるtransactionのみを検証する(検証量を減らす)
- 特定のtransactionのみを流すようにしたい
main(root) chainがnode数が多くて、処理に時間がかかってしまう それに対して、side chainは特別な処理をするユーザー/nodeのみが参加して、Blockの生成を行う
side chainが満たすべき仕様
2 way-peg
- 必要に応じて、root chain から side chainに移動することができる
- root chainのassetsをside chainに移動する仕組み
- side chainでの取引終了後, root chainに戻す必要がある
PoS / dPoS / PoA
PoWでも不可能ではないけれども、Block長に期待ができないため、reorgが起こる可能性がある 2way-pegを使用するため、root chain / side chain で finalityを得られるアルゴリズムの方が好ましい
side chainが抱える問題
root chainと同等の価値を持つ token を 弱いchain上で扱っている node数が少ないので、minerの裏切りが起こる可能性がある
Plasma
大切にすること
参加者の資産を守ること
満たすべき条件
minerが裏切ったら参加者はいつでもroot chainに戻ることができる
どのように実現しているのか
Plasma chain(Plasmaに基づいて作られたside chain)は一定期間ごとに root chainに cheak pointに記録する
exit(資産の引出し方法)
root chainに対して、exitを行う root chainでは、checkpointを元にそのexitが正当かどうかをチェックする root chainには、記録がされているため、正当化どうかのチェックは可能
ECDSA署名について学ぶ
事前の単語知識
Bitcoin の通常の2-of-2マルチシグ
Bitcoinを使用するための複数人の署名が必要な仕組み
scriptPubKeyに複数人の公開鍵がセットされていれば、Transactionを行う際に、それぞれの秘密鍵をセットする必要がある
ECDSA の署名
登場するもの
生成方法
- ランダムなnonce(Transactionごとに生成されるもの)を選択
- k を秘密鍵とした楕円曲線上の点 R = kGを計算する
- 点Rのx座標をrとする
- s = H(m) + rx / k
- 算出される (r, s) がECDSAの署名データになる
両方を合わせると73バイトくらいにデータになる
検証方法
Rx = H(m) + rx + Gs / s
ECDSAでマルチシグを構成するポイント
生成された値 (r, s)の内、秘密鍵を使った計算をするのはs
s = H(m) + rx / k
秘密鍵xを2者の秘密鍵から算出する値にすると、署名は単一になるが、2者の秘密鍵を必要とするマルチシグを構成できる
両者は それぞれの秘密鍵の内容を明示してはいけない
コインのロック
登場するもの
A の 公開鍵 P1 秘密鍵 x1 B の 公開鍵 P2 秘密鍵 x2
A と Bはそれぞれ 公開鍵を共有し、新規の公開鍵 P と nonce R を生成する これを用いて、2者間でのロックをすることができる
これをアンロックするには、 s = H(m) + r(x1 x x2) / k1 x k2 を計算する必要がある
秘密計算で署名データを計算
- AはPaillier暗号用のキーペアを生成(private, public) Paillier暗号は加法準同型性がある暗号スキーム
- publicを使って、Aの秘密鍵 x1 を暗号化し、publicと一緒に Bに送信
- Bは c1 = Enc(H(m) / k2) c2 = Enc(x1) ⊙ rx2 / k2 c3 = c1 ⊕ c2 を行い public を暗号化
- Aはc3を復号して、 s` = H(m) + r(x1 x x2) / k2 を算出
- s` / k1 で必要署名のsが取得できる
EVMとは何か
EVMとは何か
Ethereum 上にのっているVirtual Machine
SmartContractを動かず場合には、基本的に EVMの上で実行する
特徴
- チューリング完全
- stack型のマシン
- 256個のopcodeを持つ // opcode -> 機械語の1個の命令の部分で、実行する操作 (operation) の種類を指定する部分のこと
- 32byteのsegment
Ethereumのstateは全て EVM を実行した結果だってよ!
Transaction
Ethereum は World State Of Machine と言われるが、Ethereumでは前のStateの状態に前のTransactionの値を受け取って、前のStateの状態と新しいTransactionをEVMにいれて、次の状態に変わるのが基本的な流れ
S -> State Tx -> Transaction
S[N+1] = EVM(S[N], Tx[n])
World State(Ethereum の データ)の構造
BitCoinと同じく、PREVHASHを持っていて、STATE_ROOTを持っている さらに、STATE_ROOTが State DBになっている Tree上になっているが、各ノードに細かいデータを保持している
STATE_ROOTの構造
中身は全てアカウント情報になっている
- nonce -> Transactionを発光するたびに増加していくもの
- balance -> 保有しているETH量
- code -> Contract Address 本体が格納されている
- storage root -> Contractの場合に、Contractの状態を格納する領域として使用される
Contract Creation
Contractを生成する時に何が行われているのか
- Contract Address の生成 -> StateDB上に保存するAddressの生成
- StateDBに新規Account領域を確保 -> Addressに対して、新規Accountの領域を確保
- nonceを1にセット
- ETHを送信
- init codeを実行(storageとcodeの初期化)
- code hash を記録
これで Contractの生成が完了する
Contract Addressの生成方法
決定論的アルゴリズムで、Contract Creation Transactionを投げた address (sender address)とsender address が持っている nonceの値によって生成が行われる
nonce は インクリメントで増えていく + sender addressもユニークなので、Contract Address はユニークになるはず!
Storage と code の初期化方法
Contract Creationを投げたときにデータ部に長いopcodeが格納されいるのが、init 処理と本体コードを含む処理になる 上部にinit処理が書かれており、実行されることで本体コードだけ取り出される
本体コードの構成
大きく分けて、3 ~ 4
- free memory 領域宣言のための定型処理(定型文!)
- 送られてきたETHの量を検証している
-> 間違ってETHが送られてきた場合に弾く
-> payableをつけると、ここの処理を抜けれる
- 本体のコードを残す処理.return値としては、本体codeをかえす
Goのポインタがよくわかってないから、まとめてみる
Goは勉強のコストが低いから、誰でもやりやすい言語と言われている.
それは重々承知しているし、実際に書いていて、わかりやすい言語ではあると思う.
しかし、曖昧なまま進んでいくと、ぶち当たるだろう ポインタ , これがマジでよくわからない. 元々 CS とか出てる人は Cとかやってるのかもしれないけど、文学部のワイにはマジでよくわからない.
さぁ学んでみよう!!
Goの型
Go自体は、みんなご存知の通り、静的型ありの言語 型の種類は、 int, string ...etc その中に ポインタ型というのがあり、その名の通り、ポインタを扱うための型である.
これは、変数宣言の時に、型名の前に " * " をつけることで定義できる. 変数に"&"をつけると変数の アドレス を参照することができ、アドレスから変数の値を参照するには" * "を変数につける。
package main import "fmt" func main() { var p *int var n int n = 10 p = &n fmt.Print(p) // 0xc000094010 fmt.Print(*p) // 10
変数 p は ポインタ型として定義されている. そこに int型の n( 10が代入されている ) のアドレスを代入.
出力しては、pのアドレスと代入された値の 10がでてくる
そこで1個疑問が出てきた
p と n のアドレスは同じなのか
package main import "fmt" func main() { var p *int var n int n = 10 p = &n fmt.Print(&p) // 0xc000094010 fmt.Print(&n) // 0xc00009a000
よくよく考えれば、p は 別で変数宣言してるわけだし、中身を n のアドレスで上書きしても、元々のアドレスが変わるわけではない.
一度知識として、アウトプットすれば、こんなもんかって感じ
どうやってログとるの?
メディア事業部のシステムは全部 Rails で組んである。
どれくらいユーザーが記事読んだとかとかの行動ログ取ってるんだけど、Railsが吐き出してる production.log
を解析してるから、余計な情報があまりにも多い。
なので、nginxから取得できる access_log
を取るように変更したいっていうタスクが降ってきた。
とりあえず、「nginx ログ分ける」 とか検索するけど、めぼしいものはでてこない。その後も調べを続けて、locationで区切ればいいというところまではわかったけど、正規表現の目印的なものがない。
最終的には頼みの綱の先輩に聞くと、gif とかの画像仕込んでるから、それ取れば、もし仕込んでなかったら仕込めばいい。
はい、一瞬で解決。
rmagik の montage で 困った話
動画を配信するサービスをやっているので、動画の転送量が馬鹿にならない。 さぁどうするかね。
やりたかったこと
動画から生成した画像を montage
する。その時、画像の容量が大きくなるため、できるだけ削減したい。
やったこと
まずは画像の容量下げる方法考える。
CLIでやりたかったから、JPEGminiなどのGUIツールは却下。
とりあえずGoogle先生に聞いて見ると、こんな答えが返ってくる。
https://developers.google.com/speed/docs/insights/OptimizeImages?hl=ja
jpegoptim jpegtran 使えと、ほうほう。
Linux上で使うことも考えて、さくっとできそうなjpegoptimを使ってみる。
手順
ffmpeg -i original.mp4 -f image2 -vf fps=fps=12 -crf 20 images/img%d.jpg
jpegoptim --strip-all -m80 *.jpg
jpegoptim なし | jpegoptim あり |
---|---|
584K | 544K |
まぁ画像の総量を比較すると、少し減ってるのがわかる。 大きい動画の場合、もっと減る。
画像を結合する
montage *.jpg -tile 5x6 -background none animations/%d.jpg
jpegoptim なし | jpegoptim あり |
---|---|
564K | 564K |
......変化なし。
他のツールも使って見たけど、結果は同じ。
原因としては、montage
使うと、質の部分は元に戻るようだ。非可逆ではないjpegでどうやって認識してるのか分からないけど。
仕方ないので、montage
のオプションで使えるのがないかを探すと、-quality
でいけるみたい。
案外あっさりと見つかる。
montage *.jpg -tile 5x6 -background none -quality 80 animations/%d.jpg
quality 指定なし | quality 80 |
---|---|
564K | 296K |
下がったね。だいぶ
ちなみに今回作った画像の一部がこんな感じ
rehash を 覚えていない僕へ
今日の業務の中で、別のリポジトリのコードを修正するタスクが回ってきた時の恥ずかしかった話。
そのリポジトリ自体は、先輩が開発から修正まで全部してきた。
僕はまずコード読んで、多分ここ修正すればいいだろうという目星をつけたところまでは良かったのだけれども、いざ環境構築だとなったとき、全然うまくいかない(泣)
何がうまくいかないかって、READMEに書いたあることやっても、途中で「そんなコマンドないよ」とエラーを吐かれる。
そのリポジトリのコードは、一つの自作Gemになっていて、独自のコマンド叩いたら、動画が変換できるようになっている。
でも独自のコマンド叩くと、「そんなコマンドないよ〜」 なぜ!?
俺、環境構築でつまづくって、成長してないなと悩みつつ、ただ時間が過ぎていくので、先輩に聞くと、
先輩「パス通ってる?」 僕「ええ、たぶん通ってます」 先輩「ちょいかして」
先輩が何か調べてると、最後に
rehash
はい、あっさりとうまくいきました。
先輩「Gemとか入れたら、Hashテーブルをリロードしなきゃいけないぜよ」
今までそんなこと知らなかった。
rehashはRubyとかの環境構築するときにコピペで使ってたけど、そのためだったのかというを今日初めて知った。
その時は、すごく恥ずかしかった。
でも、恥かいたことは忘れない。
ってか忘れられない。
みなさん、知ったかぶりはやめましょう。たくさん恥をかきましょう。