diff --git a/lib/opFns.js b/lib/opFns.js index 56e2f67f80f..e1b7c68af88 100644 --- a/lib/opFns.js +++ b/lib/opFns.js @@ -519,7 +519,7 @@ module.exports = { checkOutOfGas(runState, options) makeCall(runState, options, localOpts, done) }, - CREATE2: function (value, offset, length, runState, done) { + CREATE2: function (value, offset, length, salt, runState, done) { if (!runState._common.gteHardfork('constantinople')) { trap(ERROR.INVALID_OPCODE) } @@ -533,17 +533,20 @@ module.exports = { // set up config var options = { value: value, - data: data + data: data, + salt: salt.toBuffer('be', 32) } var localOpts = { inOffset: offset, inLength: length, outOffset: new BN(0), - outLength: new BN(0), - salt: salt + outLength: new BN(0) } + // Deduct gas costs for hashing + // TODO this is not yet part of the tests + // subGas(runState, new BN(runState._common.param('gasPrices', 'sha3Word')).imul(length.divCeil(new BN(32)))) checkCallMemCost(runState, options, localOpts) checkOutOfGas(runState, options) makeCall(runState, options, localOpts, done) diff --git a/lib/runCall.js b/lib/runCall.js index 4fed3c028b5..691e381a2ac 100644 --- a/lib/runCall.js +++ b/lib/runCall.js @@ -5,6 +5,7 @@ const BN = ethUtil.BN const exceptions = require('./exceptions.js') const ERROR = exceptions.ERROR +const EMPTY_CODE_HASH = ethUtil.keccak256() /** * runs a CALL operation @@ -69,39 +70,53 @@ module.exports = function (opts, cb) { code = txData txData = undefined var newNonce = new BN(account.nonce).subn(1) - + if (salt) { createdAddress = toAddress = ethUtil.generateAddress2(caller, salt, code) } else { createdAddress = toAddress = ethUtil.generateAddress(caller, newNonce.toArray()) } - stateManager.clearContractStorage(createdAddress, function (err) { + stateManager.getAccount(createdAddress, function (err, account) { if (err) { done(err) + return } - async.series([ - newContractEvent, - getAccount - ], done) - - function newContractEvent (callback) { - self.emit('newContract', { - address: createdAddress, - code: code - }, callback) + if ((account.nonce && new BN(account.nonce) > 0) || account.codeHash.compare(EMPTY_CODE_HASH) != 0) { + done(ERROR.INVALID_OPCODE) + return } - function getAccount (callback) { - stateManager.getAccount(createdAddress, function (err, account) { - toAccount = account - const NONCE_OFFSET = 1 - toAccount.nonce = new BN(toAccount.nonce).addn(NONCE_OFFSET).toArrayLike(Buffer) - callback(err) - }) - } + stateManager.clearContractStorage(createdAddress, function (err) { + if (err) { + done(err) + return + } + + async.series([ + newContractEvent, + getAccount + ], done) + + function newContractEvent (callback) { + self.emit('newContract', { + address: createdAddress, + code: code + }, callback) + } + + function getAccount (callback) { + stateManager.getAccount(createdAddress, function (err, account) { + toAccount = account + const NONCE_OFFSET = 1 + toAccount.nonce = new BN(toAccount.nonce).addn(NONCE_OFFSET).toArrayLike(Buffer) + callback(err) + }) + } + }) }) + } else { // else load the `to` account toAccount = stateManager.cache.get(toAddress) diff --git a/package.json b/package.json index 907d8fafcf7..2188a1db415 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "ethereumjs-account": "^2.0.3", "ethereumjs-block": "~1.7.0", "ethereumjs-common": "~0.4.0", - "ethereumjs-util": "git+https://github.com/ethereumjs/ethereumjs-util#create2", + "ethereumjs-util": "git+https://github.com/ethereumjs/ethereumjs-util.git#create2", "fake-merkle-patricia-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1", "merkle-patricia-tree": "^2.1.2", @@ -49,7 +49,7 @@ "babel-preset-env": "^1.6.1", "coveralls": "^3.0.0", "ethereumjs-blockchain": "~2.1.0", - "ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.1.1", + "ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.2.2", "ethereumjs-tx": "1.3.3", "istanbul": "^0.4.5", "level": "^1.4.0",