Hacer una llamada con una instancia de contrato frente a hacer una llamada con un ID de método hash

Según tengo entendido, hay dos formas principales de llamar a una función en otro contrato.

1.) Usando el ID de método de 4 bytes ----> address.call(bytes4(sha3('foo()'))

2.) Usando el contrato ABI ---> contractInstance.foo()

Me preguntaba si alguien podría explicar por qué hacer una llamada con el ID del método bytes4 solo puede indicar un error de falta de gas mientras que hacer una llamada con ABI puede devolver valores reales. Supongo que tiene algo que ver con la ABI, pero me gustaría entender qué está pasando aquí debajo del capó. Gracias.

Respuestas (1)

No estoy seguro de lo que quiere decir con el uso del contrato ABI dentro de un contrato. Creo que te refieres a cuando importamos un contrato a otro contrato y accedemos a una instancia del mismo creando una referencia a él, por ejemplo contractInstance = externalContract(contractAddress).

En última instancia, la razón por la que hay valores de retorno cuando hemos importado un contrato es porque sabemos en la compilación qué tipo y tamaño de datos devolverá cada llamada de función. Entonces podemos poner los datos devueltos en el tipo de variable correcto. Sin embargo, cuando llamamos directamente a una función en una dirección, no sabemos cuál es el tipo y el tamaño de los valores devueltos porque estos detalles no se almacenan en la cadena de bloques. La función solo devuelve datos sin procesar. Esto significa que no sabemos en qué tipo de variable almacenar el valor de retorno después de llamar a esa función, por lo que simplemente no está permitido.

Como nota al margen, desde la bifurcación de Byzantium, en realidad puede obtener valores de retorno address.call()si ejecuta algunas instrucciones de ensamblaje directamente después. Específicamente la returndatacopy()instrucción que se puede ver en el documento . Y se puede ver un ejemplo de uso en un contrato de proxy actualizable que escribí (tenga en cuenta que el ejemplo usa delegar llamada pero debería comportarse igual que usar llamada). Este enfoque aún solo devuelve datos sin procesar, no crea un tipo de variable para que viva.

Ok eso fue genial gracias. ¿Puede explicar qué constituye una "instancia" de contrato bajo el capó? ¿Es el código de bytes?
También estoy cavando tu repositorio solidity-playground :-)
¡Me alegro! ¡Quizás pueda ser útil! En cuanto a la instancia del contrato. En el contexto de Solidity, es solo una representación de alto nivel de algo que finalmente se compila/convierte a código de bytes, como sugirió. Durante la compilación, cuando el compilador llega a una línea que llama a otro contrato, va al archivo especificado en la declaración de importación que representa ese contrato y verifica que todos los tipos (de args y return vals) sean los mismos que los que se están llamando. Generará un error si no lo son o si hay un problema de compatibilidad; de lo contrario, lo convertirá en código de bytes para la implementación.