Web3.js介绍 · Ethereum Blockchain Developer Crash Course(三)了解交易transaction运作过程

本节教你如何创建交易transaction,会告诉你当交易创建时发生了什么,如何手动的把交易通过web3.js广播到网络上。

本节旨在帮助你理解以太坊区块链的交易时如何运作的,当你创建交易时,你在写数据到区块链并且更新区块链的状态,比如账户间发送以太币,调用合约中会写数据的方法,部署合约到区块链等都是交易。

为了把交易广播到网络上,我们要先对交易进行签名,我们使用 ethereumjs-tx 这个JavaScript库,你可以这样安装它:

$ npm install ethereumjs-tx

用这个库的原因是我们想在本地对所有交易进行签名,如果我们的以太坊节点在本地运行,我们可以解锁存储在本地的账户并且对本地的所有交易进行签名,我们使用的是Infura管理的远程节点,即使 Infura 是个可靠的服务, 我们仍想在本地对交易进行签名,而不是让远程节点拥有我们的私钥。

下面让我们创建一个原始交易,对它签名,然后发送交易,广播到网络上。首先创建一个app.js 文件,不再用命令行写代码。

app.js中首先引入一个签名库,然后建立一个web3连接

var Tx = require('ethereumjs-tx')
const Web3 = require('web3')
const web3 = new Web3('https://ropsten.infura.io/YOUR_INFURA_API_KEY')

现在我们用的是Ropsten测试网络,不是之前的以太坊主链网络,用测试网络是因为不用真实的花费以太币,你可以获取假的以太币。 You can obtain fake Ether from a faucet on the Ropsten test network with a faucet. Here are two faucets you can use:

http://faucet.ropsten.be:3001/

https://faucet.metamask.io/

现在我们创建一个交易,发送假的以太币。首先要有两个账户和私钥,可以通过如下方式利用Web3.js建立新账户:

web3.eth.accounts.create()
// > {
//    address: "0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01",
//    privateKey: "0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709",
//    signTransaction: function(tx){...},
//    sign: function(data){...},
//    encrypt: function(password){...}
// }

建好账户后,记得要给这两个账户申请假的以太币,然后我们保存这两个账户地址和私钥,不同机器地址和私钥不同。

const account1 = '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01'
const account2 = '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa02'
export PRIVATE_KEY_1='your private key 1 here'
export PRIVATE_KEY_1='your private key 2 here'

像上面这样保存私钥不安全,我们可以从web3.js环境中读取私钥再保存,可以使用NodeJS中的 process 全局对象:

const privateKey1 = process.env.PRIVATE_KEY_1
const privateKey2 = process.env.PRIVATE_KEY_2

为了用私钥对交易进行签名,我们要用Buffer把私钥转换成字符串,Buffer是NodeJS的一个模块:

const privateKey1 = Buffer.from(process.env.PRIVATE_KEY_1)
const privateKey1 = Buffer.from(process.env.PRIVATE_KEY_2)

现在所有变量都准备好了,我们要:

  1. Build a transaction object 建立一个交易对象
  2. Sign the transaction 对交易签名
  3. Broadcast the transaction to the network 把交易广播到网络上

可以像下面建立交易:

const txObject = {
    nonce:    web3.utils.toHex(txCount),
    to:       account2,
    value:    web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
    gasLimit: web3.utils.toHex(21000),
    gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
  }
  • nonce - 这是之前的交易总数  this is the previous transaction count for the given account. We'll assign the value of this variable momentarily. We also must convert this value to hexidecimal. We can do this with the Web3.js utilitly web3.utils.toHex()
  • to - 接收以太币的账户 the account we're sending Ether to.
  • value - 以太币数量,单位是Wei,且是16进制。 the amount of Ether we want to send. This value must be expressed in Wei and converted to hexidecimal. We can convert the value to we with the Web3.js utility web3.utils.toWei().
  • gasLimit - this is the maximum amount of gas consumed by the transaction. A basic transaction like this always costs 21000 units of gas, so we'll use that for the value here.
  • gasPrice - this is the amount we want to pay for each unit of gas. I'll use 10 Gwei here.

在交易对象中没有 from 字段,当我们用 account1的私钥对交易签名时它会自动引用。

我们可以通过  web3.eth.getTransactionCount()方法获取nonce值,通过回调函数包装后:

web3.eth.getTransactionCount(account1, (err, txCount) => {
  const txObject = {
    nonce:    web3.utils.toHex(txCount),
    to:       account2,
    value:    web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
    gasLimit: web3.utils.toHex(21000),
    gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
  }
})

现在我们有了交易对象,需要对它签名:

const tx = new Tx(txObject)
tx.sign(privateKey1)

const serializedTx = tx.serialize()
const raw = '0x' + serializedTx.toString('hex')

使用 etheremjs-tx 库来创建一个新的 Tx 对象,利用 privateKey1对交易进行签名,然后把交易序列化,转化为十六进制的字符串,能传到Web3中。

最后,我们使用web3.eth.sendSignedTransaction()方法发送签名后序列化的交易到测试网络上:

web3.eth.sendSignedTransaction(raw, (err, txHash) => {
  console.log('txHash:', txHash)
})

完整的 app.js 文件如下:

var Tx     = require('ethereumjs-tx')
const Web3 = require('web3')
const web3 = new Web3('https://ropsten.infura.io/YOUR_INFURA_API_KEY')

const account1 = '' // Your account address 1
const account2 = '' // Your account address 2

const privateKey1 = Buffer.from('YOUR_PRIVATE_KEY_1', 'hex')
const privateKey2 = Buffer.from('YOUR_PRIVATE_KEY_2', 'hex')

web3.eth.getTransactionCount(account1, (err, txCount) => {
  // Build the transaction
  const txObject = {
    nonce:    web3.utils.toHex(txCount),
    to:       account2,
    value:    web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
    gasLimit: web3.utils.toHex(21000),
    gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
  }

  // Sign the transaction
  const tx = new Tx(txObject)
  tx.sign(privateKey1)

  const serializedTx = tx.serialize()
  const raw = '0x' + serializedTx.toString('hex')

  // Broadcast the transaction
  web3.eth.sendSignedTransaction(raw, (err, txHash) => {
    console.log('txHash:', txHash)
    // Now go check etherscan to see the transaction!
  })
})

在 NodeJS 控制台中可以运行 app.js 文件:

$ node app.js

或者这样运行也可以:

$ node app

本节完整的代码在: github.

猜你喜欢

转载自blog.csdn.net/u011680118/article/details/82459576