基本含义:
tx.origin
:
tx.origin 表示交易的发起者,这个值在执行交易时自动设置,用于表示这个交易是由哪个账户发起的.
使用 tx.origin 的原因是,在以太坊区块链中,交易可能会经过多个中间人,最终到达目标账户。在这种情况下,msg.sender 可能会变成中间人账户的地址,而 tx.origin 则始终表示交易的发起者。使用 tx.origin 可以保证在检查权限时,始终检查交易的实际发起者。
msg.sender
msg.sender 表示当前函数调用的发送者,这个值在执行函数调用时自动设置,用于表示谁在调用当前函数.
简单理解:
如果A调用了合约B的函数FB, 那么在函数FB中, A既是tx.origin
, 也是msg.sender
如果A调用了合约C, 合约C再调用了合约B的函数FB, 那么在函数FB中, A是tx.origin
, C是msg.sender
举例
三个合约, 外部地址调用C, C调用B, B调用A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import "hardhat/console.sol";
contract A {
function FA() public view {
console.log("A-tx.origin:", tx.origin);
console.log("A-msg.sender:", msg.sender);
console.log("A-address:", address(this));
}
}
contract B {
function FB() public {
console.log("B-tx.origin:", tx.origin);
console.log("B-msg.sender:", msg.sender);
console.log("B-address:", address(this));
A a = new A();
a.FA();
}
}
contract C {
function FC() public {
console.log("C-tx.origin:", tx.origin);
console.log("C-msg.sender:", msg.sender);
console.log("C-address:", address(this));
B b = new B();
b.FB();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//const { expect } = require('chai');
const { ethers } = require('hardhat');
describe('origin demo Test Suits', function () {
it("测试..", async function () {
const [owner, other] = await ethers.getSigners();
let facotry = await ethers.getContractFactory("C");
const contract = await facotry.deploy();
await contract.FC();
});
});
|
输出
1
2
3
4
5
6
7
8
9
|
C-tx.origin: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
C-msg.sender: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
C-address: 0x5fbdb2315678afecb367f032d93f642f64180aa3
B-tx.origin: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
B-msg.sender: 0x5fbdb2315678afecb367f032d93f642f64180aa3
B-address: 0xa16e02e87b7454126e5e10d957a927a7f5b5d2be
A-tx.origin: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
A-msg.sender: 0xa16e02e87b7454126e5e10d957a927a7f5b5d2be
A-address: 0x8ff3801288a85ea261e4277d44e1131ea736f77b
|
分析上面的输出, 可以得到下面这个图
安全隐患
网上有很多关于对tx.origin
授权导致的安全隐患的文章, 但使用时要区分你的代码到底是需要tx.origin
还是msg.sender
判断调用方是否是合约
! 不要用 codesize 判断调用方是合约还是EOA
使用
1
|
require(msg.sender == tx.origin, "caller can not be contract");
|