默认分类
以太坊交易中的发起者与执行者,深入解析 sender 与 originer
时间:2026-02-16 1:21
作者:admin
阅读:12
在以太坊区块链的世界里,每一笔交易的背后都涉及到一系列复杂的地址和角色,它们共同确保了交易的安全性、可追溯性和去中心化特性。sender(发送者)和 originer(发起者,通常以 tx.origin 表示)是两个至关重要但又容易混淆的概念,理解它们的区别与联系,对于智能合约开发者、用户以及任何希望深入了解以太坊工作机制的人来说,都是必不可少的。
sender:交易的直接执行发起者
sender,顾名思义,指的是在当前交易上下文中,直接发起调用或执行智能合约函数的那个账户地址
ong>,这个地址可以是外部拥有账户(EOA,Externally Owned Account),也就是由用户通过私钥控制的普通钱包地址;也可以是另一个智能合约地址,如果是后者,那么意味着这笔交易是由另一个智能合约触发的。
在 Solidity 智能合约编程语言中,msg.sender 是一个全局变量,它始终返回当前函数调用者的地址,它是智能合约进行权限验证、资金转移等操作时最常用的身份标识之一。
核心特点:
- 上下文相关:
msg.sender 的值取决于当前执行的调用栈,如果合约 A 调用了合约 B 的函数,那么在合约 B 的函数执行上下文中,msg.sender 就是合约 A 的地址。
- 直接调用者:它代表了直接发起本次函数调用的实体。
- 常用性:在智能合约内部,
msg.sender 被广泛用于检查调用者是否有权执行某些操作,function withdraw() public {
require(msg.sender == owner, "Only owner can withdraw");
payable(msg.sender).transfer(address(this).balance);
}
originer (tx.origin):交易的最初发起者
originer,在以太坊中通过全局变量 tx.origin 来表示,它指的是整个交易链的最初发起者,也就是首先在网络上发起这笔交易的外部拥有账户(EOA)地址,无论这笔交易经过了多少层智能合约的调用,tx.origin 始终是最初发起交易的那个 EOA 地址。
核心特点:
- 全局固定:
tx.origin 在一笔交易的整个执行过程中保持不变,它指向的是交易的源头。
- 最初发起者:它必须是 EOA,因为只有 EOA 才能主动发起一笔交易(通过签名并广播),智能合约不能主动发起交易,只能响应调用。
- 用于防钓鱼(谨慎使用):
tx.origin 通常用于防止恶意合约的钓鱼攻击,一个合约可以检查 msg.sender 是否等于 tx.origin,如果不相等,说明本次调用是由另一个合约转调过来的,可能存在风险,从而拒绝执行某些敏感操作。function dangerousFunction() public {
require(msg.sender == tx.origin, "This function can only be called directly by EOA");
// 执行敏感操作
}
sender 与 originer 的关键区别与联系
为了更清晰地理解两者的区别,我们可以通过一个典型的交易调用场景来说明:
假设:
- 用户 Alice (EOA 地址:
0xAlice) 发起了一笔交易,调用合约 B 的函数 foo()。
- 合约 B (地址:
0xB) 的 foo() 函数内部,又调用了合约 C (地址:0xC) 的函数 bar()。
在这个场景中:
tx.origin:始终是 0xAlice,因为 Alice 是这笔交易的最初发起者。
- 在合约 B 的
foo() 函数中:
msg.sender 是 0xAlice(因为 Alice 直接调用了 B)。
- 在合约 C 的
bar() 函数中:
msg.sender 是 0xB(因为合约 B 调用了合约 C)。
核心区别总结:
| 特性 |
msg.sender (sender) |
tx.origin (originer) |
| 定义 |
当前函数的直接调用者地址 |
整笔交易的最初发起者(EOA)地址 |
| 可变性 |
随着调用栈变化而变化 |
在整个交易执行过程中保持不变 |
| 类型 |
可以是 EOA,也可以是智能合约地址 |
必须是 EOA 地址 |
| 主要用途 |
合约内权限控制、身份识别 |
防钓鱼攻击、识别交易源头(但需谨慎使用) |
重要性与潜在风险
理解 sender 和 originer 的区别至关重要,因为错误地使用 tx.origin 可能会导致严重的安全漏洞。
tx.origin 的主要风险:
tx.origin 最常见的误用场景是在授权模式中,假设有一个合约 Token,它有一个 approve() 函数,允许用户授权另一个地址 spender 来转移其代币。approve() 函数错误地使用了 tx.origin 来判断授权者:
// 错误的示例
function approve(address spender, uint256 amount) public {
require(tx.origin == msg.sender, "Approval from EOA only"); // 错误的检查
allowances[msg.sender][spender] = amount;
}
攻击者可以构造如下攻击:
- 攻击者部署一个恶意合约
MaliciousContract。
- 诱骗用户 Alice(EOA)调用
MaliciousContract 中的一个函数,该函数内部会调用 Token 合约的 approve(攻击者地址, 大量代币)。
- 在
Token 的 approve() 函数中,tx.origin 是 Alice(EOA),msg.sender 是 MaliciousContract(智能合约),如果错误地认为 tx.origin == msg.sender 才是授权,那么这里会失败,但如果逻辑是检查 tx.origin 是否为 EOA(如上例注释所示),那么它会通过。
- 更糟糕的是,如果后续的
transferFrom() 函数错误地依赖 tx.origin 来判断代币所有者,攻击者就可以利用 Alice 的授权转走其代币。
正确的做法是,approve() 函数应该直接使用 msg.sender 作为授权者,因为 msg.sender 才是直接调用 approve() 并发出授权指令的实体(无论是 EOA 还是合约,但授权的主体是 msg.sender)。
msg.sender 和 tx.origin 以太坊交易中两个基础但至关重要的全局变量,它们共同标识了交易参与者的身份。msg.sender 关注的是当前调用的直接发起者,而 tx.origin 追溯的是交易的最初源头。
对于智能合约开发者而言:
- 优先使用
msg.sender 进行权限控制和身份验证,因为它准确反映了当前调用上下文。
- 谨慎使用
tx.origin,仅在需要明确识别交易最初发起者(如防钓鱼场景)时使用,并充分理解其潜在风险,避免授权相关的漏洞。
深入理解这两者的区别,不仅能帮助我们编写更安全、更健壮的智能合约,也能让我们更清晰地洞察以太坊交易执行的内在逻辑,在去中心化的世界里,每一个地址的“身份”都至关重要,而 sender 与 originer 正是这些身份的核心体现。
猜你喜欢
- 以太坊盘面分析入门,从读懂K线到把握市场脉搏
- 领英上的Web3工资,机遇/挑战与未来趋势
- 一文读懂欧易Web3钱包授权,安全开启你的Web3之旅
- 狗狗币是哪一年发行的,从玩笑到加密货币顶流的时间密码
- 欧艺Web3新玩法,扫码即可领取狗狗币红包,数字资产福利轻松get
- 以太坊网络设置全指南,从连接到自定义,一文读懂
- Doge币图片,从表情包到加密货币的文化符号
- cf北部大区交易所现在囤什么
- 液态硅胶壳抹茶绿,当清新邂逅温柔,为你的苹果披上一抹春日
返回栏目