Inspirado en la colección de basura
Un patrón de almacenamiento jerárquico de objetos dentro de objetos es un dispositivo bastante común. ¿Cómo podría uno organizar tal cosa y evitar problemas con el aumento del costo del gas a escala?
En el espíritu de ¿Existen patrones de almacenamiento sencillos y bien resueltos para Solidity? .
Este es un poco más complicado, pero parece un patrón reutilizable. La estructura básica de cada nodo es:
Este patrón intenta eliminar las operaciones de búsqueda ilimitadas en el contrato empujando la mayoría de las funciones recursivas/loco hacia el lado del cliente. Un nodo se puede validar (existe) en un solo movimiento. Las búsquedas y las inserciones utilizan una "pista" que debe estar "aproximadamente" cerca del punto de inserción o la solución. El contrato resolverá la ubicación exacta en la lista ordenada. La sugerencia ayuda a reducir el costo de la gasolina para búsquedas potencialmente costosas. Cuanto mejor sea la pista, menor será el costo.
El patrón admite la poda de ramas y su contenido a cualquier escala con un costo de gas constante y bajo.
En el caso de que un cliente quiera validar que un nodeId no está dentro de una rama podada, el cliente debe explorar recursivamente los padres hasta que se encuentre el padre "raíz" (tiene padre == 0) y confirmar que isNode == true . .. de lo contrario, la clave para verificar está dentro de una rama podada.
Ejemplo:
pragma solidity ^0.4.6;
// Simple, Scalable Object Tree
// Supports top-down tree exploration
// and pruning of branches.
// Random node membership can be confirmed client-side.
// Crawl parents recursively and confirm root node (parent=0) isNode==true.
// Not the case for members of pruned branches.
contract ObjectTree {
bytes32 public treeRoot;
struct NodeStruct {
bool isNode;
bytes32 parent; // the id of the parent node
uint parentIndex; // the position of this node in the Parent's children list
bytes32[] children; // unordered list of children below this node
// more node attributes here
}
mapping(bytes32 => NodeStruct) public nodeStructs;
event LogNewNode(address sender, bytes32 nodeId, bytes32 parentId);
event LogDelNode(address sender, bytes32 nodeId);
function ObjectTree() {
treeRoot = newNode(0);
}
function isNode(bytes32 nodeId)
public
constant
returns(bool isIndeed)
{
return nodeStructs[nodeId].isNode;
}
function newNode(bytes32 parent)
public
returns(bytes32 newNodeId)
{
if(!isNode(parent) && parent > 0) throw; // zero is a new root node
newNodeId = sha3(parent, msg.sender, block.number);
NodeStruct memory node;
node.parent = parent;
node.isNode = true;
// more node atributes here
if(parent>0) {
node.parentIndex = registerChild(parent,newNodeId);
}
nodeStructs[newNodeId] = node;
LogNewNode(msg.sender, newNodeId, parent);
return newNodeId;
}
/*
Depends entirely on the attributes you want to store in the nodes
function updateNode(bytes32 nodeId, attr ... )
public
returns(bool success)
{
nodeStructs[nodeId].attrib = attrib];
Log ...
return true;
}
*/
function registerChild(bytes32 parentId, bytes32 childId)
private
returns(uint index)
{
return nodeStructs[parentId].children.push(childId) - 1;
}
// Invalidates and detaches node to prune.
// Does not invalidate recursively (scalability).
// Top-Down crawl will avoid pruned branches.
// Bottom-Up validation will find apparent "root" isNode==false.
function pruneBranch(bytes32 nodeId)
public
returns(bool success)
{
bytes32 parent = nodeStructs[nodeId].parent;
uint rowToDelete = nodeStructs[nodeId].parentIndex;
uint rowToMove = nodeStructs[parent].children.length-1; // last child in the list
nodeStructs[parent].children[rowToDelete] = nodeStructs[parent].children[rowToMove];
nodeStructs[nodeStructs[parent].children[rowToMove]].parentIndex = rowToMove;
nodeStructs[parent].children.length--;
nodeStructs[nodeId].parent=0;
nodeStructs[nodeId].parentIndex=0;
nodeStructs[nodeId].isNode = false;
LogDelNode(msg.sender, nodeId);
return true;
}
function getNodeChildCount(bytes32 nodeId)
public
constant
returns(uint childCount)
{
return(nodeStructs[nodeId].children.length);
}
function getNodeChildAtIndex(bytes32 nodeId, uint index)
public
constant
returns(bytes32 childId)
{
return nodeStructs[nodeId].children[index];
}
}
Espero eso ayude.
tjaden hess