Bereitstellung abstrakter Verträge und Schnittstellen

Ich versuche, eine grundlegende Vererbungshierarchie mit abstrakten/virtuellen Formalismen zu erstellen. Betrachten Sie die folgenden zwei Verträge:
Abstrakter Vertrag (IUser.sol):

contract IUser {
    function addUser (address a) returns (bool) {}
}

Virtueller Vertrag (User.sol):

import "./IUser.sol";  
contract User {
    address[] userList;
    function addUser (address a) returns (bool) {
        userList.push(a);
    }

Wenn ich versuche, beide Verträge bereitzustellen, zuerst die IUser.sol und dann die User.sol, mit Truffle, erhalte ich die Fehlermeldung "IUser ist nicht definiert". Irgendwelche Vorschläge? Außerdem, wie verwenden wir Schnittstellen in 0.4.11 und stellen sie mit Truffle Migration bereit?

Antworten (1)

Sie versuchen nicht, die abstrakte Schnittstelle bereitzustellen contract IUser.

contract User is IUser {}

Sie implementieren (migrieren) User. Andere Verträge können die Abstraktion verwenden, um die Schnittstelle zum Benutzer zu verstehen. User is IUserschützt Sie vor bestimmten Arten von Entwicklerfehlern wie dem Versäumnis, eine Funktion in der Benutzeroberfläche zu definieren.

Ich hoffe es hilft.

Einige Klarstellungen, um auf die Kommentare unten zu antworten

Sie können keinen Vertrag mit einer abstrakten (undefinierten) Funktion bereitstellen. Es reagiert ähnlich auf einen Konstruktorfehler und wird nicht bereitgestellt.

Abstrakte (auch als Schnittstelle bezeichnete) Verträge, um den Overhead niedrig zu halten, wenn Verträge kommunizieren müssen. Es ist Geschmackssache, aber ich habe es für Implementierungen als nützlich empfunden, von Schnittstellen zu erben, um Fehler abzufangen.

Betrachten Sie ein Paar umfangreicher Verträge für ein Geschäft und einen Spediteur, die kommunizieren müssen. Beispielsweise muss der Laden den Versand arrangieren. Das wäre riesig:

import "./Shipping.sol";

contract Store {

  Shipping s;

  ...
}

In der Tat, wenn man die Dinge auf diese Weise angeht, wird das Blockgaslimit während des Einsatzes ein Problem sein. Gute Nachrichten: Der Shop muss nicht die internen Abläufe des Versandvertrags kennen, sondern nur die Schnittstelle. So ...

contract ShippingInterface {
  function shipStuff(bytes32 itemId, uint qty, bytes32 streetAddressId) public returns(bytes32 waybillId);
}

contract Store {

  ShippingInterface s;
  ...
}

Im ersten Fall erbt Store den gesamten Bytecode für den Versand. Im zweiten Fall erbt es nur die kritischen ABI-Informationen, ist also viel kleiner. In beiden Fällen kann der Vertrag vom Konstruktor oder einer anderen Funktion instanziiert werden.

Das wird funktionieren:

function Store(address shippingContract) public {
  Shipping s = Shipping(shippingContract);
}

aber so wird dies (zweiter Fall)

function Store(address shippingContract) public {
  ShippingInterface s = ShippingInterface(shippingContract);
}

Der zweite Weg ist viel kompakter. Beachten Sie, dass in beiden Fällen ein tatsächlicher Versandvertrag bereitgestellt wird. Die Methoden unterscheiden sich nur darin, wie Store darüber informiert wird.

Aus Stilgründen kann es praktisch sein, wenn der Compiler Inkonsistenzen meldet, die sich während der Arbeit in den Code einschleichen. Dieser Stil funktioniert in vielen Fällen.

Versand.sol

contract ShippingInterface {
  function doStuff() ... ;
}

contract Shipping is ShippingInterface {
  function doStuff() .. { // define it }
}

Store.sol

import "./Shipping.sol";

contract Store {

  ShippingInterface s; 
  ...
}

Sie würden einen Versand und einen Shop bereitstellen. Sie würden niemals ein ShippingInterface bereitstellen – es ist nur eine Möglichkeit, die Schnittstelle zur Realität zu beschreiben. Und der Compiler wird sich beschweren, wenn etwas in der Schnittstelle beschrieben ist und es nicht in dem Vertrag definiert ist, den Sie bereitzustellen versuchen, was eine gute Sache ist.

Ich hoffe es hilft.

Das ist hilfreich! Danke für das Update - ich habe eine andere verwandte Frage. Als ich versuchte, einen Vertrag bereitzustellen, der von einem anderen Vertrag (mit Modifikatoren) erbt, erhalte ich die Fehlermeldung „Vertragscode konnte nicht gespeichert werden. Bitte überprüfen Sie die Gasmenge“. Irgendwelche Vorschläge?
Klingt so, als hätte sich der Konstrukteur dafür entschieden throw. Versuchen Sie, es manuell bereitzustellen, und beheben Sie von dort aus, denke ich.
danke - um die Fragen nicht zu vermischen, werde ich dies als separate Frage im Forum posten
@skarred14: hast du das sortiert? Ich habe ein ähnliches Problem mit der Truffle-Migration, es löst einen Vertragscode aus, der nicht gespeichert werden konnte, wenn ich versuche, einen Vertrag bereitzustellen, der eine Schnittstelle implementiert
@szerte kann nach meinem bisherigen Verständnis nicht auf der Ethereum-Plattform bereitgestellt werden - sie dienen eher der Governance rund um die Wartung der Smart Contracts. Das Sicherstellen, dass ein Vertrag von einem abstrakten Vertrag geerbt wird, hilft, eine fehlerhafte Entwicklung und das Einschließen/Ausschließen von Funktionalitäten zu verhindern
@skarred14: danke. Ich glaube, ich habe verstanden, wofür sie sind, ich hatte gerade diese Fehlermeldung von Truffle und konnte den Grund nicht herausfinden. Aber es ist jetzt sortiert, ich habe tatsächlich eine der abstrakten Funktionen nicht (richtig) implementiert. Trüffel-Fehlermeldung ist nicht wirklich nützlich. Siehe auch: github.com/trufflesuite/truffle/issues/522