ethereumjs/ethereumjs-tx
https://github.com/ethereumjs/ethereumjs-tx
A simple module for creating, manipulating and signing ethereum transactions
安装:
npm install ethereumjs-tx --save
example:
const EthereumTx = require('ethereumjs-tx')
const privateKey = Buffer.from('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') const txParams = {
nonce: '0x00',
gasPrice: '0x09184e72a000',
gasLimit: '0x2710',
to: '0x0000000000000000000000000000000000000000',
value: '0x00',
data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
// EIP 155 chainId - mainnet: 1, ropsten: 3
chainId:
} const tx = new EthereumTx(txParams)
tx.sign(privateKey)
const serializedTx = tx.serialize()
Note: this package expects ECMAScript 6 (ES6) as a minimum environment. From browsers lacking ES6 support, please use a shim (like es6-shim) before including any of the builds from this repo.
支持ES6及以上,如果你的浏览器不支持ES6,则使用shim以兼容
BROWSER
For a browser build please see https://github.com/ethereumjs/browser-builds.
API
Transaction
Creates a new transaction object.
Parameters
data
Buffer or Array or Object a transaction can be initiailized with either a buffer containing the RLP serialized transaction or an array of buffers relating to each of the tx Properties, listed in order below in the exmple.Or lastly an Object containing the Properties of the transaction like in the Usage example.For Object and Arrays each of the elements can either be a Buffer, a hex-prefixed (0x) String , Number, or an object with a toBuffer method such as Bignumdata.chainId
Number EIP 155 chainId - mainnet: 1, ropsten: 3data.gasLimit
Buffer transaction gas limitdata.gasPrice
Buffer transaction gas pricedata.to
Buffer to the to addressdata.nonce
Buffer nonce numberdata.data
Buffer this will contain the data of the message or the init of a contractdata.v
Buffer EC recovery IDdata.r
Buffer EC signature parameterdata.s
Buffer EC signature parameterdata.value
Buffer the amount of ether sent
Properties
raw
Buffer The raw rlp encoded transaction
var rawTx = {
nonce: '0x00',
gasPrice: '0x09184e72a000',
gasLimit: '0x2710',
to: '0x0000000000000000000000000000000000000000',
value: '0x00',
data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
v: '0x1c',
r: '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab',
s: '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13'
};
var tx = new Transaction(rawTx);
getBaseFee
the minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee)
Returns BN
该笔交易最少要花费的gas
getChainId
返回chain id,即说明连接的network
Returns Buffer
getDataFee
The amount of gas paid for the data in this tx为了传递交易中的data需要花费的gas
Returns BN
getSenderAddress
returns the sender's address返回交易发送者的address
Returns Buffer
getSenderPublicKey
returns the public key of the sender返回交易发送者的公钥
Returns Buffer
getUpfrontCost
the up front amount that an account must have for this transaction to be valid为使该交易有效,帐户必须拥有的预备金额
Returns BN
hash
Computes a sha3-256 hash of the serialized tx计算序列化交易的hash值
Parameters
includeSignature
[Boolean] whether or not to inculde the signature (optional, defaulttrue
)是否包含签名,默认为true
Returns Buffer
sign
sign a transaction with a given a private key使用privateKey
去对交易进行签名
Parameters
privateKey
Buffer
toCreationAddress
If the tx's to
is to the creation address如果交易的to的地址是0x00000000...,返回true
Returns Boolean
validate
validates the signature and checks to see if it has enough gas确认签名并检查是否有足够的gas
Parameters
stringError
[Boolean] whether to return a string with a dscription of why the validation failed or return a Bloolean (optional, defaultfalse
)是返回一个带有验证失败原因标记的字符串,还是返回一个布尔值
Returns Boolean or String
verifySignature
Determines if the signature is valid确认签名是否有效
Returns Boolean
from
Properties
from
Buffer (read only) sender address of this transaction, mathematically derived from other parameters.属性from即交易的发送者的address
serialize
Returns the rlp encoding of the transaction返回交易的rlp编码格式
Returns Buffer
实现代码:
'use strict'
const ethUtil = require('ethereumjs-util')
const fees = require('ethereum-common/params.json')
const BN = ethUtil.BN // secp256k1n/2
const N_DIV_2 = new BN('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', ) /**
* Creates a new transaction object.
*
* @example
* var rawTx = {
* nonce: '0x00',
* gasPrice: '0x09184e72a000',
* gasLimit: '0x2710',
* to: '0x0000000000000000000000000000000000000000',
* value: '0x00',
* data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
* v: '0x1c',
* r: '0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab',
* s: '0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13'
* };
* var tx = new Transaction(rawTx);
*
* @class
* @param {Buffer | Array | Object} data a transaction can be initiailized with either a buffer containing the RLP serialized transaction or an array of buffers relating to each of the tx Properties, listed in order below in the exmple.
*
* Or lastly an Object containing the Properties of the transaction like in the Usage example.
*
* For Object and Arrays each of the elements can either be a Buffer, a hex-prefixed (0x) String , Number, or an object with a toBuffer method such as Bignum
*
* @property {Buffer} raw The raw rlp encoded transaction
* @param {Buffer} data.nonce nonce number
* @param {Buffer} data.gasLimit transaction gas limit
* @param {Buffer} data.gasPrice transaction gas price
* @param {Buffer} data.to to the to address
* @param {Buffer} data.value the amount of ether sent
* @param {Buffer} data.data this will contain the data of the message or the init of a contract
* @param {Buffer} data.v EC recovery ID
* @param {Buffer} data.r EC signature parameter
* @param {Buffer} data.s EC signature parameter
* @param {Number} data.chainId EIP 155 chainId - mainnet: 1, ropsten: 3
* */ class Transaction {
constructor (data) {
data = data || {}
// Define Properties,定义生成的raw transaction的属性
const fields = [{
name: 'nonce',
length: ,
allowLess: true,
default: new Buffer([])
}, {
name: 'gasPrice',
length: ,
allowLess: true,
default: new Buffer([])
}, {
name: 'gasLimit',
alias: 'gas',
length: ,
allowLess: true,
default: new Buffer([])
}, {
name: 'to',
allowZero: true,
length: ,
default: new Buffer([])
}, {
name: 'value',
length: ,
allowLess: true,
default: new Buffer([])
}, {
name: 'data',
alias: 'input',
allowZero: true,
default: new Buffer([])
}, {
name: 'v',
allowZero: true,
default: new Buffer([0x1c])
}, {
name: 'r',
length: ,
allowZero: true,
allowLess: true,
default: new Buffer([])
}, {
name: 's',
length: ,
allowZero: true,
allowLess: true,
default: new Buffer([])
}] /**
* Returns the rlp encoding of the transaction
* @method serialize
* @return {Buffer}
* @memberof Transaction
* @name serialize
*/
// attached serialize
ethUtil.defineProperties(this, fields, data) /**
* @property {Buffer} from (read only) sender address of this transaction, mathematically derived from other parameters.
* @name from
* @memberof Transaction
*/
Object.defineProperty(this, 'from', {
enumerable: true,
configurable: true,
get: this.getSenderAddress.bind(this)
}) // calculate chainId from signature
let sigV = ethUtil.bufferToInt(this.v)
let chainId = Math.floor((sigV - ) / )
if (chainId < ) chainId = // set chainId
this._chainId = chainId || data.chainId ||
this._homestead = true //即该签名的版本为homestead
} /**
* If the tx's `to` is to the creation address
* @return {Boolean}
*/
toCreationAddress () {
return this.to.toString('hex') === ''
} /**
* Computes a sha3-256 hash of the serialized tx
* @param {Boolean} [includeSignature=true] whether or not to inculde the signature
* @return {Buffer}
*/
hash (includeSignature) {
if (includeSignature === undefined) includeSignature = true //是否包含签名,默认为true // EIP155 spec:
// when computing the hash of a transaction for purposes of signing or recovering,
// instead of hashing only the first six elements (ie. nonce, gasprice, startgas, to, value, data),
// hash nine elements, with v replaced by CHAIN_ID, r = 0 and s = 0 let items
if (includeSignature) {//包含签名v,r,s
items = this.raw
} else {
if (this._chainId > ) {//如果chainId存在,则只是将r,s设为0
const raw = this.raw.slice()
this.v = this._chainId
this.r =
this.s =
items = this.raw
this.raw = raw
} else {//如果chainId不存在,则直接将v,r,s去掉
items = this.raw.slice(, )
}
} // create hash
return ethUtil.rlphash(items)//然后进行hash
} /**
* returns chain ID
* @return {Buffer}
*/
getChainId () {
return this._chainId
} /**
* returns the sender's address
* @return {Buffer}
*/
getSenderAddress () {
if (this._from) {
return this._from
}
const pubkey = this.getSenderPublicKey()
this._from = ethUtil.publicToAddress(pubkey)
return this._from
} /**
* returns the public key of the sender
* @return {Buffer}
*/
getSenderPublicKey () {
if (!this._senderPubKey || !this._senderPubKey.length) {
if (!this.verifySignature()) throw new Error('Invalid Signature')
}
return this._senderPubKey
} /**
* Determines if the signature is valid,确认签名是否有效
* @return {Boolean}
*/
verifySignature () {
const msgHash = this.hash(false)
// All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid.签名的s大于secp256k1n/2则无效
if (this._homestead && new BN(this.s).cmp(N_DIV_2) === ) {
return false
} try {
let v = ethUtil.bufferToInt(this.v)
if (this._chainId > ) {
v -= this._chainId * + //将v值转回正常的chain id值
}
this._senderPubKey = ethUtil.ecrecover(msgHash, v, this.r, this.s) //根据签名得到发送者的公钥
} catch (e) {
return false
} return !!this._senderPubKey //有公钥则返回true,否则为false
} /**
* sign a transaction with a given private key
* @param {Buffer} privateKey
*/
sign (privateKey) {
const msgHash = this.hash(false)
const sig = ethUtil.ecsign(msgHash, privateKey)
if (this._chainId > ) {
sig.v += this._chainId * +
}
Object.assign(this, sig)
} /**
* The amount of gas paid for the data in this tx
* @return {BN}
*/
getDataFee () {
const data = this.raw[]
const cost = new BN()
for (let i = ; i < data.length; i++) {
data[i] === ? cost.iaddn(fees.txDataZeroGas.v) : cost.iaddn(fees.txDataNonZeroGas.v)//根据data是否有值来决定怎么加
}
return cost
} /**
* the minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee)
* @return {BN}
*/
getBaseFee () {
const fee = this.getDataFee().iaddn(fees.txGas.v)
if (this._homestead && this.toCreationAddress()) {
fee.iaddn(fees.txCreation.v)
}
return fee
} /**
* the up front amount that an account must have for this transaction to be valid
* @return {BN}
*/
getUpfrontCost () {//为使该交易有效,帐户必须拥有的预备金额
return new BN(this.gasLimit)
.imul(new BN(this.gasPrice))
.iadd(new BN(this.value))
} /**
* validates the signature and checks to see if it has enough gas
* @param {Boolean} [stringError=false] whether to return a string with a description of why the validation failed or return a Boolean
* @return {Boolean|String}
*/
validate (stringError) {//确认签名并检查是否有足够的gas
const errors = []
if (!this.verifySignature()) {
errors.push('Invalid Signature')
} if (this.getBaseFee().cmp(new BN(this.gasLimit)) > ) {
errors.push([`gas limit is too low. Need at least ${this.getBaseFee()}`])
} if (stringError === undefined || stringError === false) {
return errors.length ===
} else {
return errors.join(' ')
}
}
} module.exports = Transaction
实例:
// see full article here https://wanderer.github.io/ethereum/2014/06/14/creating-and-verifying-transaction-with-node/ var Transaction = require('ethereumjs-tx') // create a blank transaction
var tx = new Transaction(null, ) // mainnet Tx EIP155 // So now we have created a blank transaction but Its not quiet valid yet. We
// need to add some things to it. Lets start:
// notice we don't set the `to` field because we are creating a new contract.
tx.nonce =
tx.gasPrice =
tx.gasLimit =
tx.value =
tx.data = '0x7f4e616d65526567000000000000000000000000000000000000000000000000003057307f4e616d6552656700000000000000000000000000000000000000000000000000573360455760415160566000396000f20036602259604556330e0f600f5933ff33560f601e5960003356576000335700604158600035560f602b590033560f60365960003356573360003557600035335700' var privateKey = new Buffer.from('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')
tx.sign(privateKey)
// We have a signed transaction, Now for it to be fully fundable the account that we signed
// it with needs to have a certain amount of wei in to. To see how much this
// account needs we can use the getUpfrontCost() method.
var feeCost = tx.getUpfrontCost()
tx.gas = feeCost
console.log('Total Amount of wei needed:' + feeCost.toString()) // if your wondering how that is caculated it is
// bytes(data length) * 5
// + 500 Default transaction fee
// + gasAmount * gasPrice // lets serialize the transaction console.log('---Serialized TX----')
console.log(tx.serialize().toString('hex'))
console.log('--------------------') // Now that we have the serialized transaction we can get AlethZero to except by
// selecting debug>inject transaction and pasting the transaction serialization and
// it should show up in pending transaction. // Parsing & Validating transactions
// If you have a transaction that you want to verify you can parse it. If you got
// it directly from the network it will be rlp encoded. You can decode you the rlp
// module. After that you should have something like
var rawTx = [
'0x00',
'0x09184e72a000',
'0x2710',
'0x0000000000000000000000000000000000000000',
'0x00',
'0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
'0x1c',
'0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab',
'0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13'
] var tx2 = new Transaction(rawTx) // Note rlp.decode will actully produce an array of buffers `new Transaction` will
// take either an array of buffers or an array of hex strings.
// So assuming that you were able to parse the tranaction, we will now get the sender's
// address console.log('Senders Address: ' + tx2.getSenderAddress().toString('hex')) // Cool now we know who sent the tx! Lets verfy the signature to make sure it was not
// some poser. if (tx2.verifySignature()) {
console.log('Signature Checks out!')
} // And hopefully its verified. For the transaction to be totally valid we would
// also need to check the account of the sender and see if they have at least
// `TotalFee`.
返回:
userdeMacBook-Pro:test-hd-wallet user$ node transaction.js
Total Amount of wei needed:
---Serialized TX----
f8e48064830186a08080b8977f4e616d65526567000000000000000000000000000000000000000000000000003057307f4e616d6552656700000000000000000000000000000000000000000000000000573360455760415160566000396000f20036602259604556330e0f600f5933ff33560f601e5960003356576000335700604158600035560f602b590033560f603659600033565733600035576000353357001ca0b8b9fedc076110cd002224a942e9d7099e4a626ebf66cd9301fc18e2c1181806a04e270be511d42189baf14599eb8d6eb5037ab105032dd3e0fa05b43dad4cb4c2
--------------------
Senders Address: 1f36f546477cda21bf2296c50976f2740247906f
Signature Checks out!
ethereumjs/ethereumjs-tx的更多相关文章
- ethereumjs/ethereumjs-wallet
Utilities for handling Ethereum keys ethereumjs-wallet A lightweight wallet implementation. At the m ...
- ethereumjs/ethereumjs-vm-2-API文档
https://github.com/ethereumjs/ethereumjs-vm/blob/master/docs/index.md vm.runBlockchain Processes blo ...
- ethereumjs/ethereumjs-vm-4-tests
根据代码发现还要了解的模块有: ethereumjs/merkle-patricia-tree -对应数据存储的数据结构 ethereumjs-blockchain —— 区块链 ethereumjs ...
- ethereumjs/ethereumjs-block-2-api
https://github.com/ethereumjs/ethereumjs-block/blob/master/docs/index.md 详细的调用代码可见本博客的ethereumjs/eth ...
- ethereumjs/ethereumjs-vm-1-简介
https://github.com/ethereumjs/ethereumjs-vm 其实这就是怎么自己使用该模块来生成一个类似geth客户端的以太坊虚拟机,然后进行各类区块链操作 SYNOPSIS ...
- ethereumjs/ethereumjs-util
ethereumjs/ethereumjs-util Most of the string manipulation methods are provided by ethjs-util 更多的字符串 ...
- ethereumjs/ethereumjs-icap
https://github.com/ethereumjs/ethereumjs-icap ethereumjs-icap 安装: npm install ethereumjs-icap --save ...
- ethereumjs/ethereumjs-common-1-简介
为了了解ethereumjs/ethereumjs-block-3-代码的使用需要了解的一个模块 https://github.com/ethereumjs/ethereumjs-common Com ...
- ethereumjs/ethereumjs-common-2-API文档
https://github.com/ethereumjs/ethereumjs-common/blob/master/docs/index.md 该API的调用的详细例子可见ethereumjs/e ...
随机推荐
- Map集合框架的练习
Map是一个很重要的集合框架,它以键值对的方式存储,下面是一个Map集合的小练习,使用了keySet的取出方法. 取出字符串的每一个字符,记录每一个字母出现的次数.使用Map集合框架. package ...
- springboot学习-springboot使用spring-data-jpa操作MySQL数据库
我们在上一篇搭建了一个简单的springboot应用,这一篇将介绍使用spring-data-jpa操作数据库. 新建一个MySQL数据库,这里数据库名为springboot,建立user_info数 ...
- Vue:模板&渲染函数学习
模板&渲染函数区别: 1.代码量:模板代码重复逐行拼写,渲染函数可以迭代拼接方式实现重复代码. 2.函数式组件中应用:基于模板的函数式组件需要手动添加特性和事件,给予渲染函数的函数是组件使用c ...
- Hibernate中的三种数据状态
Hibernate中的三种数据状态(临时.持久.游离) 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 比如:刚刚使用new关键字创建出的对象. 2.持久态 ...
- 【 js 基础 】【 源码学习 】 深浅拷贝
underscore的源码中,有很多地方用到了 Array.prototype.slice() 方法,但是并没有传参,实际上只是为了返回数组的副本,例如 underscore 中 clone 的方法: ...
- python网络爬虫抓取动态网页并将数据存入数据库MySQL
简述以下的代码是使用python实现的网络爬虫,抓取动态网页 http://hb.qq.com/baoliao/ .此网页中的最新.精华下面的内容是由JavaScript动态生成的.审查网页元素与网页 ...
- cf97D. Robot in Basement(模拟 bitset)
题意 题目链接 Sol 接下来我的实现方式和论文里不太一样 然后用bitset优化,上下走分别对应着右移/左移m位,左右走对应着右移/左移1位 我们可以直接预处理出能走的格子和不能走的格子,每次走的时 ...
- npm install、npm init、npm update、npm uninstall和package.json
npm install 安装本地包 npm install <package_name>:这个命令将在当前目录中创建node_modules目录(如果尚不存在),并将该软件包下载到该目录. ...
- 活字格Web应用平台学习笔记1 - 下载安装,ready go
今年有一个很重要的职业目标,就是好好学习活字格这个神器,争取在这两个月拿到活字格初级工程师的认证证书.给自己加个油,今天开始好好学习,好好做笔记. 第一步,下载安装 先去活字格官网:http://ww ...
- Nginx的日志优化
1.日志轮询切割: 这篇文章已经对日志轮询切割做个介绍:请点击这里 2.不记录不需要的日志 在实际的工作中,对于负载均衡器健康节点检查或某些特定文件的日志,一般不需要记录下来,因为统计PV是按照页面计 ...