Skip to content

Commit 5fdce83

Browse files
authored
Merge pull request #329 from ethereumjs/eip-1014
EIP 1014 CREATE2
2 parents 66c8a36 + 6efe3d1 commit 5fdce83

File tree

3 files changed

+91
-35
lines changed

3 files changed

+91
-35
lines changed

lib/opFns.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,37 @@ module.exports = {
514514
checkOutOfGas(runState, options)
515515
makeCall(runState, options, localOpts, done)
516516
},
517+
CREATE2: function (value, offset, length, salt, runState, done) {
518+
if (!runState._common.gteHardfork('constantinople')) {
519+
trap(ERROR.INVALID_OPCODE)
520+
}
521+
522+
if (runState.static) {
523+
trap(ERROR.STATIC_STATE_CHANGE)
524+
}
525+
526+
var data = memLoad(runState, offset, length)
527+
528+
// set up config
529+
var options = {
530+
value: value,
531+
data: data,
532+
salt: salt.toBuffer('be', 32)
533+
}
534+
535+
var localOpts = {
536+
inOffset: offset,
537+
inLength: length,
538+
outOffset: new BN(0),
539+
outLength: new BN(0)
540+
}
541+
542+
// Deduct gas costs for hashing
543+
subGas(runState, new BN(runState._common.param('gasPrices', 'sha3Word')).imul(length.divCeil(new BN(32))))
544+
checkCallMemCost(runState, options, localOpts)
545+
checkOutOfGas(runState, options)
546+
makeCall(runState, options, localOpts, done)
547+
},
517548
CALL: function (gasLimit, toAddress, value, inOffset, inLength, outOffset, outLength, runState, done) {
518549
var stateManager = runState.stateManager
519550
toAddress = addressToBuffer(toAddress)
@@ -980,7 +1011,7 @@ function makeCall (runState, callOptions, localOpts, cb) {
9801011
if (results.vm.return && (!results.vm.exceptionError || results.vm.exceptionError.error === ERROR.REVERT)) {
9811012
memStore(runState, localOpts.outOffset, results.vm.return, new BN(0), localOpts.outLength, false)
9821013

983-
if (results.vm.exceptionError && results.vm.exceptionError.error === ERROR.REVERT && runState.opName === 'CREATE') {
1014+
if (results.vm.exceptionError && results.vm.exceptionError.error === ERROR.REVERT && isCreateOpCode(runState.opName)) {
9841015
runState.lastReturned = results.vm.return
9851016
}
9861017

@@ -1018,6 +1049,10 @@ function makeCall (runState, callOptions, localOpts, cb) {
10181049
}
10191050
}
10201051

1052+
function isCreateOpCode (opName) {
1053+
return opName === 'CREATE' || opName === 'CREATE2'
1054+
}
1055+
10211056
function getContractStorage (runState, address, key, cb) {
10221057
if (runState._common.gteHardfork('constantinople')) {
10231058
async.parallel({

lib/opcodes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ const codes = {
152152
0xf2: ['CALLCODE', 700, 7, 1, true, true],
153153
0xf3: ['RETURN', 0, 2, 0, false],
154154
0xf4: ['DELEGATECALL', 700, 6, 1, true, true],
155+
0xf5: ['CREATE2', 32000, 4, 1, true, true],
155156
0xfa: ['STATICCALL', 700, 6, 1, true, true],
156157
0xfd: ['REVERT', 0, 2, 0, false],
157158

lib/runCall.js

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module.exports = function (opts, cb) {
4747
var selfdestruct = opts.selfdestruct || opts.suicides
4848
var delegatecall = opts.delegatecall || false
4949
var isStatic = opts.static || false
50+
var salt = opts.salt || null
5051

5152
txValue = new BN(txValue)
5253

@@ -77,41 +78,14 @@ module.exports = function (opts, cb) {
7778
code = txData
7879
txData = undefined
7980
var newNonce = new BN(account.nonce).subn(1)
80-
createdAddress = toAddress = ethUtil.generateAddress(caller, newNonce.toArray())
81-
stateManager.clearContractStorage(createdAddress, function (err) {
82-
if (err) {
83-
done(err)
84-
}
85-
86-
async.series([
87-
newContractEvent,
88-
getAccount
89-
], done)
9081

91-
function newContractEvent (callback) {
92-
/**
93-
* The `newContract` event when a contract is created
94-
*
95-
* @event Event: newContract
96-
* @type {Object}
97-
* @property {Buffer} address the created address for the new contract (type `Buffer | Uint8Array`)
98-
* @property {Buffer} code the deployment bytecode for reference (type `Buffer | Uint8Array`)
99-
*/
100-
self.emit('newContract', {
101-
address: createdAddress,
102-
code: code
103-
}, callback)
104-
}
82+
if (salt) {
83+
createdAddress = toAddress = ethUtil.generateAddress2(caller, salt, code)
84+
} else {
85+
createdAddress = toAddress = ethUtil.generateAddress(caller, newNonce.toArray())
86+
}
10587

106-
function getAccount (callback) {
107-
stateManager.getAccount(createdAddress, function (err, account) {
108-
toAccount = account
109-
const NONCE_OFFSET = 1
110-
toAccount.nonce = new BN(toAccount.nonce).addn(NONCE_OFFSET).toArrayLike(Buffer)
111-
callback(err)
112-
})
113-
}
114-
})
88+
checkAccountState(createdAddress, setupNewContract, done)
11589
} else {
11690
// else load the `to` account
11791
stateManager.getAccount(toAddress, function (err, account) {
@@ -121,6 +95,53 @@ module.exports = function (opts, cb) {
12195
}
12296
}
12397

98+
function checkAccountState (address, next, done) {
99+
stateManager.getAccount(address, function (err, account) {
100+
if (err) {
101+
done(err)
102+
return
103+
}
104+
105+
if ((account.nonce && new BN(account.nonce) > 0) || account.codeHash.compare(ethUtil.KECCAK256_NULL) !== 0) {
106+
toAccount = account
107+
code = new Buffer('fe', 'hex') // Invalid init code
108+
done()
109+
return
110+
}
111+
112+
next(address, done)
113+
})
114+
}
115+
116+
function setupNewContract (address, done) {
117+
stateManager.clearContractStorage(address, function (err) {
118+
if (err) {
119+
done(err)
120+
return
121+
}
122+
123+
async.series([
124+
newContractEvent,
125+
getAccount
126+
], done)
127+
128+
function newContractEvent (callback) {
129+
self.emit('newContract', {
130+
address: address,
131+
code: code
132+
}, callback)
133+
}
134+
135+
function getAccount (callback) {
136+
stateManager.getAccount(address, function (err, account) {
137+
toAccount = account
138+
toAccount.nonce = new BN(toAccount.nonce).addn(1).toArrayLike(Buffer)
139+
callback(err)
140+
})
141+
}
142+
})
143+
}
144+
124145
function subTxValue (cb) {
125146
if (delegatecall) {
126147
cb()
@@ -199,7 +220,6 @@ module.exports = function (opts, cb) {
199220
var totalGas = results.gasUsed
200221
if (!results.runState.vmError) {
201222
var returnFee = new BN(results.return.length * self._common.param('gasPrices', 'createData'))
202-
203223
totalGas = totalGas.add(returnFee)
204224
}
205225
// if not enough gas

0 commit comments

Comments
 (0)