Esta pregunta es una pregunta de diseño general que se refiere a la corrección del contrato y las funciones que enumero aquí son solo ejemplos.
A medida que me desarrollo en Ethereum, se me hace evidente que podría ser relativamente fácil diseñar mal un contrato que se bloquee solo porque las funciones clave necesarias pueden volverse repentinamente inaccesibles porque su ejecución supera repentinamente el límite de gas.
Eso me lleva a la pregunta probablemente difícil:
¿Cómo puedo afirmar que una función específica nunca usa más de una cierta cantidad de gas? Esto parece ser una necesidad crucial para la corrección del contrato.
Por ejemplo
function unbound() returns (uint256) {
uint256 total = 0;
for (uint i=0; i < users.length; i++) {
total+= users[i].value;
}
return total;
}
llamar a esta función tiene un costo de gas no determinista y podría fácilmente en algún momento volverse imposible de llamar. Por supuesto, en un ejemplo tan simple como este, es fácil rediseñar y calcular este total no en un bucle sino por otros medios. Pero no siempre es posible evitar los bucles. La pregunta es, ¿cómo se escriben funciones correctas en ese caso?
Por ejemplo, el sistema podría diseñarse de manera que nunca haya más de 6 usuarios, en cuyo caso el ciclo está vinculado y el costo de ejecución es determinista, por lo que si tengo:
function bound() returns (uint256) {
uint256 total = 0;
assert(users.length < 6);
for (uint i=0; i < users.length; i++) {
total+= users[i].value;
}
return total;
}
Esta función utiliza un bucle pero tiene un límite superior determinista para el consumo de gas.
A: ¿Cómo puedo calcular la cantidad máxima de gas que consumirá esta función?
B: ¿Cómo puedo comunicar este máximo a los clientes de la función?
¿Puedo de alguna manera hacer algo como esto:
function bound() returns (uint256) {
uint256 total = 0;
for (uint i=0; i < users.length; i++) {
total+= users[i].value;
}
assert(gasConsumend < 1234);
return total;
}
?
Estamos escribiendo contratos después de todo, y las condiciones previas y posteriores son una parte integral del diseño por contrato . Podemos escribir condiciones previas con require() y postcondiciones con assert() - pero para la corrección en ethereum también parece necesario afirmar un consumo máximo de gas. ¿Cómo?
Me temo que puede que no haya una respuesta infalible a esto, por la sencilla razón de que en el transcurso de las bifurcaciones, los costos de gasolina pueden cambiar para ciertos códigos de operación (como se hizo para detener los ataques de spam hace algún tiempo).
Debido a lo anterior, es posible que un control de gas codificado de forma rígida ya no sea válido a largo plazo.
Cuando se trata de una función de bucle, requerir que su entrada tenga una cierta longitud es una opción factible. Además, si conoce la entrada, puede usar la eth_estimateGas
llamada para realizar una "ejecución en seco" de la transacción y estimar el gas utilizado, que es cómo MyEtherWallet, Metamask, etc. a veces autocompletan el campo de gas máximo.
Tenga en cuenta que la estimación de gas no es perfecta, especialmente para transacciones que cambian según factores externos (como marcas de tiempo o que el hash de bloque sea par/impar).
Desafortunadamente, limitar las longitudes de las matrices a menudo no es factible. Si su matriz debe exceder un tamaño donde no es posible recorrerlo en un tx, una alternativa es reconstruir su función para que acepte una lista de índices como parámetros, y solo acceda a esos índices en esa transacción. Esto puede permitirle actualizar el contenido de la matriz/realizar alguna operación poco a poco en el transcurso de unas pocas transacciones.
Por ejemplo, una variable de suma podría declararse a nivel de contrato, y una matriz de 1 millón de elementos podría sumarse en el transcurso de 5000 transacciones que suman 20 elementos cada una.
Al final, sospecho que la redacción cuidadosa del contrato es la clave para tratar de evitar las situaciones, y un buen diseño de billetera/frontend puede comunicar a los usuarios finales cuándo una acción excederá el límite de gas del bloque y pedirles que reduzcan el tamaño de entrada.
matthias_buehlmann
Raghav Sood