6

【Ethereum基础】:交易的生命周期

 3 years ago
source link: http://blog.luoyuanhang.com/2018/04/20/eth-basis-transaction-life-cycle/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

大体上说,一个交易的生命周期要经历以下几个过程:

  • 构造一笔交易(这里的交易要包含交易双方的地址、以太币数量、时间戳、签名等信息,它是不含任何私密信息的合法交易数据)
  • 将消息广播到网络(几乎网络中的所有节点都会收到这笔交易数据)
  • 验证交易的合法性(生成交易的节点要首先进行验证,其它节点也要进行验证,没有经过验证的交易是不能进入到区块链网络的)
  • 将交易写入区块链

构造一笔交易

我们先用一个简单的合约作为例子来谈论一笔交易的构造过程,这个合约的作用是在区块链上存储一个数字:

1
2
3
4
5
6
7
8
9
10
11
12
13
pragma solidity ^0.4.1;

contract SimpleStorage {
uint storedData;

function set(uint x) public {
storedData = x;
}

function get() public constant returns (uint) {
return storedData;
}
}

然后我们要构造一笔交易,该交易的内容是调用合约中的函数set(uint x),并且传入参数1

首先我们知道,构造一笔交易需要以下字段(具体参照《交易与消息》一文):

  • nonce:交易发送者的交易序列号
  • gasPrice:gas价格
  • gasLimit:消耗的gas上限
  • to:交易接收者的地址
  • value:要发送的以太币(以wei为单位)
  • data:可选的数据域(在该例子中是必须的字段)

获取nonce
通过geth控制台我们能获取到nonce值,例如:
eth.getTransactionCount(eth.account[0])

gasPrice
我们能够自己随意设置gas的价格,但是有可能由于gas的价格过低,导致交易没有矿工进行处理导致失效。我们可以从这个网站来获取推荐的gas价格。

gasLimit
设置你能接受的该交易能够消耗的gas的最大数量。

to
在该例子中,接收者的地址应该是该合约的地址

value
在该例子中,不需要发送以太币,值为0

data
我们需要构造该交易的数据域。

首先,我们要调用的函数是合约中的set(uint x),根据Solidity文档^1,我们将该函数set(uint)做Keccak-256哈希^2,结果为:

cccdda2cf2895862749f1c69aa9f55cf481ea82500e4eabb4e2578b36636979b

我们取其前4字节:0xcccdda2c

然后我们所传入的函数的参数是1,填充为32字节:

0000000000000000000000000000000000000000000000000000000000000001

将这两部分连接起来:

0xcccdda2c0000000000000000000000000000000000000000000000000000000000000001

这就是数据域的内容,共计36字节。

最终我们构造好的交易是这样的:

1
2
3
4
5
6
7
8
9
txnCount = web3.eth.getTransactionCount(web3.eth.accounts[0])
var rawTxn = {
nonce: web3.toHex(txnCount),
gasPrice: web3.toHex(800000000000),
gasLimit: web3.toHex(160000),
to: '0xa55fe56f2a183f795fdaae3529d58b58e57ef5ed',
value: web3.toHex(0),
data: '0xcccdda2c0000000000000000000000000000000000000000000000000000000000000001'
};

对交易进行签名

接下来我们需要使用交易发送者账号的私钥对交易进行签名:

1
2
3
4
const privateKey = Buffer.from('你的账户私钥', 'hex')
const txn = new EthereumTx(rawTxn)
txn.sign(privateKey)
const serializedTxn = txn.serialize()

本地对交易进行验证

签名后的交易会首先提交至你的本地以太坊的节点,你的本地节点会首先对该笔交易进行验证,它会验证签名是否有效。

把交易广播至区块链网络

之后,你的本地以太坊节点会将交易广播至整个网络,在广播之后会返回一个交易id,你可以通过该id查看和追踪该交易的状态和相关信息。几乎以太坊网络上的所有节点都会收到这笔交易。有一些节点会设置一个最低的gas价格,它们会忽略低于该gasPrice值的交易。

矿工节点接收到交易

生成的交易需要被区块链网络中的矿工打包到区块,才能写入到区块链中。矿工会有一个待处理的交易列表,其中的交易是按交易的gasPrice进行排序的,交易的gasPrice越高,处理的优先级就越高。如果交易的gasPrice过低,有可能一直得不到矿工的处理,从而被忽略。

矿工将交易打包至区块并广播至网络

矿工会取若干交易然后打包至一个区块中,一个区块中能够包含多少条交易是和区块的gasLimit有关的,所有交易的gasLimit总和不能超过区块的gasLimit。当矿工选择好要打包的交易之后,就开始了PoW(Proof of Work)挖矿过程,最先发现新的区块的矿工能够将交易打包至区块,并且获取到相应的奖励。

其它节点同步新的区块数据

由于新的区块已经产生,所有的节点都需要对区块进行同步,你的交易会随着区块的同步被同步至所有节点上。

至此,一笔交易的生命周期彻底结束,它被永远的写入到了区块链中。


本文的版权归作者 罗远航 所有,采用 Attribution-NonCommercial 3.0 License。任何人可以进行转载、分享,但不可在未经允许的情况下用于商业用途;转载请注明出处。感谢配合!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK