Skip to content

Commit f9126f6

Browse files
committed
erc20
1 parent fdd1fd1 commit f9126f6

File tree

1 file changed

+254
-2
lines changed

1 file changed

+254
-2
lines changed

13区块链/以太坊.md

Lines changed: 254 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,257 @@
33
## Ethereum geth 同步区块的三种模式
44

55
- full:从开始到结束,获取区块的header、body,从创始块开始校验每一个元素,下载所有区块数据信息。速度最慢,获取到所有的历史数据。
6-
- fast:获取区块的header,获取区块的body,在同步到当前块之前不处理任何事务,不逐一验证,有可能丢失历史数据。
7-
- light:仅获取当前状态。验证元素需要向full节点发起相应的请求。
6+
- snap:获取区块的header,获取区块的body,在同步到当前块之前不处理任何事务,不逐一验证,有可能丢失历史数据。
7+
- light:仅获取当前状态。验证元素需要向full节点发起相应的请求。
8+
9+
## [以太坊交易信息及event、input、logs、topics等概念机制](https://blog.csdn.net/cljdsc/article/details/121798544)
10+
11+
### 交易信息
12+
13+
#### 合约事件
14+
15+
- `event Transfer(address indexed from, address indexed to, uint256 value)`
16+
- 事件名称:Transfer
17+
- 事件的参数:address, address, uint256
18+
- 注意:此事件的from和to参数前有indexed标记,value没有indexed标记
19+
20+
#### 以太坊交易获取
21+
22+
当上述事件在合约中调用后,我们通过其交易hash获取交易信息。从以太坊得到一条交易信息的方式有两种:
23+
- eth_getTransactionByHash: :返回指定交易对应的交易信息。
24+
```shell
25+
curl -s -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36"],"id":1}' http://127.0.0.1:8545
26+
```
27+
```json
28+
{
29+
"jsonrpc": "2.0",
30+
"id": 1,
31+
"result": {
32+
"blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
33+
"from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
34+
"blockNumber": "0xd19505",
35+
"gasPrice": "0x274daee580",
36+
"gas": "0x10e3d",
37+
"maxPriorityFeePerGas": "0x6ccc91d0",
38+
"maxFeePerGas": "0x2d48ddd9f1",
39+
"input": "0xa9059cbb000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000016512c902",
40+
"hash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
41+
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
42+
"nonce": "0x14",
43+
"value": "0x0",
44+
"transactionIndex": "0x71",
45+
"accessList": [],
46+
"type": "0x2",
47+
"v": "0x1",
48+
"chainId": "0x1",
49+
"s": "0x75a485b8c378173a829b27a2e55312311fdb33c68ae65f4c74e5f9cc0a748e0d"
50+
"r": "0xa1d7455286525df11602aab34e9e8ab21b092e2c7853a0d6beca0dfb2a78b2e8",
51+
}
52+
}
53+
```
54+
55+
- eth_getTransactionReceipt :返回指定交易对应的收据信息。
56+
```json
57+
{
58+
"jsonrpc": "2.0",
59+
"id": 1,
60+
"result": {
61+
"blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
62+
"blockNumber": "0xd19505",
63+
"contractAddress": null,
64+
"cumulativeGasUsed": "0x6c847e",
65+
"effectiveGasPrice": "0x274daee580",
66+
"from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
67+
"gasUsed": "0xa169",
68+
"logs": [
69+
{
70+
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
71+
"topics": [
72+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
73+
"0x000000000000000000000000b8262c6a2dcabd92a77df1d5bd074afd07fc5829",
74+
"0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7"
75+
],
76+
"data": "0x000000000000000000000000000000000000000000000000000000016512c902",
77+
"blockNumber": "0xd19505",
78+
"transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
79+
"transactionIndex": "0x71",
80+
"blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
81+
"logIndex": "0xa0",
82+
"removed": false
83+
}
84+
],
85+
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000008000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000080000000000000000000000000000000000000004000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200",
86+
"status": "0x1",
87+
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
88+
"transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
89+
"transactionIndex": "0x71",
90+
"type": "0x2"
91+
}
92+
}
93+
```
94+
95+
### input解析
96+
97+
#### input内容解析
98+
99+
**若input=0x则为非合约调用,否则为合约方法调用。**
100+
以合约方法function transfer(address to, uint tokens) 为例;
101+
input数据分为3个部分:
102+
第一部分: 4 字节,是方法名的哈希
103+
例如:`a9059cbb`,具体可参见:以太坊智能合约各方法对应的签名编码
104+
第二部分: 32字节,以太坊地址,目前以太坊地址是20个字节,高位补0
105+
例如:`000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca`
106+
第三部分:32字节,是需要传输的代币数量,这里是1*10^18 GNT
107+
例如:`0000000000000000000000000000000000000000000000000de0b6b3a7640000`
108+
所有这些加在一起就是交易数据:
109+
`a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000`
110+
111+
#### input处理逻辑
112+
113+
```javascript
114+
115+
if(transanctionInput=='0x'){
116+
// 非合约调用
117+
return;
118+
}else{
119+
retJson['function'] = {'funcName':null,'inputs':null,'outputs':null,'exeResult':null};
120+
var funcArr = mxxContractABI.filter(function (per) {
121+
return per.signature == funcHash ;
122+
});
123+
if(funcArr!==null&&funcArr.length>0){ // 得到方法名
124+
if(funcArr[0].hasOwnProperty("name") && funcArr[0].name!==null){
125+
retJson['function']['funcName'] = funcArr[0].name;
126+
}
127+
if(funcArr[0].hasOwnProperty("inputs") && funcArr[0].inputs!==null){
128+
funcArr[0].inputs.map(function (res) { // 得到方法inputs(输入)
129+
inputs.push(res.type);
130+
});
131+
retJson['function']['inputs'] = inputs;
132+
}
133+
if(funcArr[0].hasOwnProperty("outputs")&& funcArr[0].outputs!==null){
134+
funcArr[0].outputs.map(function (res) {// 得到方法outputs(输出)
135+
outputs.push(res.type);
136+
});
137+
retJson['function']['outputs']= outputs;
138+
}
139+
140+
}
141+
status = transanctionReceipt.status;
142+
if(status == '0x1'){
143+
//执行成功
144+
retJson['function']['exeResult'] = 'Successfully Executed';
145+
}else {
146+
retJson['function']['exeResult'] = 'Failed Executed';
147+
}
148+
149+
```
150+
151+
### logs解析
152+
153+
智能合约通过【事件】来产生【日志】,日志存储的Gas费用要比合约的存储便宜很多(日志每个字节花费8个Gas,而合约存储是每32个字节20000个Gas)。想要通过合约向用户返回数据,则需将数据以事件的形式传给用户,用户拿到transactionReceipt后解析log,log.args.x拿到数据。Input只能拿到调用合约以及function的信息,而不能拿到function运行后内部产生的事件(事件不一定和function拥有相同名称和参数)。
154+
155+
#### 解析步骤
156+
157+
1. 取出transactionReceipt中logs。
158+
2. 取出logs中一条log。
159+
3. 使用event.js得到transferEvent,然后用transferEvent的decode方法解析log。
160+
```javascript
161+
web3SolidityEvent = require('./node_modules/truffle-contract/node_modules/web3/lib/web3/event.js');
162+
var transferErc20Json = {
163+
"anonymous": false,
164+
"inputs": [{
165+
"indexed": true,
166+
"name": "from",
167+
"type": "address"
168+
}, {
169+
"indexed": true,
170+
"name": "to",
171+
"type": "address"
172+
}, {
173+
"indexed": false,
174+
"name": "value",
175+
"type": "uint256"
176+
}],
177+
"name": "Transfer",
178+
"type": "event",
179+
"signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
180+
};
181+
var transferEvent = new web3SolidityEvent(null, config.transferErc20Json, null);
182+
async function processReceiptLogs(transactionReceipt){
183+
let ethErc20LogRecord = null;
184+
let logs = transactionReceipt.logs;
185+
186+
for (let i = 0; i < logs.length; i++) {
187+
let isContractExists = await redis.contractExists(logs[i].address);
188+
189+
if (isContractExists === true) {//判断redis中是否存在
190+
191+
//是否是ERC-20 transfer事件,用topics来判断
192+
if(logs[i].topics[0] === transferErc20Json.signature){
193+
194+
var log = await transferEvent.decode(logs[i]);
195+
logger.debug(prefixOfLogger +'--'+'transferEvent decode result:',log);
196+
ethErc20LogRecord = {
197+
txHash: log.transactionHash,
198+
logIndex: log.logIndex,
199+
contractAddress: log.address,
200+
fromAddress: log.args.from ,
201+
toAddress: log.args.to,
202+
value: log.args.value.div(Math.pow(10, 18)).toString(),
203+
data: log.args.data,
204+
blockNumber: log.blockNumber,
205+
removed: log.removed
206+
};
207+
db.setCreateAndUpdateTime(ethErc20LogRecord);
208+
let createLogRecord = await tables.EthErc20Log.create(ethErc20LogRecord);
209+
210+
}
211+
}
212+
}
213+
```
214+
215+
### 合约交易关键字段解释
216+
217+
>| [getTransactionReceipt返回信息字段详情可参考](https://infura.io/docs/ethereum/json-rpc/eth-getTransactionReceipt)
218+
219+
```json
220+
{
221+
"jsonrpc": "2.0", //RPC版本号,2.0
222+
"id": 1, //RPC请求编号
223+
"result": { //调用结果,为交易收据,主要包含如下字段:
224+
"blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528", // 区块哈希
225+
"blockNumber": "0xd19505", // 区块高度
226+
"contractAddress": null, //合约地址
227+
"cumulativeGasUsed": "0x6c847e", //当前交易执行后累计花费的gas总值
228+
"effectiveGasPrice": "0x274daee580", //当前交易预计使用的gas总值
229+
"from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829", //当前交易发送者的地址
230+
"gasUsed": "0xa169", //执行当前这个交易单独花费的gas
231+
"logs": [ //这个交易产生的日志对象数组
232+
{
233+
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7", //当前交易被调用的合约地址
234+
"topics": [
235+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", //keccak(Transfer(address,address,uint256)), //合约事件签名哈希值,对事件的字符做keccak散列运算
236+
"0x000000000000000000000000b8262c6a2dcabd92a77df1d5bd074afd07fc5829", //当前交易from的地址
237+
"0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7" //当前交易to的地址
238+
],
239+
"data": "0x000000000000000000000000000000000000000000000000000000016512c902", //包含日志的非索引参数
240+
"blockNumber": "0xd19505", // 区块高度
241+
"transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36", //交易的哈希值,32字节
242+
"transactionIndex": "0x71" //交易在区块里面的序号,当交易为pending时为空
243+
"blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
244+
"logIndex": "0xa0", //块中日志索引位置的整数,当交易为pending时日志为空。
245+
"removed": false //当由于链重组而删除日志时,为True。 如果它是一个有效的日志则为False。
246+
}
247+
],
248+
//bloom过滤器,当交易为pending时日志为空
249+
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000008000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000080000000000000000000000000000000000000004000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200",
250+
"status": "0x1", //交易事务状态,1(成功)或0(失败)
251+
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7", //当前交易被调用的合约地址
252+
"transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36", //交易的哈希值,32字节
253+
"transactionIndex": "0x71", //交易在区块里面的序号,当交易为pending时为空
254+
"type": "0x2"
255+
}
256+
}
257+
258+
```
259+

0 commit comments

Comments
 (0)