¿Cuál es la diferencia entre 'msg.sender' y 'tx.origin'?

Si cualquiera de los dos se usa en el cuerpo de una función de Solidity que puede cambiar el estado de un contrato (llamada de escritura), ¿cuál es la diferencia principal y/o el beneficio de usar uno sobre el otro? Por ejemplo:

   function setOwner() {
      owner = msg.sender;
   }

contra

   function setOwner() {
      owner = tx.origin;
   }

¿Cual es la diferencia?

Respuestas (2)

Con msg.senderel propietario puede ser un contrato.

Con tx.originel dueño nunca puede haber un contrato.

En una cadena de llamada simple A->B->C->D, dentro de D msg.senderestará C y tx.originserá A.

msg.senderSe prefiere por la flexibilidad que proporciona. Además, para Serenity, aunque lleva un tiempo, Vitalik recomienda evitar tx.origin: ¿Cómo hago que mi DAPP sea "a prueba de serenidad"?

Considere cuidadosamente si realmente alguna vez necesita usar tx.origin. Recuerda, es posible que no seas el único usuario de tu contrato. Otras personas pueden querer usar su contrato y querer interactuar con él a través de un contrato que han escrito.

Si realmente se desea el origen en D, entonces cada una de las funciones en los contratos B, C, D podría tomar un parámetro extra para propagar el origen: A pasaría su dirección ( this) a B, B pasaría el valor a C, y C se lo pasaría a D.

EDITAR: Para enfatizar el comentario de @WBT a continuación, un contrato que usa un valor pasado para el origen, debe tener mucho cuidado en cómo usa el origen: cualquiera puede pasar un valor que no es el origen real.

Si usa una billetera como la billetera Mist, no querrá usar tx.origin, si entiendo esta explicación correctamente. Nunca tendría éter sustancial a menos que estuviera en una billetera multi-sig como la billetera Mist.
¡Aceptar! El código que usa tx.origin no será "poseído" por una billetera multi-sig de contrato como Mist.
El código de muestra de OpenZeppelin tiene "propietario público de la dirección", lo que significa que cualquiera puede obtener la dirección del propietario del contrato. ¿Puede una billetera (hacker) falsificar msg.sender para hacerse pasar por el propietario?
@Curt La forma factible de hacerse pasar por msg.sender es tener su clave privada; sin la clave privada es computacionalmente inviable.
Pasar la dirección de origen como parámetro nunca debe usarse por seguridad (por ejemplo, "permitir esta acción solo si la dirección pasada es el propietario del contrato / tiene ciertos privilegios") porque es fácil de falsificar: un atacante puede simplemente averiguar la dirección correcta para pasar (por ejemplo, llamar al propietario()) y pasarla como el valor del parámetro. No desea otorgar permisos a la persona que llama, lo que debería requerir una demostración de que el actor tiene la clave privada asociada con la dirección (como cuando lee msg.sender directamente, no a través de un parámetro pasado).

msg.senderproporciona el remitente directo del mensaje, por ejemplo, un contrato que lo transmitió.

tx.originproporciona el origen de las transacciones, por lo que la dirección de usuario desde la que se envió originalmente. En la práctica, siempre será un usuario, por lo que la respuesta de eth es cierta.