No sé por qué nadie hace esta pregunta (hice mi tarea e hice un montón de búsquedas en Google para obtener una respuesta), pero me cuesta entender cómo funcionan realmente los modificadores de funciones.
Seguro que es trivial cuando solo usas un modificador, o si usas la _
notación siempre al final. Pero me encuentro con un código que se parece a esto:
modifier modA {
// verify something
_;
// verify something
_;
}
modifier modB {
// verify something
_;
// verify something
_;
}
modifier modC {
// verify something
_;
// verify something
_;
}
function Fun() modA modB modC {
// Do something
}
Entonces finalmente me doy cuenta de que no tenía idea de lo que estaba pasando debajo.
En el caso anterior, ¿cómo se supone que funciona? Mirar la documentación realmente no ayuda porque solo dice que los modificadores simplemente reemplazan _
con el código de la función. Pero, ¿y si hay varios de estos?
Entonces, si vamos de modA
a modB
, ¿ _
se reemplazan con el siguiente modificador? ¿Qué quieren decir con "ser reemplazado por la función original"?
Creo que una buena manera de entender lo que está pasando es experimentar con
Creé este contrato en Remix para probar/probar algunas de mis suposiciones sobre lo que sucedía con los modificadores:
pragma solidity ^0.4.18;
contract modifierTest {
uint public modState1;
uint public modState2;
uint public modState3;
modifier modA() {
modState1 = modState1 + 1;
_;
}
modifier modB() {
modState2 = modState2 + 1;
_;
modState2 = modState2 + 1;
_;
}
function func() public modA modB {
modState3 = modState3 + 1;
}
}
Inicialmente, todas las variables de estado del contrato se establecen en 0 de forma predeterminada.
Después de ejecutar la función func y examinar las variables de estado, vemos el siguiente resultado:
modState1 - uint256: 1
modState2 - uint256: 2
modState3 - uint256: 2
De esto, podemos entender que el ; en el modificador *modA* fue reemplazado por el código del modificador *modB* y que los * ;*s en el cuerpo del modificador modB fueron reemplazados por el código de la función func .
Entonces, si pasamos de modA a modB, ¿se reemplaza el _ con el siguiente modificador? ¿Qué quieren decir con "ser reemplazado por la función original"?
Con suerte, este ejemplo demuestra cómo el _ se reemplaza por el siguiente modificador y que el _ del modificador final se reemplaza por el código de la función.
Supongamos una variable de todo el contrato 'a' con un valor de '0' y una función F con un modificador M:
function F() M() {
a = 1;
}
modifier M() {
if (a == 1) throw;
_
}
esto no tirará. Pero esta versión:
modifier M() {
_
if (a == 1) throw;
}
lanzará Piense en los modificadores como un reemplazo de código (precompilado en términos de C++) en lugar de "llamar a". Los modificadores no son funciones. Es exactamente como si la función F se viera así en cada caso, que si asume que 'a' tiene un valor de '0' para comenzar, tiene dos comportamientos diferentes:
function F() {
if (a == 1) throw;
a = 1;
}
y
function F() {
a = 1;
if (a == 1) throw;
}
Para resolverlo, no importa cuán complicado sea, simplemente copie el código modificador en la ubicación adecuada en la función que se está modificando. Puede que tenga que copiar muchos niveles de profundidad, pero eso es lo que está haciendo el precompilador.
Me sorprende ver dos _
en tus ejemplos. No sabía que podías hacer eso. Me parece una muy mala práctica usar _
dos veces en un modificador. Hace que el código sea tremendamente difícil de entender conceptualmente. Por lo menos lo hace por mí.
_
s. Aquí hay uno: ethereum.stackexchange.com/a/5864/21958 - Además, creo que entiendo lo que dices, pero ¿podrías aclarar la respuesta para asegurarte? Como entendí, estás diciendo que la función F() no se ejecuta hasta que pasa por cada modificador M1(), M2(), M3()... uno por uno, haciendo que M1() reemplace F() primero, luego reemplace el resultado con M2(), y así sucesivamente. ¿Y solo cuando llega al último modificador ejecuta realmente la función?
Jack O'Neill
func
se llama dos veces, porque tiene múltiples_;
dentromodB
, y no porque haya múltiples modificadores.