Warum ändert das Erstellen eines Arrays im Speicher innerhalb einer Methode den Status für etwas anderes?

Ich habe einen einfachen Vertrag, der ein festlegt, ownerwenn der Vertrag initialisiert wird, aber ich habe Probleme zu verstehen, warum er sich unter bestimmten Umständen ändert.

Ich habe 3 Möglichkeiten ausprobiert, ein Array zu initialisieren und festzulegen:

  1. Verwenden eines Arrays im Speicher
  2. Ein Speicherarray außerhalb einer Methode definieren und darauf pushen
  3. Definieren eines Speicherarrays innerhalb einer Methode und Pushen darauf

Die Fälle 1 und 2 verhalten sich wie erwartet, aber Fall 3 ändert schließlich den ownerWert und führt dazu, dass Tests fehlschlagen. Kann jemand Einblick in dieses Verhalten geben?

Intelligenter Vertrag:

pragma solidity ^0.4.4;

contract WeirdCase {

    address internal owner;
    uint256[] newArray;

    constructor() {
        owner = msg.sender;
    }

    function someMethod1() external {
        uint256[] memory newArray = new uint256[](10);
        for (uint256 i = 0; i < 10; i++) {
            newArray[i] = i;
        }
    }

    function someMethod2() external {
        for (uint256 i = 0; i < 10; i++) {
            newArray.push(i);
        }
    }

    function someMethod3() external {
        uint256[] storage weirdArray;
        for (uint256 i = 0; i < 10; i++) {
            weirdArray.push(i);
        }
    }

    function getOwner() view returns(address) {
        return owner;
    }
}

Testfall:

var WeirdCase = artifacts.require("./WeirdCase.sol");

contract('WeirdCase', function(accounts) {

  let weirdCase;

  beforeEach(async () => {
    weirdCase = await WeirdCase.new();
  });


  it("Case 1: succeeds", async function () {
    let beforeOwner = await weirdCase.getOwner();
    await weirdCase.someMethod1();

    let afterOwner = await weirdCase.getOwner();
    assert.equal(beforeOwner, afterOwner);
  });

  it("Case 2: succeeds", async function () {
    let beforeOwner = await weirdCase.getOwner();
    await weirdCase.someMethod2();

    let afterOwner = await weirdCase.getOwner();
    assert.equal(beforeOwner, afterOwner);
  });

  /*
   * DON'T KNOW WHY THIS FAILS!!!
   */
  it("Case 3: not sure why this fails", async function () {
    let beforeOwner = await weirdCase.getOwner();
    await weirdCase.someMethod3();

    let afterOwner = await weirdCase.getOwner();
    assert.equal(beforeOwner, afterOwner);
  });
});

Antworten (1)

Diese Zeile ist der Schlüssel:

uint256[] storage weirdArray;

Sie definieren weirdArrayals Zeiger auf ein Array im Speicher, aber Sie zeigen nie auf ein Array im Speicher. Daher weirdArraywird der Array-Zeiger als initialisiert 0x00.

Dadurch .push()schreibt der in den Speicherort 0x00, da die pushMethode davon ausgeht, dass dort das Array gespeichert ist. 0x00passiert, wo der Compiler Ihre ownerZustandsvariable platziert hat.

Das macht Sinn ... Ich denke, ich muss überdenken, wie man wann/wie dynamische Arrays oder Arrays im Speicher verwendet. Vielen Dank!