2017-12-25 21 views
0

私は最初のEth契約をプログラミングしていますが、私は問題に直面しています。buyメソッドのガス消費量は本当に高くなります(「最大ガス - あなたが所有できる複数のゾーンを持つ地図(2Dマップ)があります(ここではユニットと呼ばれています。これが私が "unitsToState"を維持する理由です) "明らかなマッピング)。 - 隣接する複数のゾーンを一度に購入することができるため、「ブロック」が作成されます。 - 新しいブロックを購入するとき、契約は内部のすべてのユニットが空であるかどうかを確認する必要があります(unitsToState [x] == 0)。ブロックを購入すると、これらの状態は1に設定されます。あまりにも多くのガス消費

私はこの問題が主に「Solidity」の悪いアルゴリズムプログラミングであると推測していますので、あまり詳しく説明しません。

この方法は、小ゾーンを表すX、Y、X、YからYまでのarround 500kガスで実行することができますが、遠く離れているとガス見積もり中に「Maximum gas allowance exceeded」エラー...だから、本当に私は問題があると思います。..

`` ` ...

struct Block { 
    address owner; 
    uint fromX; 
    uint fromY; 
    uint toX; 
    uint toY; 
    string imageUrl; 
    string redirectUrl; 
    string text; 
    bool removed; 
} 

uint size = 100; 
mapping (uint => uint) unitsToState; 
Block[] public blocks; 
uint public areaPrice; 
uint public areaPerUnit; 

... 


function buy(uint fromX, uint fromY, uint toX, uint toY, string imageUrl, string redirectUrl, string text) payable public { 
    require(fromX >= 0); 
    require(fromY >= 0); 
    require(fromX <= toX); 
    require(fromY <= toY); 
    require(toX < size); 
    require(toY < size); 

    // Here do check of collisions. 
    for (uint i = fromX; i <= toX; i++) { 
     for (uint j = fromY; j <= toY; j++) { 
      require(getUnitsToState(i*size*size + j) == 0); 
     }  
    } 

    uint width = toX - fromX + 1; 
    uint height = toY - fromY + 1; 
    uint areaCount = width * height * areaPerUnit; 
    uint price = areaCount * areaPrice; 
    require(msg.value >= price); 

    Block memory b = Block(
     msg.sender, 
     fromX, 
     fromY, 
     toX, 
     toY, 
     imageUrl, 
     redirectUrl, 
     text, 
     false 
    ); 
    blocks.push(b); 

    // Registrer units states. 
    for (i = fromX; i <= toX; i++) { 
     for (j = fromY; j <= toY; j++) { 
      unitsToState[i*size*size + j] = 1; 
     }  
    } 
} 

... 

` ``

答えて

0
特にネストされたループと

大きなループ、ソリディティに危険です。各反復でどの論理を実行しているのか注意する必要があります。

あなたのケースでは、それはガス使用量の巨大なスパイクを引き起こしているunitsToStateフラグを設定している2番目のループです。ゼロ以外のデータを格納する呼び出しには、2万のガス(ゼロの場合は5,000)がかかります。ループが繰り返されるたびにそのコストが発生します。

Block構造体の内部で衝突チェックを行う必要があるようです。あなたはそれを使うことができますか?

for (uint8 i = 0; i < blocks.length; i++) { 
    Block storage bTest = blocks[i]; 

    bool xIntersect = int(fromX) - int(bTest.toX) <= 0 && int(toX) - int(bTest.fromX) >= 0; 
    bool yIntersect = int(fromY) - int(bTest.toY) <= 0 && int(toY) - int(bTest.fromY) >= 0; 

    require (!(xIntersect && yIntersect)); 
} 

ガス代はAppendix G of the yellow paperを参照してください。

+0

返信いただきありがとうございます。しかし、ブロック領域は長さが10,000にもなる可能性があります...それは長期的に実際のコードよりもコストがかかりませんか?実際のロジックは、多くのガスが消費されますが、一定のガス消費量です。あなたのポイント ? – NathanVss

+0

あなたのご意見が分かりません。ブロックサイズが大きくなればなるほど、このアプローチはより効率的になるはずです。あなたのバージョンは、衝突するユニットが見つかるまで検索します。私が投稿したものは、ブロックレベルで、xとyの範囲が要求されているものと重複していないかどうかを調べます。いずれにしても、私の元のコメントで述べたように、ガス使用量の最大のヒットは、ループ内で 'unitsToState [i * size * size + j] = 1;'です。購入した10,000個の1x1ブロック(最悪の場合)を使って投稿したバージョンをテストして、それが実行されているかどうかを確認してください。 –

+0

うん、私はそれを試み、後に私のコストを更新します。 1つの質問ですが、なぜ "ブロックストレージbTest"を宣言するときにキーワード "storage"を入れましたか? – NathanVss

関連する問題