В чем разница между «msg.sender» и «tx.origin»?

Если любой из них используется в теле функции Solidity, которая может изменить состояние контракта (вызов записи), в чем основное отличие и/или преимущество использования одного над другим. Например:

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

против.

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

Какая разница?

Ответы (2)

С msg.senderсобственником может быть договор.

С tx.originсобственником никогда не может быть контракта.

В простой цепочке вызовов A->B->C->D внутри D msg.senderбудет C, а tx.originбудет A.

msg.senderпредпочтительнее из-за гибкости, которую он обеспечивает. Кроме того, для Serenity, несмотря на то, что прошло некоторое время, Виталик рекомендует избегать tx.origin: Как мне сделать мой DAPP «защищенным от Serenity?»

Внимательно подумайте, действительно ли вам когда-нибудь понадобится использовать tx.origin. Помните, что вы не можете быть единственным пользователем вашего контракта. Другие люди могут захотеть использовать ваш контракт и захотеть взаимодействовать с ним через контракт, который они написали.

Если источник действительно требуется в D, то каждая из функций в контрактах B, C, D может принимать дополнительный параметр для распространения источника: A передаст свой адрес ( this) в B, B передаст значение C, и C передаст его D.

РЕДАКТИРОВАТЬ: Чтобы подчеркнуть комментарий @WBT ниже, контракт, который использует переданное значение для источника, должен быть очень осторожным в том, как он использует источник: любой может передать значение, которое не является реальным источником.

Если вы используете кошелек, такой как кошелек Mist, вы не захотите использовать tx.origin, если я правильно понимаю это объяснение. У меня никогда не было бы существенного количества эфира, если бы он не был в кошельке с несколькими подписями, таком как кошелек Mist.
Соглашаться! Код, который использует tx.origin, не будет «владеть» кошельком с мультиподписью контракта, таким как Mist.
Пример кода OpenZeppelin имеет «публичный адрес владельца», что означает, что любой может получить адрес владельца контракта. Может ли кошелек (хакер) подделать msg.sender, чтобы выдать себя за владельца?
@Curt Возможный способ выдать себя за msg.sender - это иметь его закрытый ключ; без закрытого ключа это вычислительно невозможно.
Передача исходного адреса в качестве параметра никогда не должна использоваться в целях безопасности (например, «разрешить это действие только в том случае, если переданный адрес является владельцем контракта / имеет определенные привилегии»), потому что его легко подделать: злоумышленник может просто выяснить правильный адрес для передачи (например, вызов owner()) и передать его в качестве значения параметра. Вы не хотите, чтобы это давало вызывающему абоненту разрешения, которые должны требовать демонстрации того, что актер владеет закрытым ключом, связанным с адресом (как при чтении msg.sender напрямую, а не через переданный параметр).

msg.senderдает прямого отправителя сообщения, например, контракт, который передал его.

tx.originдает источник транзакций, то есть адрес пользователя, с которого он был первоначально отправлен. На практике это всегда будет пользователь, поэтому ответ eth остается верным.