(Solidez) Herencia: ¿cómo agregar atributos adicionales a una estructura en el contrato base?

Este es un ejemplo muy simplificado pero, por supuesto, también se extiende a contratos más complicados, simplemente no he encontrado una solución elegante.

contract Group {
    struct Person {
        uint age;
        bytes32 name;
    }
    mapping (address => Person) members;
}

contract RockBand {
    struct Musician {
        uint age;
        bytes32 name;
        bytes32 instrument;
    }
    mapping (address => Musician) members;
}

contract FootballClub {
    struct Player {
        uint age;
        bytes32 name;
        bytes32 position;
    }
    mapping (address => Player) members;
}

Ahora tiene sentido para mí hacer una especie de 'biblioteca' de Group, y heredar de ella en los otros dos contratos. Pero no he encontrado una forma de modificar una estructura definida en un contrato secundario. Lo mejor que se me ocurre es:

contract Group {
    struct Person {
        uint age;
        bytes32 name;
    }
    mapping (address => Person) members;
}

contract RockBand is Group{
    struct MusicianExtra {
        bytes32 instrument;
    }
    mapping (address => MusicianExtra) membersMusicianExtra;
}

contract FootballClub is Group{
    struct PlayerExtra {
        bytes32 position;
    }
    mapping (address => PlayerExtra) membersFootbalExtra;
}

Esto es lo mismo que la funcionalidad anterior, pero requiere un mapeo adicional para la información adicional. También se volverá confuso y desordenado en contratos más grandes, y probablemente sea menos eficiente si necesita buscar en dos asignaciones en lugar de una para obtener la información.

Espero que alguien en la comunidad tenga alguna idea para mí.

¡Gracias! :)

Respuestas (1)

Veo a dónde vas con esto y por qué la lucha. En resumen, la herencia no funcionará con este enfoque. Lo fundamental es que las estructuras y las asignaciones (etc.) definen para siempre el diseño del almacenamiento, por lo que no es algo que una subclase pueda extender. En cambio, una subclase necesita lidiar con el almacenamiento tal como es, no como le gustaría que fuera. Espero que tenga sentido.

Hay más de una forma de abordar esto y me imagino que probablemente tengas algo más complejo que el ejemplo en mente. Aquí hay una idea general.

Considere aislar todos los elementos comunes en Personas y luego mantener relaciones con clases más especializadas. Algunas personas son miembros de la banda, y los miembros de la banda son siempre personas. He tenido cierto éxito usando contratos de almacenamiento de datos separados en una base de 1:1. Es decir, cada entidad (clase) tiene un contrato de almacenamiento. En mi opinión, el almacenamiento debería hacer cumplir la integridad referencial.

Algunas ideas y ejemplos: https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42

Otro enfoque es utilizar un diseño de almacenamiento abstracto utilizando pares clave/valor. Esto es empleado por el proyecto uPort de Consensys. La ventaja de usar pares clave/valor es que amplía los diseños de los documentos con más campos sobre la marcha. Algunos trabajos experimentales aquí: https://bitbucket.org/rhitchens2/soliditystoragepatterns/src/ec5997449f4d99a2357c3b134f8794a790660a59/GeneralizedCollection.sol?at=master&fileviewer=file-view-default . El diseño es básicamente: record key + field key refersTo value.

Los dos métodos se pueden combinar para formar un almacenamiento de documentos flexible con uniones forzadas y funciones de "carne y papas" a lo largo de las líneas de "búsqueda relacionada". generalizedCollection resuelve la actualización de detalles de diseño similares a esquemas en un escenario de contrato actualizable.

Espero eso ayude.