Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

从记录跟踪交易探索以太坊交易

V刘晨曦
145 0 0
以太坊可被看做基于交易的状态机:交易可以改变状态机,状态机可以记录跟踪交易。本文将在一个比较深入的层次考察以太坊交易的组成部分,解释大部分令人费解的十六进制数是怎么确定的。在本教程中,我们使用 node.js,所以我们首先从安装依赖关系开始。$ npm install web3@0.19 ethereumjs-util@4.4 ethereumjs-tx@1.3; p" ?( ?; A! a! p" n, r
然后创建文件 tx.js ,请求依赖关系。var Web3 = require('web3');
2 Q! c' o, F4 {% Z. nvar web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io/'));
" R# M, X0 r5 n8 ~" L3 E& m4 ovar util = require('ethereumjs-util');
4 J2 o3 o. o9 O5 avar tx = require('ethereumjs-tx');
0 n' o' B6 a% p1 S首先我们从理解一个私钥开始。以太坊通过
  S  @: p9 b4 X0 C/ x7 D( k9 ?公钥加密
  s9 ?5 h5 ~7 }( l5 A进行授权。具体来说,用( R: L0 o5 i: _2 @3 |
椭圆曲线数字加密算法
/ p  Y( F5 Z0 Z! x8 m9 F3 e,通过
, V1 _+ T' z6 G' f; w$ {3 Esecp256k1
! ^+ E& t' S- q  S标准生成公钥。除了有一些9 t, \. {5 U: @3 g, p0 a9 H
限制& V' i7 Z, L9 a0 e0 I
外,私钥只是一个随机的 256 位的数。例如:var privateKey = '0xc0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0de';6 o4 U+ O) `1 `- E
通过私钥导出相应的公钥:var publicKey = util.bufferToHex(util.privateToPublic(privateKey));3 S" T" ]% P$ W' F! S
如果你输出公钥,可以看到下面的 16 进制数:0x4643bb6b393ac20a6175c713175734a72517c63d6f73a3ca90a15356f2e967da03d16431441c61ac69aeabb7937d333829d9da50431ff6af38536aa262497b27
: j% c; l8 s* y与私钥相关联的以太坊地址是用相应公钥进行
, m. S$ [! ^; g+ F( b! l5 ISHA3-256 (Keccak); F. [" A" o* i9 V. h
哈希运算后得到的后 160 位。var address = '0x' + util.bufferToHex(util.sha3(publicKey)).slice(26);5 G: ^9 }) V. `+ o) ]
//0x53ae893e4b22d707943299a8d0c844df0e3d5557
) t6 |; o. K1 ]5 D, u正如你看到的,多个私钥可以有相同的地址。一个以太坊账户与一个地址相关联,而且每个地址都有以下属性:; f8 S- n6 {% }% D  F  d# m9 x# D$ t- M, |
nonce:输出交易的次数,从 0 开始
; e" Q% m' c+ s) E- B. hbalance:账户中的以太币数. s* {9 ~! n3 }8 ^
storageRoot:与账户存储相关联的哈希值4 V' S# W/ c& I
codehash:控制账户的代码的哈希,如果它是空的,那么就是一个正常账户,能够通过私钥访问的,否则,它就是一个智能合约,其交互受到代码的控制
) _9 p0 e  J9 p+ K接下来我们看一下交易,交易有 6 个输入域:1 K  z" n" D4 w8 v3 m
nonce:输出交易的次数,从 0 开始+ j# p8 H1 q0 P. o" O/ o5 o8 z2 V
gasPrice:交易中花费的单位 Gas 的价格1 l# J& K: x! \0 V
gasLimit:处理交易允许花费的最大 Gas 量
& \; G, d' ^5 Y! l' yto:交易发送到的账户,如果是空,交易就会创建合约) I; z' ^& E) C4 d
value:发送的以太币的量
* [% [) U3 k- g4 S: D, idata:可以是任意的消息或合约函数调用或创建合约的代码
( l" p! T6 b" m0 @! g一个发送 1000wei 以太并且留下消息 0Xc0de 的交易可以被构造如下:var rawTx = {% i+ k" @! Z) p0 q; @; j; }
    nonce: web3.toHex(0),
! f1 v0 m4 `0 Q* `5 o8 X. V* D    gasPrice: web3.toHex(20000000000),
- P8 ]( F9 |7 V- Q    gasLimit: web3.toHex(100000),# @0 \9 j$ I# o' O  z' _, b8 k% m
    to: '0x687422eEA2cB73B5d3e242bA5456b782919AFc85',
- i9 N  [/ k2 T0 F2 a$ o5 x    value: web3.toHex(1000),
3 D) g  C4 M1 ]( a/ L% y# n    data: '0xc0de'' U% M- D3 r0 ?* B8 U: R
};, \$ n) b" E) I
注意, from 地址并没有指定,在私钥签署后,它会从签名中提取。签署交易:var p = new Buffer('c0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0de', 'hex');
" n: {* s1 @, n+ j- |8 {; avar transaction = new tx(rawTx);. S! b1 ^, i# r! I0 x( G
transaction.sign(p);( w, F7 L# U( o1 ^2 R5 X
然后交易就可以发送到网络上,而且能通过一个 256 位的交易 ID 进行追踪。这个交易可以在
) v5 {6 L' F3 b. k7 Z  P- T8 _! g/ NEtherscan
0 v7 d) ~; l2 J. k( Q9 `) w; X# M中查看。交易 ID 是交易的哈希值console.log(util.bufferToHex(transaction.hash(true)));
0 ?' l7 d) M2 B8 W6 a  J//0x8b69a0ca303305a92d8d028704d65e4942b7ccc9a99917c8c9e940c9d57a9662' m/ h  T8 q+ c* G( E
接下来,我们看一下指什么构成了函数调用的数据。以此次合约交易数据为例:console.log(web3.eth.getTransaction('0xaf4a217f6cc6f8c79530203372f3fbec160da83d1abe048625a390ba1705dd57').input);" e. G% N: A& O2 X; k+ E
//0xa9059cbb0000000000000000000000007adee867ea91533879d083dd47ea81f0eee3a37e000000000000000000000000000000000000000000000000d02ab486cedbffff
* r- O) }4 M0 d  Y为了知道调用的是哪个函数,必须提前知道合约的所有的函数,才能创建哈希表。前 32 位 a9059cbb 是函数哈希的前 32 位。在当前情况下,函数为 transfer(address _to, uint256 _value) ,它的哈希为:console.log(web3.sha3('transfer(address,uint256)'));
- z3 a+ y* R5 `  e# c! P! m//0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b$ d3 k8 H) b0 d5 ]/ K1 c. H/ F
接下来是参数,每个 256 位,所以当前情况下 address 是:0x0000000000000000000000007adee867ea91533879d083dd47ea81f0eee3a37e
, b  q0 m" `- ^. Xuint256 是:0x000000000000000000000000000000000000000000000000d02ab486cedbffff' _( }" l6 S7 ~* ?
接下来,如上所述,通过省略 to 域,可以建立一个合约。但是如何确定合约地址呢?以此交易为例:console.log(web3.eth.getTransactionReceipt('0x77a4f46ff7bf8c084c34293fd654c60e107df42c5bcd2666f75c0b47a9352be5').contractAddress);
! X2 l( P" a0 a3 R1 F% N//0x950041c1599529a9f64cf2be59ffb86072f00111/ `- m$ r& B1 O2 _! d6 E9 X8 I
合约地址是发送者地址哈希值的后 160 位,而且 nonce 可以提前确定。对于这个交易来说,发送者和 nonce 可以在下列代码中发现:var contractTx = web3.eth.getTransaction('0x77a4f46ff7bf8c084c34293fd654c60e107df42c5bcd2666f75c0b47a9352be5');
$ l2 W5 S7 r' I. [; l8 Iconsole.log(contractTx.from);
+ `1 m. W! T& V" y//0x84f9d8b0e74a7060e20b025c1ea63c2b171bae6f) k6 O4 F9 ~) V- ~9 }. f, p
console.log(contractTx.nonce);
1 @+ f, \6 k, h/ f& Z//07 g* x! F0 x1 x0 d. S% m6 n
所以合约地址是:console.log('0x' + util.bufferToHex(util.rlphash(['0x84f9d8b0e74a7060e20b025c1ea63c2b171bae6f', 0])).slice(26));
0 R9 t# ?9 }% P0 z//0x950041c1599529a9f64cf2be59ffb86072f00111
: |3 }2 u2 G7 k: d8 ?, s现在我们算是搞清楚了这些十六进制数的含义!以太坊和智能合约具有打破许多行业的巨大潜力。线上有许多资源,你可以在下面找到几个更多关于以太坊的教程!以太坊主站3 `4 P; N6 U: w# e  {
https://www.ethereum.org/
: D0 Z1 N% I4 b& o6 l以太坊的其中一个客户端 Mist 的 GitHub Repo
+ {' g# {  f* P0 t* o3 w0 m0 bhttps://github.com/ethereum/mist/releases
. J8 I- Y/ S2 s6 [  t" ASolidity( j2 x6 i# I7 m. j  ]" f
http://solidity.readthedocs.io/en/latest/' P9 u8 p1 t) Z/ }9 G& E
Web3 api( A0 W* k" Y% ]% g1 u9 e" I
https://github.com/ethereum/wiki/wiki/JavaScript-API. T% s7 l+ S/ }& J0 d
社区讨论- b  E: P- V" `4 G
https://www.reddit.com/r/ethereum/9 v3 Z1 _& y- _3 Y7 y) J. b- f
如果你有任何关于此文的问题,你可以在我们
0 A$ H  R) z! W+ GGitHub nightlyHacks repo0 r: |6 p" ~0 E7 t, p
中提出。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

V刘晨曦 初中生
  • 粉丝

    0

  • 关注

    3

  • 主题

    14