You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.6 KiB
156 lines
4.6 KiB
'use strict'
|
|
var EthJSTX = require('ethereumjs-tx')
|
|
var EthJSBlock = require('ethereumjs-block')
|
|
var ethJSUtil = require('ethereumjs-util')
|
|
var BN = ethJSUtil.BN
|
|
|
|
function TxRunner (executionContext, vmaccounts, opts) {
|
|
this.executionContext = executionContext
|
|
this.web3 = executionContext.web3()
|
|
this.vm = executionContext.vm()
|
|
this.queueTxs = opts.queueTxs
|
|
this.personalMode = opts.personalMode
|
|
this.blockNumber = 0
|
|
if (this.executionContext.isVM()) {
|
|
this.blockNumber = 1150000 // The VM is running in Homestead mode, which started at this block.
|
|
}
|
|
this.running = false
|
|
this.pendingTxs = []
|
|
this.vmaccounts = vmaccounts
|
|
}
|
|
|
|
TxRunner.prototype.rawRun = function (args, cb) {
|
|
this.pendingTxs.push({tx: args, cb: cb})
|
|
this.execute()
|
|
}
|
|
|
|
TxRunner.prototype.execute = function () {
|
|
var self = this
|
|
if (this.running || this.pendingTxs.length === 0) {
|
|
return
|
|
}
|
|
var args = this.pendingTxs[0].tx
|
|
var cb = this.pendingTxs[0].cb
|
|
this.pendingTxs.shift()
|
|
var callback = function (error, result) {
|
|
cb(error, result)
|
|
self.running = false
|
|
self.execute()
|
|
}
|
|
|
|
this.running = true
|
|
var from = args.from
|
|
var to = args.to
|
|
var data = args.data
|
|
if (data.slice(0, 2) !== '0x') {
|
|
data = '0x' + data
|
|
}
|
|
var value = args.value
|
|
var gasLimit = args.gasLimit
|
|
|
|
var tx
|
|
if (!self.executionContext.isVM()) {
|
|
tx = {
|
|
from: from,
|
|
to: to,
|
|
data: data,
|
|
value: value
|
|
}
|
|
if (args.useCall) {
|
|
tx.gas = gasLimit
|
|
self.web3.eth.call(tx, function (error, result) {
|
|
callback(error, {
|
|
result: result,
|
|
transactionHash: result.transactionHash
|
|
})
|
|
})
|
|
} else {
|
|
self.web3.eth.estimateGas(tx, function (err, gasEstimation) {
|
|
if (err) {
|
|
return callback(err, gasEstimation)
|
|
}
|
|
var blockGasLimit = self.executionContext.currentblockGasLimit()
|
|
// NOTE: estimateGas very likely will return a large limit if execution of the code failed
|
|
// we want to be able to run the code in order to debug and find the cause for the failure
|
|
if (gasEstimation > gasLimit) {
|
|
return callback('Gas required exceeds limit: ' + gasLimit)
|
|
}
|
|
if (gasEstimation > blockGasLimit) {
|
|
return callback('Gas required exceeds block gas limit: ' + gasLimit)
|
|
}
|
|
tx.gas = gasEstimation
|
|
var sendTransaction = self.personalMode ? self.web3.personal.sendTransaction : self.web3.eth.sendTransaction
|
|
sendTransaction(tx, function (err, resp) {
|
|
if (err) {
|
|
return callback(err, resp)
|
|
}
|
|
|
|
tryTillResponse(self.web3, resp, callback)
|
|
})
|
|
})
|
|
}
|
|
} else {
|
|
try {
|
|
var account = self.vmaccounts[from]
|
|
if (!account) {
|
|
return cb('Invalid account selected')
|
|
}
|
|
tx = new EthJSTX({
|
|
nonce: new BN(account.nonce++),
|
|
gasPrice: new BN(1),
|
|
gasLimit: new BN(gasLimit, 10),
|
|
to: to,
|
|
value: new BN(value, 10),
|
|
data: new Buffer(data.slice(2), 'hex')
|
|
})
|
|
tx.sign(account.privateKey)
|
|
|
|
const coinbases = [ '0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e' ]
|
|
const difficulties = [ new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10) ]
|
|
var block = new EthJSBlock({
|
|
header: {
|
|
timestamp: new Date().getTime() / 1000 | 0,
|
|
number: self.blockNumber,
|
|
coinbase: coinbases[self.blockNumber % coinbases.length],
|
|
difficulty: difficulties[self.blockNumber % difficulties.length],
|
|
gasLimit: new BN(gasLimit, 10).imuln(2)
|
|
},
|
|
transactions: [],
|
|
uncleHeaders: []
|
|
})
|
|
if (!args.useCall) {
|
|
++self.blockNumber
|
|
} else {
|
|
self.vm.stateManager.checkpoint()
|
|
}
|
|
|
|
self.vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (err, result) {
|
|
if (args.useCall) {
|
|
self.vm.stateManager.revert(function () {})
|
|
}
|
|
callback(err, {
|
|
result: result,
|
|
transactionHash: ethJSUtil.bufferToHex(new Buffer(tx.hash()))
|
|
})
|
|
})
|
|
} catch (e) {
|
|
callback(e, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
function tryTillResponse (web3, txhash, done) {
|
|
web3.eth.getTransactionReceipt(txhash, function (err, result) {
|
|
if (!err && !result) {
|
|
// Try again with a bit of delay
|
|
setTimeout(function () { tryTillResponse(web3, txhash, done) }, 500)
|
|
} else {
|
|
done(err, {
|
|
result: result,
|
|
transactionHash: result.transactionHash
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
module.exports = TxRunner
|
|
|