Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

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

V刘晨曦
143 0 0
以太坊可被看做基于交易的状态机:交易可以改变状态机,状态机可以记录跟踪交易。本文将在一个比较深入的层次考察以太坊交易的组成部分,解释大部分令人费解的十六进制数是怎么确定的。在本教程中,我们使用 node.js,所以我们首先从安装依赖关系开始。$ npm install web3@0.19 ethereumjs-util@4.4 ethereumjs-tx@1.3
& y8 k; z. U9 B4 |! f& F然后创建文件 tx.js ,请求依赖关系。var Web3 = require('web3');
& {3 g+ v6 S. ?6 f- Mvar web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io/'));
5 t6 Y. G) C/ J1 d2 j1 m( Svar util = require('ethereumjs-util');
/ E4 o- [, d  ?var tx = require('ethereumjs-tx');
' P8 O: ^" @9 J: M; H首先我们从理解一个私钥开始。以太坊通过
: \6 G8 v5 v# {2 ~; p( h( ?( K公钥加密
3 H6 j* K. c0 ?( q, q进行授权。具体来说,用
) x4 T* R+ m9 ], l  B: B& {椭圆曲线数字加密算法
8 \0 a; ?! O( o3 y$ o,通过0 T& M  w5 K  G: q0 ^. E1 L
secp256k16 [& p3 X( t/ D: D- D: Q
标准生成公钥。除了有一些
. h0 d* c2 m: b5 Q2 K限制
$ ]# y: @" f8 e8 F6 B6 Q外,私钥只是一个随机的 256 位的数。例如:var privateKey = '0xc0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0de';
3 o; `% x! }+ d; ?$ x8 R+ X& j通过私钥导出相应的公钥:var publicKey = util.bufferToHex(util.privateToPublic(privateKey));* U0 C! @2 y4 A) ]2 H7 e/ H9 @
如果你输出公钥,可以看到下面的 16 进制数:0x4643bb6b393ac20a6175c713175734a72517c63d6f73a3ca90a15356f2e967da03d16431441c61ac69aeabb7937d333829d9da50431ff6af38536aa262497b276 P! }8 u0 c$ ^: k8 ]
与私钥相关联的以太坊地址是用相应公钥进行
2 D/ h6 c$ k& oSHA3-256 (Keccak)5 Q: T8 G0 h% W& s. C' }1 M
哈希运算后得到的后 160 位。var address = '0x' + util.bufferToHex(util.sha3(publicKey)).slice(26);
) f0 L; I% c8 r6 J//0x53ae893e4b22d707943299a8d0c844df0e3d5557+ S0 d8 \& y' ^3 [2 T4 R
正如你看到的,多个私钥可以有相同的地址。一个以太坊账户与一个地址相关联,而且每个地址都有以下属性:
1 _5 d4 r# S: E. a) V% ?4 nnonce:输出交易的次数,从 0 开始; L! c3 _4 e2 Q6 D
balance:账户中的以太币数) i) l5 ]6 y% n) E' N5 i, T' s) N
storageRoot:与账户存储相关联的哈希值" ^- T- {9 O- y( J. u
codehash:控制账户的代码的哈希,如果它是空的,那么就是一个正常账户,能够通过私钥访问的,否则,它就是一个智能合约,其交互受到代码的控制) i; U' }, x4 y
接下来我们看一下交易,交易有 6 个输入域:* j5 m+ F( O& X6 @
nonce:输出交易的次数,从 0 开始. t& O: R* M9 R: F' T% e5 g0 R
gasPrice:交易中花费的单位 Gas 的价格
5 Y# [5 Y; N$ M7 s& j& o, a1 H' NgasLimit:处理交易允许花费的最大 Gas 量  D% L2 N6 r3 f6 H  m  l
to:交易发送到的账户,如果是空,交易就会创建合约
% G* u" z8 O5 b3 H, Y- [% ~0 qvalue:发送的以太币的量/ z8 k, A. \8 M1 ?8 }
data:可以是任意的消息或合约函数调用或创建合约的代码
6 Z6 q$ K$ n3 H6 R( S" g: O一个发送 1000wei 以太并且留下消息 0Xc0de 的交易可以被构造如下:var rawTx = {/ `+ i4 S! A( e7 E/ x% e0 _- K1 G; Y
    nonce: web3.toHex(0),
: x: v' a& ]- J* j7 Q  G* P    gasPrice: web3.toHex(20000000000),% x- y5 j# @- A& E) S4 t, t1 o
    gasLimit: web3.toHex(100000),
* J( T( R5 l$ _/ V$ B    to: '0x687422eEA2cB73B5d3e242bA5456b782919AFc85',
- z! f7 F5 @# n" w7 T! }! ?    value: web3.toHex(1000),' Y. l+ z' {! V* b
    data: '0xc0de'" M! c0 u. r% `5 y( `& t2 J7 k
};# y, K+ Z& y9 ^" u6 x) V; f8 d1 Q* O# v
注意, from 地址并没有指定,在私钥签署后,它会从签名中提取。签署交易:var p = new Buffer('c0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0dec0de', 'hex');
+ c0 Q* t( n/ ^. c2 L, n- R: fvar transaction = new tx(rawTx);* J' A7 W: c+ K+ J. i2 c4 n
transaction.sign(p);
- y# y: G( E8 b$ j然后交易就可以发送到网络上,而且能通过一个 256 位的交易 ID 进行追踪。这个交易可以在: z4 A( y, A/ v
Etherscan% y3 N5 U' C) F% y- d
中查看。交易 ID 是交易的哈希值console.log(util.bufferToHex(transaction.hash(true)));7 V, G4 S, f: b" q
//0x8b69a0ca303305a92d8d028704d65e4942b7ccc9a99917c8c9e940c9d57a96621 e/ f4 F/ k/ f$ l& x
接下来,我们看一下指什么构成了函数调用的数据。以此次合约交易数据为例:console.log(web3.eth.getTransaction('0xaf4a217f6cc6f8c79530203372f3fbec160da83d1abe048625a390ba1705dd57').input);2 \( ~: B  W: J2 b/ W$ c4 {
//0xa9059cbb0000000000000000000000007adee867ea91533879d083dd47ea81f0eee3a37e000000000000000000000000000000000000000000000000d02ab486cedbffff5 U" a  M" r9 w8 N9 {* V; r
为了知道调用的是哪个函数,必须提前知道合约的所有的函数,才能创建哈希表。前 32 位 a9059cbb 是函数哈希的前 32 位。在当前情况下,函数为 transfer(address _to, uint256 _value) ,它的哈希为:console.log(web3.sha3('transfer(address,uint256)'));
$ w8 c  \$ w# _//0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
; k+ @% N" @3 W4 x接下来是参数,每个 256 位,所以当前情况下 address 是:0x0000000000000000000000007adee867ea91533879d083dd47ea81f0eee3a37e9 f! V: E/ O) i) w+ B
uint256 是:0x000000000000000000000000000000000000000000000000d02ab486cedbffff
( b, n  W  A) U' E" K" t) s" N接下来,如上所述,通过省略 to 域,可以建立一个合约。但是如何确定合约地址呢?以此交易为例:console.log(web3.eth.getTransactionReceipt('0x77a4f46ff7bf8c084c34293fd654c60e107df42c5bcd2666f75c0b47a9352be5').contractAddress);3 w6 a+ u8 x& B' a* [7 R( E/ ?( a
//0x950041c1599529a9f64cf2be59ffb86072f001114 P5 i% q5 J: P0 _  Y: C6 W0 |$ |
合约地址是发送者地址哈希值的后 160 位,而且 nonce 可以提前确定。对于这个交易来说,发送者和 nonce 可以在下列代码中发现:var contractTx = web3.eth.getTransaction('0x77a4f46ff7bf8c084c34293fd654c60e107df42c5bcd2666f75c0b47a9352be5');2 N  F, j( y5 \/ l# Z
console.log(contractTx.from);
: l5 u) x( D4 u3 o: f  o//0x84f9d8b0e74a7060e20b025c1ea63c2b171bae6f
! }9 n- Z+ a. fconsole.log(contractTx.nonce);
: X/ O: N7 J3 ]% b, a//0
, k) D; _4 ^, `; ~$ U所以合约地址是:console.log('0x' + util.bufferToHex(util.rlphash(['0x84f9d8b0e74a7060e20b025c1ea63c2b171bae6f', 0])).slice(26));
. p, w. D( n- A& d4 `//0x950041c1599529a9f64cf2be59ffb86072f00111
: k( l& u, u! k& ], S现在我们算是搞清楚了这些十六进制数的含义!以太坊和智能合约具有打破许多行业的巨大潜力。线上有许多资源,你可以在下面找到几个更多关于以太坊的教程!以太坊主站
8 N. P: j. z% [( b! V1 i6 D: @; \0 Thttps://www.ethereum.org/5 J9 V5 W% D( ]1 [8 k0 k0 b
以太坊的其中一个客户端 Mist 的 GitHub Repo0 i. H0 D( `6 F" ]$ A
https://github.com/ethereum/mist/releases0 f9 W2 D7 R! g- g
Solidity/ m' G- @8 X  ?2 g
http://solidity.readthedocs.io/en/latest/
. L/ f6 x4 t1 b3 b) w0 a$ d: }Web3 api" k8 D; E2 g$ C3 j2 F
https://github.com/ethereum/wiki/wiki/JavaScript-API
7 ]0 y8 |: ^$ A+ f" \) J/ B社区讨论6 x, G2 Z+ @% `) M$ E. `" r
https://www.reddit.com/r/ethereum/
/ z" `/ k/ n. w4 j如果你有任何关于此文的问题,你可以在我们) ?# I, d9 W% n% D0 x& |* P2 D$ ]9 L
GitHub nightlyHacks repo
9 `( c: f1 ^6 B中提出。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

V刘晨曦 初中生
  • 粉丝

    0

  • 关注

    3

  • 主题

    14