Skip to content

Commit

Permalink
Merge pull request #143 from cdetrio/eip150-final
Browse files Browse the repository at this point in the history
EIP 150 finished
  • Loading branch information
wanderer authored Jul 16, 2017
2 parents 0e5a588 + b98b61d commit 1971754
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 61 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ build/Release
# Dependency directory
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
node_modules
package-lock.json


1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ VM.deps = {
* @param {Blockchain} [opts.blockchain] A blockchain object for storing/retrieving blocks
* @param {Boolean} [opts.activatePrecompiles] Create entries in the state tree for the precompiled contracts
* @param {Boolean} [opts.enableHomestead] Force enable Homestead irrelevant to block number
* @param {Boolean} [opts.enableHomesteadReprice] Force enable Homestead Reprice (EIP150) irrevelant to block number
*/
function VM (opts = {}) {
this.stateManager = new StateManager({
Expand Down
79 changes: 48 additions & 31 deletions lib/opFns.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ module.exports = {
}

checkCallMemCost(runState, options, localOpts)
checkOutOfGas(runState, options)
makeCall(runState, options, localOpts, done)
},
CALL: function (gasLimit, toAddress, value, inOffset, inLength, outOffset, outLength, runState, done) {
Expand All @@ -539,11 +540,8 @@ module.exports = {
outLength: outLength
}

// add stipend
if (!value.isZero()) {
runState.gasLeft.iadd(new BN(fees.callStipend.v))
subGas(runState, new BN(fees.callValueTransferGas.v))
options.gasLimit.iadd(new BN(fees.callStipend.v))
}

stateManager.exists(toAddress, function (err, exists) {
Expand All @@ -563,11 +561,17 @@ module.exports = {

try {
checkCallMemCost(runState, options, localOpts)
checkOutOfGas(runState, options)
} catch (e) {
done(e.error)
return
}

if (!value.isZero()) {
runState.gasLeft.iadd(new BN(fees.callStipend.v))
options.gasLimit.iadd(new BN(fees.callStipend.v))
}

makeCall(runState, options, localOpts, done)
})
},
Expand All @@ -594,30 +598,30 @@ module.exports = {
outLength: outLength
}

// add stipend
if (!value.isZero()) {
runState.gasLeft.isub(new BN(fees.callValueTransferGas.v)).iadd(new BN(fees.callStipend.v))
options.gasLimit.iadd(new BN(fees.callStipend.v))
subGas(runState, new BN(fees.callValueTransferGas.v))
}

checkCallMemCost(runState, options, localOpts)
checkOutOfGas(runState, options)

// load the code
stateManager.getAccount(toAddress, function (err, account) {
if (err) return done(err)
if (utils.isPrecompiled(toAddress)) {
options.compiled = true
options.code = runState._precompiled[toAddress.toString('hex')]
if (!value.isZero()) {
runState.gasLeft.iadd(new BN(fees.callStipend.v))
options.gasLimit.iadd(new BN(fees.callStipend.v))
}

if (utils.isPrecompiled(toAddress)) {
options.compiled = true
options.code = runState._precompiled[toAddress.toString('hex')]
makeCall(runState, options, localOpts, done)
} else {
stateManager.getContractCode(toAddress, function (err, code, compiled) {
if (err) return done(err)
options.code = code
options.compiled = compiled
makeCall(runState, options, localOpts, done)
} else {
stateManager.getContractCode(toAddress, function (err, code, compiled) {
if (err) return done(err)
options.code = code
options.compiled = compiled
makeCall(runState, options, localOpts, done)
})
}
})
})
}
},
DELEGATECALL: function (gas, toAddress, inOffset, inLength, outOffset, outLength, runState, done) {
var stateManager = runState.stateManager
Expand Down Expand Up @@ -645,6 +649,7 @@ module.exports = {
}

checkCallMemCost(runState, options, localOpts)
checkOutOfGas(runState, options)

// load the code
stateManager.getAccount(toAddress, function (err, account) {
Expand Down Expand Up @@ -675,20 +680,29 @@ module.exports = {
var contractAddress = runState.address
suicideToAddress = utils.setLengthLeft(suicideToAddress, 20)

// only add to refund if this is the first suicide for the address
if (!runState.suicides[contractAddress.toString('hex')]) {
runState.gasRefund = runState.gasRefund.add(new BN(fees.suicideRefundGas.v))
}

runState.suicides[contractAddress.toString('hex')] = suicideToAddress
runState.stopped = true

stateManager.getAccount(suicideToAddress, function (err, toAccount) {
// update balances
if (err) {
cb(err)
return
}

if (!toAccount.exists) {
try {
subGas(runState, new BN(fees.callNewAccountGas.v))
} catch (e) {
cb(e.error)
return
}
}

// only add to refund if this is the first suicide for the address
if (!runState.suicides[contractAddress.toString('hex')]) {
runState.gasRefund = runState.gasRefund.add(new BN(fees.suicideRefundGas.v))
}
runState.suicides[contractAddress.toString('hex')] = suicideToAddress
runState.stopped = true

var newBalance = new Buffer(new BN(contract.balance).add(new BN(toAccount.balance)).toArray())
async.series([
stateManager.putAccountBalance.bind(stateManager, suicideToAddress, newBalance),
Expand Down Expand Up @@ -813,9 +827,12 @@ function checkCallMemCost (runState, callOptions, localOpts) {
if (!callOptions.gasLimit) {
callOptions.gasLimit = runState.gasLeft
}
}

if (runState.gasLeft.cmp(callOptions.gasLimit) === -1) {
trap(ERROR.OUT_OF_GAS)
function checkOutOfGas (runState, callOptions) {
const gasAllowed = runState.gasLeft.sub(runState.gasLeft.div(new BN(64)))
if (callOptions.gasLimit.gt(gasAllowed)) {
callOptions.gasLimit = gasAllowed
}
}

Expand Down
16 changes: 8 additions & 8 deletions lib/opcodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const codes = {

// 0x30 range - closure state
0x30: ['ADDRESS', 2, 0, 1, true],
0x31: ['BALANCE', 20, 1, 1, true],
0x31: ['BALANCE', 400, 1, 1, true],
0x32: ['ORIGIN', 2, 0, 1, true],
0x33: ['CALLER', 2, 0, 1, true],
0x34: ['CALLVALUE', 2, 0, 1, true],
Expand All @@ -42,8 +42,8 @@ const codes = {
0x38: ['CODESIZE', 2, 0, 1, false],
0x39: ['CODECOPY', 3, 3, 0, false],
0x3a: ['GASPRICE', 2, 0, 1, false],
0x3b: ['EXTCODESIZE', 20, 1, 1, true],
0x3c: ['EXTCODECOPY', 20, 4, 0, true],
0x3b: ['EXTCODESIZE', 700, 1, 1, true],
0x3c: ['EXTCODECOPY', 700, 4, 0, true],

// '0x40' range - block operations
0x40: ['BLOCKHASH', 20, 1, 1, true],
Expand All @@ -58,7 +58,7 @@ const codes = {
0x51: ['MLOAD', 3, 1, 1, false],
0x52: ['MSTORE', 3, 2, 0, false],
0x53: ['MSTORE8', 3, 2, 0, false],
0x54: ['SLOAD', 50, 1, 1, true],
0x54: ['SLOAD', 200, 1, 1, true],
0x55: ['SSTORE', 0, 2, 0, true],
0x56: ['JUMP', 8, 1, 0, false],
0x57: ['JUMPI', 10, 2, 0, false],
Expand Down Expand Up @@ -143,13 +143,13 @@ const codes = {

// '0xf0' range - closures
0xf0: ['CREATE', 32000, 3, 1, true],
0xf1: ['CALL', 40, 7, 1, true],
0xf2: ['CALLCODE', 40, 7, 1, true],
0xf1: ['CALL', 700, 7, 1, true],
0xf2: ['CALLCODE', 700, 7, 1, true],
0xf3: ['RETURN', 0, 2, 0, false],
0xf4: ['DELEGATECALL', 40, 6, 1, true],
0xf4: ['DELEGATECALL', 700, 6, 1, true],

// '0x70', range - other
0xff: ['SUICIDE', 0, 1, 0, false]
0xff: ['SUICIDE', 5000, 1, 0, false]
}

module.exports = function (op, full) {
Expand Down
2 changes: 1 addition & 1 deletion lib/runCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ module.exports = function (opts, cb) {
var returnFee = results.return.length * fees.createDataGas.v
var totalGas = results.gasUsed.addn(returnFee)
// if not enough gas
if (totalGas.cmp(gasLimit) <= 0) {
if (totalGas.cmp(gasLimit) <= 0 && results.return.length <= 24576) {
results.gasUsed = totalGas
} else {
results.return = new Buffer([])
Expand Down
3 changes: 2 additions & 1 deletion lib/runCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module.exports = function (opts, cb) {
callData: opts.data || new Buffer([0]),
code: opts.code,
populateCache: opts.populateCache === undefined ? true : opts.populateCache,
enableHomestead: this.opts.enableHomestead === undefined ? block.isHomestead() : this.opts.enableHomestead // this == vm
enableHomestead: this.opts.enableHomestead === undefined ? block.isHomestead() : this.opts.enableHomestead
}

// temporary - to be factored out
Expand Down Expand Up @@ -105,6 +105,7 @@ module.exports = function (opts, cb) {

function vmIsActive () {
var notAtEnd = runState.programCounter < runState.code.length

return !runState.stopped && notAtEnd && !runState.vmError && !runState.returnValue
}

Expand Down
19 changes: 7 additions & 12 deletions lib/runTx.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const Bloom = require('./bloom.js')
const Block = require('ethereumjs-block')

/**
* Process a transaction. Run the vm. Transfers eth. checks balaces
* Process a transaction. Run the vm. Transfers eth. Checks balances.
* @method processTx
* @param opts
* @param opts.tx {Transaction} - a transaction
Expand All @@ -27,10 +27,6 @@ module.exports = function (opts, cb) {
block = new Block()
}

if (this.opts.enableHomestead) {
tx._homestead = true
}

if (new BN(block.header.gasLimit).cmp(new BN(tx.gasLimit)) === -1) {
cb(new Error('tx has a higher gas limit than the block'))
return
Expand Down Expand Up @@ -70,7 +66,7 @@ module.exports = function (opts, cb) {
}

/**
* populates the cache with the two and from of the tx
* populates the cache with the 'to' and 'from' of the tx
*/
function populateCache (cb) {
var accounts = new Set()
Expand All @@ -85,10 +81,9 @@ module.exports = function (opts, cb) {
self.stateManager.warmCache(accounts, cb)
}

// sets up the envorment and runs a `call`
// sets up the environment and runs a `call`
function runCall (cb) {
// check to the sender's account to make sure it has enought wei and the
// correct nonce
// check to the sender's account to make sure it has enough wei and the correct nonce
var fromAccount = self.stateManager.cache.get(tx.from)
var message

Expand Down Expand Up @@ -141,10 +136,10 @@ module.exports = function (opts, cb) {
results.bloom = txLogsBloom(results.vm.logs)
fromAccount = self.stateManager.cache.get(tx.from)

// caculate the totall gas used
// caculate the total gas used
results.gasUsed = results.gasUsed.add(basefee)

// refund the accoun.stateManagert
// process any gas refund
var gasRefund = results.vm.gasRefund
if (gasRefund) {
if (gasRefund.cmp(results.gasUsed.divn(2)) === -1) {
Expand All @@ -155,7 +150,7 @@ module.exports = function (opts, cb) {
}

results.amountSpent = results.gasUsed.mul(new BN(tx.gasPrice))
// refund the left over gas amount
// refund the leftover gas amount
fromAccount.balance = new BN(tx.gasLimit).sub(results.gasUsed)
.mul(new BN(tx.gasPrice))
.add(new BN(fromAccount.balance))
Expand Down
10 changes: 4 additions & 6 deletions tests/GeneralStateTestsRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ function runTestCase (testData, t, cb) {
function (done) {
var tx = testUtil.makeTx(testData.transaction)
block = testUtil.makeBlockFromEnv(testData.env)
if (!block.isHomestead() && !testData.homestead) {
tx._homestead = false
} else {
block.isHomestead = function () {
return true
}
tx._homestead = true
tx.enableHomestead = true
block.isHomestead = function () {
return true
}

if (tx.validate()) {
Expand Down
3 changes: 2 additions & 1 deletion tests/hooked.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ tape('hooked-vm', function (test) {
}

var vm = createHookedVm({
enableHomestead: true
enableHomestead: true,
enableHomsteadReprice: true
}, hooksForBlockchainState(blockchainState))

// vm.on('step', function(stepData){
Expand Down
2 changes: 1 addition & 1 deletion tests/tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const argv = require('minimist')(process.argv.slice(2))
const async = require('async')
const tape = require('tape')
const testing = require('ethereumjs-testing')
const FORK_CONFIG = argv.fork || 'Homestead'
const FORK_CONFIG = argv.fork || 'EIP150'
const skip = [
'CreateHashCollision', // impossible hash collision on generating address
'SuicidesMixingCoinbase', // sucides to the coinbase, since we run a blockLevel we create coinbase account.
Expand Down

0 comments on commit 1971754

Please sign in to comment.