La organización de datos simple y apropiada puede desafiar a los recién llegados a Solidity. Quiere que organicemos todo de formas a las que muchos de nosotros no estamos acostumbrados.
¿Existen patrones generales bien resueltos para la organización rutinaria de datos en cadena?
Aquí hay algunos patrones simples y útiles en orden creciente de utilidad.
Los registros de eventos se omiten por brevedad. En la práctica, es deseable emitir eventos para cada cambio de estado importante.
Lista simple usando matriz
Fortalezas
debilidades
Ejemplo:
pragma solidity ^0.4.6;
contract simpleList {
struct EntityStruct {
address entityAddress;
uint entityData;
// more fields
}
EntityStruct[] public entityStructs;
function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
EntityStruct memory newEntity;
newEntity.entityAddress = entityAddress;
newEntity.entityData = entityData;
return entityStructs.push(newEntity)-1;
}
function getEntityCount() public constant returns(uint entityCount) {
return entityStructs.length;
}
}
Mapeo con Struct
Fortalezas
debilidades
Ejemplo:
contract mappingWithStruct {
struct EntityStruct {
uint entityData;
bool isEntity;
}
mapping (address => EntityStruct) public entityStructs;
function isEntity(address entityAddress) public constant returns(bool isIndeed) {
return entityStructs[entityAddress].isEntity;
}
function newEntity(address entityAddress, uint entityData) public returns(bool success) {
if(isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
entityStructs[entityAddress].isEntity = true;
return true;
}
function deleteEntity(address entityAddress) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
entityStructs[entityAddress].isEntity = false;
return true;
}
function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
return true;
}
}
Matriz de estructuras con identificadores únicos
Fortalezas
debilidades
Ejemplo:
contract arrayWithUniqueIds {
struct EntityStruct {
address entityAddress;
uint entityData;
}
EntityStruct[] public entityStructs;
mapping(address => bool) knownEntity;
function isEntity(address entityAddress) public constant returns(bool isIndeed) {
return knownEntity[entityAddress];
}
function getEntityCount() public constant returns(uint entityCount) {
return entityStructs.length;
}
function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
if(isEntity(entityAddress)) revert();
EntityStruct memory newEntity;
newEntity.entityAddress = entityAddress;
newEntity.entityData = entityData;
knownEntity[entityAddress] = true;
return entityStructs.push(newEntity) - 1;
}
function updateEntity(uint rowNumber, address entityAddress, uint entityData) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
if(entityStructs[rowNumber].entityAddress != entityAddress) revert();
entityStructs[rowNumber].entityData = entityData;
return true;
}
}
Estructuras asignadas con índice
Fortalezas
debilidades
Ejemplo:
contract MappedStructsWithIndex {
struct EntityStruct {
uint entityData;
bool isEntity;
}
mapping(address => EntityStruct) public entityStructs;
address[] public entityList;
function isEntity(address entityAddress) public constant returns(bool isIndeed) {
return entityStructs[entityAddress].isEntity;
}
function getEntityCount() public constant returns(uint entityCount) {
return entityList.length;
}
function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
if(isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
entityStructs[entityAddress].isEntity = true;
return entityList.push(entityAddress) - 1;
}
function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
return true;
}
}
Estructuras asignadas con índice habilitado para eliminar
Fortalezas
debilidades
ACTUALIZACIÓN, 2019
Este patrón está disponible como biblioteca para Solidity 0.5.1: https://medium.com/@robhitchens/solidity-crud-epilogue-e563e794fde , https://github.com/rob-Hitchens/UnorderedKeySet
Ejemplo:
contract mappedWithUnorderedIndexAndDelete {
struct EntityStruct {
uint entityData;
uint listPointer;
}
mapping(address => EntityStruct) public entityStructs;
address[] public entityList;
function isEntity(address entityAddress) public constant returns(bool isIndeed) {
if(entityList.length == 0) return false;
return (entityList[entityStructs[entityAddress].listPointer] == entityAddress);
}
function getEntityCount() public constant returns(uint entityCount) {
return entityList.length;
}
function newEntity(address entityAddress, uint entityData) public returns(bool success) {
if(isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
entityStructs[entityAddress].listPointer = entityList.push(entityAddress) - 1;
return true;
}
function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
entityStructs[entityAddress].entityData = entityData;
return true;
}
function deleteEntity(address entityAddress) public returns(bool success) {
if(!isEntity(entityAddress)) revert();
uint rowToDelete = entityStructs[entityAddress].listPointer;
address keyToMove = entityList[entityList.length-1];
entityList[rowToDelete] = keyToMove;
entityStructs[keyToMove].listPointer = rowToDelete;
entityList.length--;
return true;
}
}
Este último tiene una explicación aquí: https://medium.com/@robhitchens/solidity-crud-part-2-ed8d8b4f74ec#.ekc22r5lf
Ejemplo de árbol de carpetas: ¿Cómo podemos organizar el almacenamiento de una carpeta o un árbol de objetos en Solidity?
El ejemplo de lista enlazada muestra una forma de mantener una lista ordenada usando una biblioteca. https://github.com/ethereum/dapp-bin/blob/master/library/linkedList.sol 0
Agregando a la respuesta de Rob, use revert() como una alternativa de throw. Desde la versión 0.4.13, la palabra clave throw está obsoleta y se eliminará gradualmente en el futuro. Lea aquí para más información: exigir, afirmar y revertir en solidez.
Entonces, como ejemplo, deberías cambiar
if(isEntity(entityAddress)) throw;
a
if(isEntity(entityAddress)) revert();
en el código anterior proporcionado por Rob.
revert()
: ethfiddle.com/PgDM-drAc9require()
pero eso significaría invertir todas las reglas... if(bad) revert()
=>require(!bad)
throw
y revert()
? ¿Hacen lo mismo, revirtiendo todos los estados? @Abhishek Sinha && @Rob Hitchenssolc 0.4.13
, y obsoleto . revert
_ Se diferencian ligeramente del original en detalles como la destrucción de gas. Echa un vistazo aquí: ethereum.stackexchange.com/questions/15166/…require
assert
throw
throw
Gran respuesta de Rob Hitchens . Me gustaría señalar un cambio de ruptura menor en el código mencionado. En newEntity
función del simpleList
contrato, el autor ha utilizadoreturn entityStructs.push(newEntity)-1;
Desde la versión 0.6.0 de Solidity, la función array.push() no devuelve nada. Consulte la respuesta aquí: https://ethereum.stackexchange.com/a/87791/73743 . Entonces, la return entityStructs.push(newEntity)-1;
parte del código rompe el contrato inteligente.
array--
ha sido reemplazado por .pop
, por ejemplo.
pablo s
Rob Hitchens