¿Qué partes de la función se ejecutan externamente y cuáles se ejecutan "en cadena"?

Todavía soy un novato en solidez, así que me disculpo si la pregunta es demasiado básica.

Estoy tratando de escribir un contrato que guarde el hash de un montón (potencialmente) grande de datos en cadena.

Por esta razón, me gustaría escribir una función que realice el hash externamente (es decir, en la máquina que llama, algo así como una función de vista), y luego guarde el resultado en la cadena. ¿Es posible? Un ejemplo de código aquí:

contract Test {
  bytes32[] hashes;

  function extCall(bytes _data) external view {
    bytes32 hash = keccak256(_data);
    _intCall(hash);
  }

  function _intCall(bytes32 _hash) private {
    hashes.push(_hash)
  }
}

La intención aquí era excluir la posibilidad de guardar el hash en la cadena sin tener los datos originales. Por este motivo, la única forma de llamar a la función _intCall sería llamarla a través de extCall. Pero, parece que al hacer este truco, también extCall se llama en cadena y consume gas. En particular, recibo esta advertencia mientras pruebo con trufa:

Advertencia: función declarada como vista, pero esta expresión (potencialmente) modifica el estado y, por lo tanto, requiere que no se pague (el valor predeterminado) o que se pague.

PD: hay una (GRANDE) posibilidad de que haya entendido mal el tema, ¡así que toda ayuda es realmente aceptada!

Respuestas (2)

Cualquier cosa que haga como parte de una transacción sucede en cadena. Cualquier cosa que modifique el estado de un contrato debe hacerse como parte de una transacción.

Está bien llamar a una viewfunción como ayudante; ese código solo se ejecutará en un solo nodo (el que está hablando) y puede devolver un valor. Por lo tanto, esto no generaría un costo por todos los datos que está procesando:

contract Test {
    bytes32[] hashes;

    function hash(bytes data) public pure {
        return keccak256(data);
    }

    function store(bytes32 hash) public {
        hashes.push(hash);
    }
}

Esto se usaría algo como esto (pseudocódigo web3.py-ish):

hash = contract.call().hash("my document here")  # not a transaction
contract.transact().store(hash)  # a transaction

Pero entonces también puede hacer el hash fuera del contrato por completo (por ejemplo, hash = keccak256("my document here")).

No hay forma de demostrarle a nadie que tiene un documento que coincide con el hash a menos que envíe el documento completo como parte de una transacción.

Ok, gracias, solo una pregunta más: ¿es solo una característica de solidez o es inherente a ethereum? Quiero decir, según su conocimiento, ¿habrá una manera de implementar una especie de "llamada mixta externa/interna" directamente en una llamada de asamblea?
Es inherente a Ethereum.

pure -> Para operar con datos (literales) ejemplos:

función hola() pública/externa pura {

a) return 4 + 5;

b) uint number = 6;
   return number;

c) string memory hello = "hi"; // 'memory' -> refers to the temporary memory of the virtual machine of ethereum.
   return hello;

}

ver -> para leer los datos del contrato

ejemplos:

cadena hola = "hola"; -> GLOBAL EN EL CONTRATO (BLOCKCHAIN) si se ha declarado fuera de la función.

function hellooo() vista pública/externa {

a) return hello; 

b) string storage str = hello; -> Refers to the state variable 
(pointer).   
return str;

}

*Ninguno de estos modificadores consume gas porque estas funciones no escriben ni guardan datos en la cadena de bloques.

Gracias, ¿qué sucede si llamo a una función pública A pura/vista en una función B no pura/vista? ¿A consumirá gas porque se llama en B "alcance"? Porque si llamo a la función B dentro de A, A comienza a consumir gas incluso si está marcado como puro/vista.
En ese caso 'B' consume gas, si llamas a 'A', vas a consumir gas. Da igual el modificador 'puer/view' de 'A'. Como regla general, siempre que llames a una función que no sea 'view/puere' te costará gasolina.