Skip to content

Commit 21cf775

Browse files
jwasingerrmeissner
authored andcommitted
add support for CREATE2
trap if not constantinople add check if nonce or code at address Fix lint errors Refactoring Fix lint Use invalid init code on colission Fix lint
1 parent 41e3f63 commit 21cf775

File tree

3 files changed

+87
-33
lines changed

3 files changed

+87
-33
lines changed

lib/opFns.js

Lines changed: 31 additions & 0 deletions
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 hashingq
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)

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: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const BN = ethUtil.BN
55
const exceptions = require('./exceptions.js')
66

77
const ERROR = exceptions.ERROR
8+
const EMPTY_CODE_HASH = ethUtil.keccak256()
89

910
/**
1011
* runs a CALL operation
@@ -47,6 +48,7 @@ module.exports = function (opts, cb) {
4748
var selfdestruct = opts.selfdestruct || opts.suicides
4849
var delegatecall = opts.delegatecall || false
4950
var isStatic = opts.static || false
51+
var salt = opts.salt || null
5052

5153
txValue = new BN(txValue)
5254

@@ -77,41 +79,14 @@ module.exports = function (opts, cb) {
7779
code = txData
7880
txData = undefined
7981
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-
}
8582

86-
async.series([
87-
newContractEvent,
88-
getAccount
89-
], done)
90-
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-
}
83+
if (salt) {
84+
createdAddress = toAddress = ethUtil.generateAddress2(caller, salt, code)
85+
} else {
86+
createdAddress = toAddress = ethUtil.generateAddress(caller, newNonce.toArray())
87+
}
10588

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-
})
89+
checkAccountState(createdAddress, setupNewContract, done)
11590
} else {
11691
// else load the `to` account
11792
stateManager.getAccount(toAddress, function (err, account) {
@@ -121,6 +96,53 @@ module.exports = function (opts, cb) {
12196
}
12297
}
12398

99+
function checkAccountState (address, next, done) {
100+
stateManager.getAccount(address, function (err, account) {
101+
if (err) {
102+
done(err)
103+
return
104+
}
105+
106+
if ((account.nonce && new BN(account.nonce) > 0) || account.codeHash.compare(EMPTY_CODE_HASH) !== 0) {
107+
toAccount = account
108+
code = new Buffer('0xfe', 'hex') // Invalid init code
109+
done()
110+
return
111+
}
112+
113+
next(address, done)
114+
})
115+
}
116+
117+
function setupNewContract (address, done) {
118+
stateManager.clearContractStorage(address, function (err) {
119+
if (err) {
120+
done(err)
121+
return
122+
}
123+
124+
async.series([
125+
newContractEvent,
126+
getAccount
127+
], done)
128+
129+
function newContractEvent (callback) {
130+
self.emit('newContract', {
131+
address: address,
132+
code: code
133+
}, callback)
134+
}
135+
136+
function getAccount (callback) {
137+
stateManager.getAccount(address, function (err, account) {
138+
toAccount = account
139+
toAccount.nonce = new BN(toAccount.nonce).addn(1).toArrayLike(Buffer)
140+
callback(err)
141+
})
142+
}
143+
})
144+
}
145+
124146
function subTxValue (cb) {
125147
if (delegatecall) {
126148
cb()

0 commit comments

Comments
 (0)