¿Sería mejor usar `throw` en lugar de `return false`?

Mi objetivo es llevar a cabo alguna función simple, pero el usuario debe saber si la llamada falla. Aquí se puede ver un ejemplo de una función simple .

En lugar de return false, quiero usar throw. ¿Su efecto sería el mismo en el flujo de la función? ¿Y cuál gasta menos gasolina?

En general, ¿cuál podría estar más motivado para usar?

Respuestas (3)

Esta discusión importa principalmente en el contexto de un contrato que llama a otro contrato. Si el contrato de la persona que llama arroja, no hay nada catchen el contrato de la persona que llama en las versiones actuales de EVM. Por lo tanto, el error de lanzamiento es imposible de recuperar si es necesario. Pero esto rara vez es necesario en los casos de uso habituales.

El uso de throw hace que sea más fácil ver si la transacción tuvo algún error en un explorador de blockchain.

Consulte también la discusión de las próximas características que abordan estos https://github.com/ethereum/EIPs/issues/140

"Usar throw hace que sea más fácil ver si la transacción tuvo algún error en un explorador de blockchain". La ironía es que si te gusta hacer las cosas programáticamente (es decir, sin humanos en el ciclo), lanzar es MÁS DIFÍCIL de diagnosticar porque todo lo que obtienes es gasUsed = gasSent, no obtienes ningún mensaje de error y no puedes averiguar qué línea de código falló en que contrato.
@PaulS: las transacciones tampoco tienen valor de retorno.
las transacciones pueden registrar mensajes, que es como realizo las pruebas automatizadas. (y/o escribir funciones de acceso). Una transacción abortada no registra nada...

Solo pensé en intervenir, en caso de que estas preguntas y respuestas sean útiles para otros. Para abreviar, imagínese que prefijé todo con en mi opinión .

Es una pregunta muy general. Segregaría las situaciones en dos casos:

  1. "No" es una respuesta válida a una pregunta
  2. Algo está mal con la transacción.

En el primer caso, return falsepodría ser el camino a seguir. Por ejemplo, "¿Es lunes?" - No. Nada está especialmente mal y "No" es una respuesta válida y esperada. Implícitamente, la persona que llama debe estar preparada para la posibilidad de que regrese un "No" y tratarlo en consecuencia.

Un gran número de casos pertenecen a la segunda categoría; algo está mal. En estos casos es casi siempre preferible throw; en mi opinión .

Considere que podemos implementar un contrato y luego, en el futuro, la persona que llama podría ser otro contrato. Si estamos return false, en efecto, cargando a la persona que llama con la responsabilidad de lidiar con resultados inesperados. Eso lleva a la complejidad y la complejidad es algo que no queremos en los contratos inteligentes. Por otro lado, si throwa la primera señal de problemas, estamos prestando un servicio a todos los que llamen en el futuro; si nuestra función "no sucedió", entonces no sucedió nada.

Esto es todo lo contrario de la filosofía en otros entornos donde existe una obsesión cercana por detectar errores y explicar problemas. Creo que merece una mención para aquellos que comienzan y posiblemente se preguntan sobre el enfoque habitual.

En un contrato inteligente, tiendo a fallar temprano, fallar mucho y no explicar nada. En otras palabras, throwen (casi) todas las oportunidades.

Heurística general:

  1. Valide la entrada y tire si algo está mal.
  2. Hacer cosas.
  3. Comprueba los resultados y si algo está mal, tira.
  4. Devuelve "éxito" o resultado.

Puede parecer un poco brutal. En mi opinión , un contrato inteligente debería centrarse en salvaguardar la integridad de la aplicación (y los datos) y debería hacerlo de la manera más sencilla posible porque estamos tratando con una plataforma en la que un error o un descuido podría tener consecuencias no triviales y podría ser difícil. o imposible de arreglar.

Nuestro objetivo es "obviamente correcto". Minimizar la complejidad implica que explicar las razones es una preocupación aparte (para que los clientes lo averigüen). Throwsuele ser la respuesta más segura y sencilla a las excepciones que amenazan la integridad del sistema.

Espero eso ayude.

En general, es mejor usar throwen lugar de return false.

Una razón objetiva es que throwes más seguro porque revierte todos los cambios de estado: es seguro que cuando falla la llamada nada cambia. Es posible rastrear y deshacer manualmente todos los cambios, pero es posible perder algo al hacerlo "manualmente".

Una razón subjetiva es que la corrección, la seguridad y la protección son las prioridades más importantes para las aplicaciones descentralizadas y sin confianza (como describe @Rob), y throwes objetivamente más seguro.

Lanzar vs. Devolver describe:

Por que usarthrow

  • Cualquier efecto secundario del código se revierte
  • Algunas billeteras pueden predecir throwcon anticipación, advirtiendo al usuario

Por que usarreturn

  • El usuario desprevenido consume menos gasolina (nuevamente, suponiendo que no se trate de una llamada malintencionada).
  • Un contrato de llamadas puede recuperarse con gracia de la falla, a diferencia de throw.

Otra consideración es el informe de errores. Actualmente no throwhay forma de obtener más información sobre el error, mientras que los eventos y los códigos de error se pueden usar returnpara transmitir una razón más granular sobre el error.

Otra cosa a tener en cuenta al usar web3.js es que cuando throwse encuentra Solidity, actualmente web3.js tiene un problema con falselos valores .


En el futuro

revertprobablemente será el que se use, ya que tendrá todos los beneficios de throwy return:

La REVERTinstrucción proporciona una forma de detener la ejecución y revertir los cambios de estado, sin consumir todo el combustible provisto y con la capacidad de devolver una razón.