EVMの限界を突破して行く
WIP
これはなに
Ethereumでスマコン書く時にブチ当たった壁とその解決策の記録
EVMでぶち当たる壁
その1 Stack Too Deep
その2 コントラクトサイズ
その3 gasコスト
memo
配列に格納、参照作業はgasとスロットを使う
配列の要素をevnetで発火する際は変数にpushする前段階で変数に代入しておいて、それをeventではいた方がコスパがいい
しかしコントラクトの限度サイズを超えてしまう
Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fails.
More info: eip-170
structのプロパティは8個がマックス
eventではけるstructは3つ
1. Stack Too Deep
2. 困った時のガス削減 Tips
個別ケース
パターン1
Array.push(NewStruct(hoge,hoge,hoge));
emit StructGenerated(Array0); NewStruct memory foo = newStruct(hoge,hoge,hoge);
Array.push(foo);
emit StructGenerated(foo);
パターン2
Struct storage struct = structs(id-1)
change state
emit getStruct()
Struct storage struct = structs(id-1)
change state
Struct memory struct = structs(id-1)
emit getStruct()
パターン3
スロットの節約
https://gyazo.com/916965189effc709d63f79a6a17659ac
パターン4(うーんだけど)
ガンガンハードコーディング
Use libraries to save some bytecode
3. コントラクトサイズ
お気持ち
コントラクトサイズに制約があるのはgasが膨大になるのを防ぐため。なので超工夫してgasコストを抑えたとしてもコントラクトサイズは大きくなるので詰む。gasを節約するコードを頑張って書いた時にgasコストは問題ないのに、gasコストが膨大になるのを防ぐことを目的としたコントラクトのbyte制限に引っかかるのはなかなかの本末転倒感isある。
<< EIP170
コントラクト(solidity, vyper)をコンパクトにする≠>ガスを削減
コントラクト(solidity, vyper)をコンパクトにする≠>byte数を削減
アセンブリーをコンパクトにする≠>ガスを削減
アセンブリーをコンパクトにする→byte数を削減
ガスを消費するオペコードを減らせば→ガスを削減
ガスを消費するオペコードを減らしつつアセンブリーをコンパクトにする→最強
なんで制限があるの
when a contract is called, even though the call takes a constant amount of gas, the call can trigger O(n) cost in terms of reading the code from disk, preprocessing the code for VM execution, and also adding O(n) data to the Merkle proof for the block's proof-of-validity.At the higher gas levels that could be triggered in the future, possibly very soon due to dynamic gas limit rules, this would become a greater concern - not nearly as serious as recent denial of service attacks, but still inconvenient especially for future light clients verifying proofs of validity or invalidity.
<<コントラクトが無制限にでかいとそれに応じて消費gasも多くなるから将来的にgasが高騰?(gas levelとは?)するとgas消費がすごい事になって困る
<<V神) ほんじゃコントラクトサイズ上限作るか
制限は24576(0x6000)
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract(0x6000)
ハードコードされている。(プライベートチャンネルなら書き換えも可?)
解決策(優先度高い順)
秘密兵器optimaizer
optimiserは多言語に対応できるようにassemblyに対して機能する。OptimizerはbytecodeをJUMPs と JUMPDESTsの部分で分割し、 “CommonSubexpressionEliminator” を利用して同じ表現の部分を統合する。
<<表現が同じならなば統合される
<<なるべく同じ使い回しを多様すれば同じ挙動のコントラアクトでも多くの部分をoptimizeしてくれる。
<<仮説:optimizeしたassemblyをbyteに戻した時のバイト数が24576以下ならばok?
optimizer BEFORE AFTER
BM old 41316 op assembly 14112-908-(3)
BM old 59356 no op assembly 19290-908-(1)
BM old 68680 no op assembly 23813-1500-(5)
BM old 107747 no op assembly 33260-908-(1)
もうアセンブリーを書いてしまえ
assembly BEFORE AFTER
アセンブリでも無理。Huff