スマートコントラクトを開発をしようと開発入門の本を買ってみて勉強してみたのですが、実際にアプリを開発するためには不便すぎる&色々と悩ましい仕様が多かったので、メモがてらTipsを残しておきます。
便利な開発環境
開発入門だとデプロイの度にコマンド打ったり、ローカルのgethがコントラクトを承認するの待ったりと色々と面倒だと思っていたら、TRUFFLE(トリュフ)という開発ツールがあることを発見。
http://truffleframework.com/
TRUFFLE BOXESというDappを作るためのサンプルコードもあって便利。
フロントにReactやAngularを使ったものもある。
http://truffleframework.com/boxes/
デバッグ方法
VS Codeで開発していたらデバッグできなかった。
デバッグする時にはRemix(browser-solidity)を使う必要がありそう。
https://qiita.com/_pochi/items/69058975e8b1293f0467
[追記]
Truffle consoleでdebugコマンドを使えばデバッグ可能。
debug <Transaction ID>
http://truffleframework.com/tutorials/debugging-a-smart-contract
solidityにnullやemptyはない
uintなら0、配列ならlengthなどを使わなければならないので、ちゃんと設計しないとつまづく事に。
https://stackoverflow.com/questions/37852682/are-there-null-like-thing-in-solidity
stringの配列やmappingはreturnできない
これもちゃんと設計しないとつまづく事に。
addressやuintの配列は大丈夫とのこと。
https://ethereum.stackexchange.com/questions/17312/solidity-can-you-return-dynamic-arrays-in-a-function
https://ethereum.stackexchange.com/questions/11926/how-to-return-a-mapping-type
memory領域の可変長の配列はreturnできない
配列にループで何か値を格納してretuenする際に、配列を固定長で定義しないとVM error: invalid opcode.
というとエラーが発生する。
// OK
uint256[] memory results = new uint256[](10);
for (uint256 idx = 0; idx < 10; idx++) {
results[idx] = idx;
}
return results;
// NG
uint256[] memory results;
for (uint256 idx = 0; idx < 10; idx++) {
results[idx] = idx;
}
return results;
バグがあった時にコントラクトをアップデートできるようにデータとロジックを分ける
バグがあった場合、新しいコントラクトをデプロイすることになりデータが消えてしまうので、データを保持するコントラクトは切り出して置くと良いとのこと。
データの方にバグがあったら大変そうだ。。
https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88
[追記]
アップデート可能なコントラクトといかいう概念もあるらしい。
https://fukutech.hatenablog.com/entry/upgradeability-contract
https://guide.blockchain.z.com/ja/docs/problem/versionup/
throwではなくrequireを使う
throwは廃止されていているらしい。
https://github.com/ethereum/solidity/issues/1793
ループは極力使わない
長さが未定の配列のループはgasをたくさん消費してgas limitに達し、コントラクトが実行されない可能性があるとのこと。
http://solidity.readthedocs.io/en/develop/security-considerations.html#gas-limit-and-loops
transactionの発行が必要なファンクションは戻り値を受け取れない
transactionの発行が必要なファンクションで戻り値を設定していても、外部のアプリケーションから呼んだ場合には戻り値を受け取ることはできない。
戻り値が必要な場合は、Eventの発行かStorageへの保存で対応する必要がある。
https://ethereum.stackexchange.com/questions/31399/get-the-return-value-of-payable-function