Solidity Smart Contract geerbte Funktionsausgabe fehlgeschlagen

Ich versuche, eine Funktion vom übergeordneten Vertrag in den untergeordneten Vertrag zu erben, und es funktioniert einwandfrei in der Remix-JavaScript-VM. Folgende Schritte habe ich gemacht:

  1. Den übergeordneten Vertrag in der Remix-JavaScript-VM bereitgestellt.
  2. einige zufällige Werte gespeichert, indem die storeValueFunktion aus dem übergeordneten Vertrag ausgeführt wurde
  3. kopierte die Adresse des übergeordneten Vertrags und instanziierte sie im untergeordneten Vertrag. Wenn ich nun die getValueFunktion aus dem untergeordneten Vertrag aufrufe, die im Grunde die Funktion zum Abrufen gespeicherter Werte aus dem übergeordneten Vertrag aufruft, ist die Ausgabe ein Array von Werten und alles funktioniert einwandfrei .


ABER

Wenn ich beide Verträge auf der privaten Blockchain bereitstelle, erhalte ich ein leeres Array von Werten. Ich habe folgende Schritte gemacht:

  1. startete die private Blockchain (Geth-Client)
  2. Ändern Sie die Umgebung im Remix auf Web3 Provider
  3. Stellen Sie den WEB3DEPLOY-Code von Remix in der privaten Kette bereit und kopieren Sie die Adresse der abgebauten Adresse aus der privaten Kette
  4. verwendet die Adresse, um den übergeordneten Vertrag im untergeordneten Vertrag zu instanziieren
  5. wiederholte den Bereitstellungsprozess für den untergeordneten Vertrag
  6. füttern Sie die Werte mit web3.py im Python-Jupyter-Notebook


Wenn ich jetzt die Funktion direkt accountTxvom übergeordneten Vertrag im Frontend aufrufe, funktioniert sie einwandfrei. Aber wenn ich die geerbte Funktion getValuevom untergeordneten Vertrag im Frontend aufrufe, ist das Ergebnis ein leeres Array.
Das Problem ist also, dass ich die Ausgabe der Funktion getValue, die die Funktion aufruft, nicht von einem anderen Vertrag erhalten kann, wenn sie in einer privaten Kette bereitgestellt wird. Aber es funktioniert gut in Remix JavaScript VM.
Elternvertrag:

pragma solidity ^0.4.20;

contract Parent {

    uint256[] values;
    mapping (address => uint256[])transactions;


    function storeValue(uint256 _value) {

        transactions[msg.sender].push(_value);
    }

    function accountTx(address addr) constant returns(uint256[]) {

        return (transactions[addr]);
    }

}


Kindervertrag:

pragma solidity ^0.4.20;

import './Parent.sol';


contract Child {

  /* instantiating parent contract*/
  Parent p = Parent(0x9dd1e8169e76a9226b07ab9f85cc20a5e1ed44dd);


   function getValue() public view returns (uint256[]){
      return p.accountTx(msg.sender);
  }

}

Ich habe die Instanz des übergeordneten Vertrags als global erstellt, weil ich sie für einige Funktionen verwenden möchte.
Fehlt so etwas wie die Funktion als zu deklarieren external? Jede Anleitung wäre auf jeden Fall dankbar, danke.

Antworten (1)

Ich vermute, Sie missverstehen vielleicht die Vererbung von "dem Vertrag".

Es gibt zwei verschiedene Ideen, die ähnlich aussehen. Betrachten wir sie:

  1. Es gibt einen Vertrag A und einen Vertrag B und sie müssen kommunizieren. A ist nicht B und B ist nicht A, aber A braucht genügend Informationen über B, um mit ihm kommunizieren zu können, und umgekehrt.
  2. Es gibt einen wiederverwendbaren Code, der sich mit einem Problem auf niedriger Ebene befasst. Es ist praktisch, es in viele Verträge zu importieren, damit sie die Logik „erben“ können.

Das sind zwei völlig getrennte Anliegen.

Sie könnten ein wiederverwendbares Stück Code erstellen (absichtlich unvollständig, um die Dinge auf den Punkt zu bringen):

Stoppbar.sol

contract Stoppable {

    bool public isRunning;

    modifier onlyIfRunning {
        require(isRunning);
        _;
    }

    function Stoppable() public {
        isRunning = true;
    }

    function setRunSwitch(bool newSetting) public returns(bool contractRunning) {
        isRunning = newSetting;
    }
}

Großartig. Wenn wir nun wollen, dass A oder B stoppbar sind, fügen wir einfach contract A is Stoppable {...den onlyIfRunningModifikator zu den zustandsändernden Funktionen hinzu, die wir schützen möchten. Aerhält sowohl die Zustandsvariable isRunningals auch die Funktion setRunSwtich(), da sie den Code erbt und ihr Konstruktor immer dann ausgeführt wird, wenn eine Abereitgestellt wird.

Betrachten Sie nun den anderen Fall. Bmöchte etwas darüber inspizieren Aoder Beine Transaktion an senden A. Hier geht es nicht um Erbschaft. Hier geht es darum, dass B genug Informationen hat, um mit einer Instanz A zu sprechen.

B braucht

  1. Die Funktionssignaturen von A
  2. Die Adresse einer Instanz von A (wo wurde sie bereitgestellt?)

A.sol

contract A {

  bytes32 public something;

  function setSomething(bytes32 newThing) public {
    something = newThing;
  }
}

B.sol

contract B {

  A a; // Type A (source available in the contract above), called "a"

  function B(address aAddress) public { // inform B where it can find an instance of A
    a = A(aAddress);
  }

  function getSomethingFromA() public view returns(bytes32 theThing) {
    return a.something();
  }
}

Das wird zunächst nicht kompiliert, weil Aes nicht definiert ist. In B.soldir würde

import "./A.sol"; 

Das ist so, dass der Compiler es sehen und die Schnittstelleninformationen herausfinden kann, die B benötigt. Beachten Sie, dass wir nichts wie sagen B is A.

Falls das Vorstehende zu abstrakt ist, ziehen Sie ein System von Konzertkarten, Bands, Veranstaltungsorten und Veranstaltungen in Betracht, die jeweils in einer Reihe von ineinandergreifenden Verträgen vertreten sind. Es kann ratsam sein, die Verträge einen gemeinsamen Satz von Berechtigungen und Admin-Verträgen erben zu lassen, wie die Stoppable-Idee. Ineinandergreifende Verträge wie Events könnten Bands und Veranstaltungsorte inspizieren, um zu bestätigen, dass die Dinge sinnvoll sind, daher benötigen sie ein wenig Wissen über Schnittstellen und Aufenthaltsort.

Es erscheint nicht sinnvoll zu sagen, Event ist Venue oder Venue is Band. Wenn es anfängt, sich so zu verdrehen, ist das ein Zeichen dafür, dass das Erbe missbraucht wird.

Ich hoffe es hilft.