Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP 150 finished #143

Merged
merged 24 commits into from
Jul 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4970be5
Remove unused _homestead flag
axic Oct 24, 2016
2f589c9
Add homesteadReprice option
axic Oct 24, 2016
254522e
Implement EIP150.1c (suicide new account cost)
axic Oct 24, 2016
3eff9d3
Implement EIP150.1b (all but 64th rule)
axic Oct 26, 2016
5eaab3d
Increase gas baseCosts for EIP150
sdtsui Jun 25, 2017
06356a9
Improve comments in runTx
sdtsui Jun 25, 2017
2f74596
Change gas baseCost to finalized EIP150 spec, 700 instead of 4000
sdtsui Jun 25, 2017
cf667f4
Add gasLimit to CREATE and CALL opFns
sdtsui Jun 25, 2017
1b9980c
Resolve conflicts, bump FORK_CONFIG, bump ethereumjs-testing version
sdtsui Jun 29, 2017
0245c77
Separate OOG from checkCallMemCost, so EIP150 limit can be applied
sdtsui Jul 3, 2017
44d10c8
Cleanup repo, remove support for flags in calcCallLimit
sdtsui Jul 3, 2017
1d27a58
Fix application of stipend in CALL
sdtsui Jul 4, 2017
8d56f86
Fix from @inclu-media for checkOutOfGas - 335 failing tests
sdtsui Jul 4, 2017
5432e8e
Fix callcall_00_OOGE test with @cdetrio
sdtsui Jul 5, 2017
78357eb
Cleanup, remove commented code
sdtsui Jul 5, 2017
001033c
Add @inclu-media\'s use of BN in checkOutofGas
sdtsui Jul 5, 2017
7d841dc
Fixed last commit (code parts left)
Jul 5, 2017
b5da2a1
fix some initializations, validate results return length
hugo-dc Jul 6, 2017
86e8895
Removed double-run of checkCallMemCost/checkOutOfGas in CREATE opcode…
Jul 7, 2017
67c9749
fixed refund handling in SUICIDE
inclu-media Jul 9, 2017
095b8ac
subGas in CALLCODE, unnecessary stateManager call removed
inclu-media Jul 9, 2017
fb2172e
Fix lint errors in opFns, runCode, and test hooks
sdtsui Jul 10, 2017
b0b1b07
Removed unintentionally added package-lock.json file, added package-l…
Jul 10, 2017
b98b61d
Merge branch 'master' into eip150-final
Jul 16, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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