Comprobaciones de solidez-Efectos-Patrón de interacciones

De los documentos de solidez :

Utilice el patrón de comprobaciones-efectos-interacciones La mayoría de las funciones primero realizarán algunas comprobaciones (quién llamó a la función, si los argumentos están dentro del rango, si enviaron suficiente Ether, si la persona tiene tokens, etc.). Estas comprobaciones deben hacerse primero.

Como segundo paso, si todas las comprobaciones pasaron, se deben realizar efectos a las variables de estado del contrato actual. La interacción con otros contratos debe ser el último paso en cualquier función.

Los primeros contratos retrasaron algunos efectos y esperaron que las llamadas a funciones externas regresaran en un estado sin errores. Esto suele ser un error grave debido al problema de reingreso explicado anteriormente.

Tenga en cuenta que, además, las llamadas a contratos conocidos pueden, a su vez, causar llamadas a contratos desconocidos, por lo que probablemente sea mejor aplicar siempre este patrón.

¿La declaración "La interacción con otros contratos debe ser el último paso en cualquier función" también se aplica a las "interacciones constantes", es decir, cuando se llama a una función pureo viewen otro contrato?

Creo que la respuesta es naturalmente No , sin embargo, los documentos enfatizan cualquier función .

¿No es esta restricción un poco demasiado dura? ¿O estoy equivocado?

¡Gracias!

Respuestas (2)

¿No es esta restricción un poco demasiado dura?

No es una "restricción". Es un patrón para ayudarte a evitar cierta clase de errores. Ciertamente, hay momentos en los que es seguro violar este patrón, pero es una buena regla general.

¿La declaración "La interacción con otros contratos debe ser el último paso en cualquier función" también se aplica a las "interacciones constantes", es decir, cuando se llama a una función pureo viewen otro contrato?

¿ Cómo sabes que la función a la que llamas es pureo view? Si siempre está llamando al mismo contrato y ha auditado su código, entonces probablemente podría ignorar con seguridad el patrón Comprobaciones-Efectos-Interacciones. Pero si llama a un contrato que se determina en tiempo de ejecución, no tiene idea de si va a cambiar de estado o no.

No entiendo a qué te refieres con "el contrato al que llamas es pureo view". Interactuar con un contrato, hasta donde entiendo este término, significa llamar a la función de un contrato. Cuando digo pureo view, me refiero a esa función, que obviamente conozco durante el tiempo de compilación, independientemente de si conozco o no la dirección del contrato durante el tiempo de compilación (¿de qué otra manera llamaría a esta función sin conocer su prototipo?).
Lo siento, debería haber dicho "función a la que llamas" (editado ahora). La firma de la función no existe en tiempo de ejecución. Llamar a una función viewo puretiene el mismo aspecto en tiempo de ejecución que llamar a una función que no tiene uno de esos modificadores.

¿No es esta restricción un poco demasiado dura?

No precisamente. Es solo un orden de eventos contrario a la intuición. Puedes acostumbrarte a usarlo en todos los casos. Eventualmente, el código le parecerá muy sospechoso si no sigue el patrón seguro.

Enfoque intuitivo:

  1. Interactuar con un contrato
  2. Compruebe el resultado.
  3. Haz algo con el resultado.

Camino seguro:

  1. Tratar con optimismo los cambios de estado (contabilidad): asumir el éxito.
  2. Interactuar con el contrato.
  3. Revertir los cambios del paso 1 si es necesario ( .transfer()) lo hace automáticamente. revert()es una opción, o devolver manualmente todos los valores a sus valores anteriores en el improbable caso de que desee continuar.

Puede ser útil separar los contratos en dos categorías: aquellos en los que confía y aquellos de los que no puede estar seguro.

No hay nada de malo, y a menudo no puede evitar llamar viewy purefunciones en su propio sistema (de confianza) y no hay nada de malo en eso. También es posible que desee llamar a viewfunciones en los contratos de otras personas que pueden ser sospechosas; por ejemplo, lo han hecho actualizable, por lo que no hay forma de garantizar que la interacción siempre sea segura, incluso si ve el código hoy.

Dado que esos contratos que no son de confianza pueden inspeccionar por sí mismos el estado de su contrato, existe la posibilidad de que vuelva a entrar en la clase de exploits. Una solución a ese problema es asegurarse de que su estado esté completamente en orden antes de transferir el control de flujo al contrato que no es de confianza. En otras palabras, no les dé la oportunidad de inspeccionar una transacción incompleta y a medias en curso porque invocan otras funciones en su contrato o pueden regresar con un resultado inesperado para el que su contrato no está preparado.

En esencia, ponga a sus guardias al frente y recopile toda la información que necesitará (verificaciones). Registre la actualización completa de su propio estado, incluidos los resultados esperados de los pasos finales, por ejemplo, poner a cero un saldo (efectos). Por último, las operaciones de cambio de estado en otros contratos "no confiables" como send, transfero call. Observe si falló y revierta los cambios de estado en ese caso.

Espero eso ayude.