対応方法 - GAS使用量問題

コントラクトのデプロイ時に全ソースをトランザクションに入れることが前提のため、コントラクトで必要なロジックがが多くなれば、その分大量のGASが消費されます。

そこで、このフィールド部を structure として Contract から独立させ、コントラクトのデプロイは一度だけ行います。

オブジェクトはデプロイしたコントラクト内で、 structure オブジェクトとして生成し、id とのマッピング形式で管理します。

  • クラス図

    structure

  • ソースコード

    contract SomeThing {
    
        struct SomeThingStruct {
            bytes32 id;
            string name;
        }
        mapping (bytes32 => SomeThingStruct) someThings;
    
        function create(bytes32 _id, string _name) {
            someThings[_id] = SomeThingStruct(_id, _name);
        }
    
        function getId(bytes32 _id) constant returns(bytes32) {
            return someThings[_id].id;
        }
    
        function getName(bytes32 _id) constant returns(string) {
            return someThings[_id].name;
        }
    }
    

    structure

これによりデプロイ時には 275,234GAS が必要になりますが、その後のオブジェクト生成毎のコストは 63,250GAS (22.98%) に抑えられています。

注意点

GAS削減はできましたが、この方法には一つ問題点があります。

Contract のデプロイ時には、デプロイされたContractを一意に特定するアドレスがEthereum上で付与されます。

structure の場合は、それぞれアドレスを保持しているわけではないので、一意に特定するキー(ここではidフィールド)を呼び出し側が指定する必要があります。

万一キーが重複した場合は、throwなどでエラーを出して重複登録を防ぐ必要があります。

  • 登録時の重複チェック

    contract SomeThing {
        struct SomeThingStruct {
            bytes32 id;
            string name;
        }
        mapping (bytes32 => SomeThingStruct) someThings;
    
        function create(bytes32 _id, string _name) {
            if (someThings[_id].id != "") throw;
            someThings[_id] = SomeThingStruct(_id, _name);
        }
        function getId(bytes32 _id) constant returns(bytes32) {
            return someThings[_id].id;
        }
    
        function getName(bytes32 _id) constant returns(string) {
            return someThings[_id].name;
        }
    }
    

Ethrerumのロジックは基本的には直列で処理されるため、上記のようにその場で存在確認して登録すれば、重複を確実に排除することができます。

補足

デプロイ時のコンパイルソースのdata部分が主な理由と考えられるため、フィールド部分を別コントラクトにして対応する方法も考えられますが、結果は下記の通りです。

  • ソースコード

    contract SomeThingFactory {
        mapping (bytes32 => SomeThing) someThings;
    
        function create(bytes32 _id, string _name) {
            someThings[_id] = new SomeThing(_id, _name);
        }
    
        function get(bytes32 _id) constant returns(address) {
            return address(someThings[_id]);
        }
    }
    contract SomeThing {
        bytes32 private id;
        string private name;
        function SomeThing(bytes32 _id, string _name) {
            id = _id;
            name = _name;
        }
        function getId() constant returns(bytes32) {
            return id;
        }
        function getName() constant returns(string) {
            return name;
        }
    }
    
  • SomeThingFactoryの生成とSomeThingFactory#createの実行

    Facroty実行結果

結局 200,247GAS 消費され、そもそも削減に寄与していないことが分かります。

別のコントラクト(SomeThingFactory)経由で別コントラクトを生成(new)した場合も、通常のデプロイと同様のGASが消費されます。

results matching ""

    No results matching ""