合約調(diào)用的時(shí)候回產(chǎn)生event log(事件日志)逛犹,這個(gè)event log會(huì)記錄在一個(gè)調(diào)用合約的交易的receipt函數(shù)中蒋荚。通過對(duì)event log的分析可以得到跟多這個(gè)交易的一些詳細(xì)內(nèi)容
- 獲得event log
首先獲得一個(gè)塊中的交易數(shù)組 web3.eth.getBlock(blockHashOrNumber, true, function(error, blockData) {} 其次根據(jù)返回的blockData.transactions獲得交易數(shù)組 隨后可以根據(jù)交易數(shù)組獲得每個(gè)交易的hash 最后 var data = web3.eth.getTransactionReceipt(hash); 獲得這個(gè)交易的更多交易細(xì)節(jié) var logsArr = data.logs; 得到了event log
- 分析
1. 規(guī)則 例如:代幣的購買蜜唾,會(huì)觸發(fā)代幣的Transfer事件厨幻,這是ERC20標(biāo)準(zhǔn)的基本規(guī)定 1. 對(duì)事件的基本定義 event Transfer(address indexed from, address indexed to, uint256 value); 事件名字:Transfer 事件的參數(shù):address, address, uint256悲敷,且此事件的from和to參數(shù)前有indexed標(biāo)記怨酝,value沒有indexed標(biāo)記 事件的規(guī)則是: topic[0]: keccak(Transfer(address,address,uint256)),對(duì)事件的字符做keccak散列運(yùn)算 topic[1]: address類型from參數(shù)補(bǔ)齊64位 topic[1]: address類型to參數(shù)補(bǔ)齊64位 data: 沒有indexed標(biāo)記的value的值轉(zhuǎn)化為16進(jìn)制漆魔,并補(bǔ)齊64位 具體的實(shí)現(xiàn)如下: // 從from這個(gè)賬戶發(fā)送 value個(gè)toekn(代幣) 到to這個(gè)賬戶 Transfer(address indexed from, address indexed to, uint256 value) // 事件名字散列值 topic[0] = keccak(Transfer(address,address,uint256)) = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef // 后續(xù)的就是參數(shù)中有indexed標(biāo)志的參數(shù) 所傳遞的值 // fromeAddress 補(bǔ)齊64位 topic[1] = 0x0000000000000000000000000000000000000000000000000000000000000000 topic[2] = 0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550 // 然后是另一個(gè)不帶indexed標(biāo)志的參數(shù)的 值傳入 // 這就是一個(gè)數(shù)字轉(zhuǎn)化為16進(jìn)制 然后補(bǔ)齊64位 data = 0x00000000000000000000000000000000000000000000002be4fb8c854544b555 2. 具體的事件的分析 1. 基本交易信息 - 交易hash <https://etherscan.io/tx/0xd54e1fbc350dac428ca65a4abef6db4e343e1367e6cd9434bb14949a469cefc4> - 合約1的code <https://etherscan.io/address/0x20bf6672497941bd3e4ec5fd551de5c31e0a898a#code> - 合約2的code <https://etherscan.io/address/0x78b039921e84e726eb72e7b1212bb35504c645ca#code> 事件的記錄由合約代碼決定 2. 交易描述 普通用戶地址向合約地址1轉(zhuǎn)賬1.75eth坷檩,所觸發(fā)的事件分析 3.事件日志字段 1. 第一個(gè)事件日志 "address": "0x78b039921e84e726eb72e7b1212bb35504c645ca", "topics": [ "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885", "0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550" ], "data": "0x00000000000000000000000000000000000000000000002be4fb8c854544b555" 即合約地址為0x78b039921e84e726eb72e7b1212bb35504c645ca的合約觸發(fā)了事件,這個(gè)合約地址時(shí)合約2 根據(jù)對(duì)代碼的分析以及keccak散列后的結(jié)果對(duì)比改抡,確定是 Mint(address indexed to, uint256 amount) 即對(duì)字符:Mint(address,uint256) 處理后的0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885 這個(gè)日志矢炼,就是對(duì)第二個(gè)參數(shù)topics[1]的地址0xd53487c6b3a88dded611079b7ae7b377f4888550分發(fā)了data字段內(nèi)容(轉(zhuǎn)化后為809.709931333333333333),即轉(zhuǎn)了809.709931333333333333個(gè)Sether幣 2. 第二個(gè)事件日志 "address": "0x78b039921e84e726eb72e7b1212bb35504c645ca", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550" ], "data": "0x00000000000000000000000000000000000000000000002be4fb8c854544b555" 合約2觸發(fā)的事件阿纤,將代幣分配到某個(gè)地址的操作 Transfer(address indexed from, address indexed to, uint256 value) 對(duì)Transfer(address,address,uint256) 處理得0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef 從0x地址句灌,實(shí)際就是從空地址轉(zhuǎn)賬,也就是代幣增發(fā)(類似于系統(tǒng)又印了多少鈔票),然后分配給0xd53487c6b3a88dded611079b7ae7b377f4888550 data字段是分配的具體數(shù)字: 809.709931333333333333 3. 第三個(gè)事件日志 "address": "0x20bf6672497941bd3e4ec5fd551de5c31e0a898a", "topics": [ "0xde080401e79886a3afdeac3fa6426ade55f095bfd9fbe1065b017f1e90479a86", "0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550", "0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550" ], "data": "0x000000000000000000000000000000000000000000000000181449a077eb7c0000000000000000000000000000000000000000000000002be4fb8c854544b555" 這個(gè)是合約1觸發(fā)的事件日志 SethTokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount) 對(duì)字符:SethTokenPurchase(address,address,uint256,uint256) 處理后0xde080401e79886a3afdeac3fa6426ade55f095bfd9fbe1065b017f1e90479a86 這件事我的理解就是胰锌,記錄了0xd53487c6b3a88dded611079b7ae7b377f4888550地址花了1.73509271 eth購買了809.709931333333333333 個(gè)Sether幣 data字段是兩個(gè)字段骗绕,可以去除0x字符后,然后64位分割為兩個(gè)字段资昧,然后轉(zhuǎn)化為10進(jìn)制即可酬土。
- 遺留問題
從普通地址轉(zhuǎn)賬給合約地址的eth,通過合約處理后格带,轉(zhuǎn)給了合約的錢包地址撤缴,這個(gè)交易信息,怎么獲燃蟆腹泌?
參考:合約內(nèi)部交易信息獲取被下面合約代碼處理了 // 錢包地址調(diào)用transfer函數(shù),這個(gè)函數(shù)是一個(gè)公開函數(shù)尔觉,就是類似于evm中默認(rèn)有的 wallet.transfer(msg.value); 這種合約內(nèi)部的交易怎么處理凉袱?
交易的真實(shí)數(shù)據(jù)信息如下
{
"blockHash": "0xb385e463f51b3f482bf229fe8aa1a61ecfcd3a3619d617afe58517b42e56500a",
"blockNumber": 4906655,
"contractAddress": null,
"cumulativeGasUsed": 2815773,
"from": "0xd53487c6b3a88dded611079b7ae7b377f4888550",
"gasUsed": 73886,
"logs": [
{
"address": "0x78b039921e84e726eb72e7b1212bb35504c645ca",
"topics": [
"0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885",
"0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550"
],
"data": "0x00000000000000000000000000000000000000000000002be4fb8c854544b555",
"blockNumber": 4906655,
"transactionHash": "0xd54e1fbc350dac428ca65a4abef6db4e343e1367e6cd9434bb14949a469cefc4",
"transactionIndex": 105,
"blockHash": "0xb385e463f51b3f482bf229fe8aa1a61ecfcd3a3619d617afe58517b42e56500a",
"logIndex": 16,
"removed": false
},
{
"address": "0x78b039921e84e726eb72e7b1212bb35504c645ca",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550"
],
"data": "0x00000000000000000000000000000000000000000000002be4fb8c854544b555",
"blockNumber": 4906655,
"transactionHash": "0xd54e1fbc350dac428ca65a4abef6db4e343e1367e6cd9434bb14949a469cefc4",
"transactionIndex": 105,
"blockHash": "0xb385e463f51b3f482bf229fe8aa1a61ecfcd3a3619d617afe58517b42e56500a",
"logIndex": 17,
"removed": false
},
{
"address": "0x20bf6672497941bd3e4ec5fd551de5c31e0a898a",
"topics": [
"0xde080401e79886a3afdeac3fa6426ade55f095bfd9fbe1065b017f1e90479a86",
"0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550",
"0x000000000000000000000000d53487c6b3a88dded611079b7ae7b377f4888550"
],
"data": "0x000000000000000000000000000000000000000000000000181449a077eb7c0000000000000000000000000000000000000000000000002be4fb8c854544b555",
"blockNumber": 4906655,
"transactionHash": "0xd54e1fbc350dac428ca65a4abef6db4e343e1367e6cd9434bb14949a469cefc4",
"transactionIndex": 105,
"blockHash": "0xb385e463f51b3f482bf229fe8aa1a61ecfcd3a3619d617afe58517b42e56500a",
"logIndex": 18,
"removed": false
}
],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800800000020008020000008000000000002000000000000200000000000000000000000020000000000000000000800000000000000400000000010000000000000000000000000000000200000000000000000000000000000000000000000000080000000000000000000000000000000002000000000000000000000000000000002000000000000000000000000000044000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x20bf6672497941bd3e4ec5fd551de5c31e0a898a",
"transactionHash": "0xd54e1fbc350dac428ca65a4abef6db4e343e1367e6cd9434bb14949a469cefc4",
"transactionIndex": 105
}
合約1的代碼摘抄如下
合約1
....上半部分和合約2的代碼一樣....
部分代碼如下
contract MintableToken is StandardToken, Ownable {
// 定義的時(shí)間Mint
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
.....
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
// mint函數(shù)
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
// 調(diào)用Mint事件
Mint(_to, _amount);
// 調(diào)用Transfer事件進(jìn)行代幣分發(fā)
Transfer(0x0, _to, _amount);
return true;
}
....
}
/**
* @title SetherToken
* @dev Sether ERC20 Token that can be minted.
* It is meant to be used in sether crowdsale contract.
*/
// 繼承于MintableToken,可以使用它的函數(shù)調(diào)用
contract SetherToken is MintableToken {
string public constant name = "Sether";
string public constant symbol = "SETH";
uint8 public constant decimals = 18;
function getTotalSupply() public returns (uint256) {
return totalSupply;
}
}
/**
* @title SetherBaseCrowdsale
* @dev SetherBaseCrowdsale is a base contract for managing a sether token crowdsale.
*/
contract SetherBaseCrowdsale {
using SafeMath for uint256;
// The token being sold
// 被分發(fā)的代幣
SetherToken public token;
....
// address where funds are collected
// 募集的資金都轉(zhuǎn)到這個(gè)錢包地址
address public wallet;
......
/**
* event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event SethTokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
// 和合約名字一樣的函數(shù)侦铜,合約創(chuàng)建時(shí)自動(dòng)調(diào)用
function SetherBaseCrowdsale(uint256 _rate, address _wallet) {
require(_rate > 0);
require(_wallet != address(0));
// 創(chuàng)建代幣合約专甩,并存儲(chǔ)代幣合約地址
token = createTokenContract();
rate = _rate;
// 錢包地址
wallet = _wallet;
}
// fallback function can be used to buy tokens
// fallback function 當(dāng)有賬戶向這個(gè)地址轉(zhuǎn)真實(shí)的eth時(shí),自動(dòng)觸發(fā)這個(gè)函數(shù)
function () payable {
// 調(diào)用buyTokens函數(shù)
buyTokens(msg.sender);
}
// low level token purchase function
function buyTokens(address beneficiary) public payable {
....
// 代幣調(diào)用mint函數(shù)钉稍,進(jìn)而觸發(fā)這個(gè)函數(shù)中事件
token.mint(beneficiary, tokens);
// 觸發(fā)SethTokenPurchase事件
SethTokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
// 調(diào)用forwardFunds函數(shù)
forwardFunds();
}
// send ether to the fund collection wallet
// 將收到的eth轉(zhuǎn)到錢包地址
function forwardFunds() internal {
// 錢包地址調(diào)用transfer函數(shù)涤躲,這個(gè)函數(shù)是一個(gè)公開函數(shù),就是類似于evm中默認(rèn)有的
wallet.transfer(msg.value);
}
.....
}
/**
* @title SetherMultiStepCrowdsale
* @dev Multi-step payment policy contract that extends SetherBaseCrowdsale
*/
contract SetherMultiStepCrowdsale is SetherBaseCrowdsale {
.....
}
/**
* @title SetherCappedCrowdsale
* @dev Extension of SetherBaseCrowdsale with a max amount of funds raised
*/
contract SetherCappedCrowdsale is SetherMultiStepCrowdsale {
.....
}
/**
* @title SetherStartableCrowdsale
* @dev Extension of SetherBaseCrowdsale where an owner can start the crowdsale
*/
contract SetherStartableCrowdsale is SetherBaseCrowdsale, Ownable {
.....
}
/**
* @title SetherFinalizableCrowdsale
* @dev Extension of SetherBaseCrowdsale where an owner can do extra work
* after finishing.
*/
contract SetherFinalizableCrowdsale is SetherBaseCrowdsale, Ownable {
.....
}
/**
* @title SetherCrowdsale
* @dev This is Sether's crowdsale contract.
*/
contract SetherCrowdsale is SetherCappedCrowdsale, SetherStartableCrowdsale, SetherFinalizableCrowdsale {
.....
}
合約2的代碼摘抄如下贡未,合約2的代碼就是合約1代碼的上半部分
合約2<SetherToken>
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
....
}
library SafeMath {
....
}
contract ERC20Basic {
....
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
....
}
contract BasicToken is ERC20Basic {
....
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
....
}
contract MintableToken is StandardToken, Ownable {
....
}
/**
* @title SetherToken
* @dev Sether ERC20 Token that can be minted.
* It is meant to be used in sether crowdsale contract.
*/
contract SetherToken is MintableToken {
....
}