Implementación de interfaces y contratos abstractos

Estoy tratando de crear una jerarquía de herencia básica con formalismos abstractos/virtuales. Considere los siguientes dos contratos:
Contrato abstracto (IUser.sol):

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

Contrato Virtual (Usuario.sol):

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

Cuando trato de implementar ambos contratos, primero el IUser.sol y luego el User.sol, usando truffle, aparece el error "IUser no está definido". ¿Alguna sugerencia? Además, ¿cómo usamos las interfaces en 0.4.11 y las implementamos usando truffle migrate?

Respuestas (1)

No intenta implementar la interfaz abstracta contract IUser.

contract User is IUser {}

Usted implementa (migra) User. Otros contratos pueden usar la abstracción para comprender la interfaz con el Usuario. User is IUserlo protege de ciertos tipos de errores del desarrollador, como no poder definir una función en la interfaz.

Espero eso ayude.

Algunas aclaraciones para responder a los comentarios a continuación.

No puede implementar un contrato con una función abstracta (indefinida). Reaccionará de manera similar a una falla del constructor y no se implementará.

Contratos abstractos (también conocidos como interfaz) para mantener bajos los gastos generales cuando los contratos necesitan comunicarse. Es cuestión de gustos, pero me ha resultado útil que las implementaciones hereden de las interfaces como forma de detectar errores.

Considere un par de contratos grandes para una tienda y un transportista que necesitan comunicarse. Por ejemplo, la tienda necesita organizar el envío. Esto sería enorme:

import "./Shipping.sol";

contract Store {

  Shipping s;

  ...
}

De hecho, si uno aborda las cosas de esta manera, el bloque gasLimit será un problema durante el despliegue. Buenas noticias: la tienda no necesita conocer el funcionamiento interno del contrato de envío, solo la interfaz. Entonces ...

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

contract Store {

  ShippingInterface s;
  ...
}

En el primer caso, Store hereda todo el bytecode para Shipping. En el segundo caso, hereda solo la información ABI crítica, por lo que es mucho más pequeño. En ambos casos, el contrato puede ser instanciado por el constructor o alguna otra función.

Esto funcionará:

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

pero también lo hará este (segundo caso)

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

La segunda forma es mucho más compacta. Tenga en cuenta que en ambos casos se implementa un contrato de envío real . Los métodos difieren solo en la forma en que se informa a Store al respecto.

Como cuestión de estilo, puede ser útil que el compilador informe sobre las incoherencias que se introducen en el código a medida que avanza. Este estilo funciona en muchos casos.

Envios.sol

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

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

Tienda.sol

import "./Shipping.sol";

contract Store {

  ShippingInterface s; 
  ...
}

Implementarías un envío y una tienda. Nunca implementaría una interfaz de envío: es solo una forma de describir la interfaz real. Y el compilador se quejará si hay algo descrito en la interfaz y no está definido en el contrato que está tratando de implementar, lo cual es bueno.

Espero eso ayude.

¡Esto es útil! Gracias por la actualización. Tengo otra pregunta relacionada. Cuando traté de implementar un contrato que se hereda de otro contrato (que tiene modificadores) y obtengo un error de "no se pudo almacenar el código del contrato. Verifique la cantidad de gas". ¿Alguna sugerencia?
Parece que el constructor decidió throw. Intente implementarlo manualmente y solucione los problemas desde allí, supongo.
gracias, para no mezclar las preguntas, publicaré esto como una pregunta separada en el foro
@skarred14: ¿lo solucionaste? Tengo un problema similar con la migración de trufas, arroja un código de contrato que no se pudo almacenar cuando intento implementar un contrato que implementa una interfaz
@szerte según lo que entiendo hasta ahora, no se puede implementar en la plataforma Ethereum; lo son más para la gobernanza en torno al mantenimiento de los contratos inteligentes. Asegurar que un contrato se herede de un contrato abstracto ayuda a prevenir el desarrollo erróneo y la inclusión/exclusión de funcionalidades
@skarred14: gracias. Creo que entendí para qué sirven, acabo de recibir este mensaje de error de truffle y no pude entender el motivo. Pero ahora está ordenado, en realidad no implementé (correctamente) una de las funciones abstractas. El mensaje de error de trufa no es realmente útil. Consulte también: github.com/trufflesuite/truffle/issues/522