Almacenar datos en mapeo vs matriz

Veo que hay algunos ejemplos de Solidity que se usan mappingpara almacenar el estado, y algunos usan arrays.

Por ejemplo, este ejemplo está usando mapeo:

struct Campaign {
   ....
}
uint numCampaigns;
mapping (uint => Campaign) campaigns;

y hay una matriz:

Proposal[] public proposals;
struct Proposal {
   ....
}

Entiendo que hay un patrón un poco diferente para agregar un nuevo valor, básicamente porque las matrices tienen el .lengthatributo. Al menos si estamos comparando con mapping (uint => ...). Eso es todo lo que veo, ¿tal vez me estoy perdiendo algo?

Digamos que tengo un patrón similar: un contrato que opera algunas estructuras/documentos (el contrato tiene funciones para agregar y actualizar dichos documentos). Podría haber una cantidad ilimitada de documentos procesados ​​por contrato. Mi instinto me dice que debería usar mappingallí, pero no puedo encontrar ninguna prueba. Así que mi pregunta es cuál elegir y cuándo.

Respuestas (3)

mappinggeneralmente se recomienda. Para este caso de uso de un contrato, que podría tener un número ilimitado de documentos, que podrían actualizarse, la recomendación se mantiene.

La principal ventaja de una matriz es para la iteración. Pero la iteración debe limitarse, no solo por la velocidad, sino potencialmente por la seguridad. Como ejemplo extremo, se podría infligir una Denegación de servicio permanente en un contrato si su servicio implica iterar sobre una matriz que un atacante puede llenar, de modo que el costo de iteración y operación supere permanentemente el límite de gas del bloque.

Un comentario de @PaulS sugiere que iterar una matriz de longitud 50 es relativamente eficiente; Se recomienda probar los casos de uso para identificar también detalles como los costos de gas deseados o aceptables.

Tenga en cuenta que, para mayor claridad, no se deben intentar reemplazar todos los arreglos con asignaciones: las asignaciones solo se pueden usar para datos almacenados .

¿Cuál es una buena manera de evitar el problema de DoS si aún necesita una iteración?
@eth ¿Puede comentar por qué se recomiendan las asignaciones?
@ComandanteCheth ¿Qué parte de esta respuesta necesita aclaración? También puede usar tanto un mapeo como una matriz: el principal peligro a tener en cuenta con una matriz es iterar demasiado.
@Raine: podría tener una función que tome un índice de inicio y siempre itere una cantidad fija de veces, por lo que se usan múltiples transacciones con un índice de inicio diferente.

Este es un problema de diseño específico de su aplicación. ¿Qué tendrá que hacer con los documentos? Por ejemplo, si necesita obtener un documento específico para realizar una actualización, una asignación será mucho más fácil que recorrer una serie de documentos. Almacenar documentos por alguna identificación facilitaría esto:

mapping(uint256 => Document);
Hago algunas búsquedas y muchas reducciones en mi aplicación. Así que uso los dos al mismo tiempo. Uso una matriz para la iteración y un mapa para la búsqueda. En realidad, las caminatas O (n) son bastante eficientes para < 50 de longitud, por lo que un mapeo podría ser excesivo.

Todo se reduce al hecho de que está utilizando arreglos para almacenar estos documentos y esos arreglos crecen sin límites y debido a que siempre va a iterar a lo largo de sus arreglos, es posible que termine gastando una enorme cantidad de gasolina. solo para buscar algún documento dado dentro de la matriz de propuestas.

Para resolver este problema, deje de usar matrices por completo dentro de su contrato y, en su lugar, use una estructura de datos ligeramente diferente.

La estructura de datos que debe usar para almacenar todas estas propuestas, en lugar de ser una matriz, será un mapeo.

Un mapeo es un tipo de referencia que está disponible para nosotros dentro de Solidity. Una asignación es como una colección de pares clave/valor, por lo que es similar a un objeto de JavaScript, pero existen algunas diferencias discretas y definidas entre una asignación y un objeto de JavaScript.

Entonces, ¿por qué un mapeo va a resolver su problema?

Todo se reduce al tiempo de búsqueda de cada una de estas estructuras de datos. En la disciplina de Ciencias de la Computación, cada vez que estamos tratando de encontrar algún dato dentro de una matriz, el mejor caso que podemos obtener para ejecutar esa búsqueda es Linear Time. Cuando decimos que la búsqueda dentro de la matriz es un tiempo lineal, eso significa que por cada registro adicional que agreguemos a esta matriz, llevará una cantidad de tiempo ligeramente mayor ejecutar la búsqueda.

Si tenemos 100 elementos en la matriz, puede tardar 100 segundos. En otras palabras, el tamaño de la matriz determina cuánto tiempo llevará la búsqueda.

Eso es lo que lo va a meter en problemas con los precios de la gasolina si opta por arreglos.

La gran diferencia entre una matriz y un mapeo es que hacer una búsqueda dentro de un mapeo es lo que se llama en la disciplina de Ciencias de la Computación, Tiempo Constante.

Cuando decimos tiempo constante, significa que no importa cuántos datos almacenemos dentro de este mapeo, siempre tomará la misma cantidad de tiempo. Entonces, si tenemos una propuesta, tomará un segundo, pero si tenemos mil propuestas, solo tomará un segundo iterar a través de estas propuestas.

Claramente, definitivamente querrá usar el mapeo aquí.