mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-10 22:13:47 +00:00
core/vm: implemented create2
This commit is contained in:
parent
797172bfe8
commit
4eae3cc25c
6 changed files with 74 additions and 4 deletions
|
|
@ -236,7 +236,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
vmerr error
|
vmerr error
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
|
createAddressFn := vm.CreateAddressFn(st.evm.ChainConfig(), st.evm.BlockNumber, sender.Address(), st.state.GetNonce(sender.Address()), st.data)
|
||||||
|
ret, _, st.gas, vmerr = evm.Create(sender, createAddressFn, st.data, st.gas, st.value)
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// Create creates a new contract using code as deployment code.
|
||||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
func (evm *EVM) Create(caller ContractRef, createAddress addressCreationFn, code []byte, gas uint64, value *big.Int) (ret []byte, _ common.Address, leftOverGas uint64, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, common.Address{}, gas, nil
|
return nil, common.Address{}, gas, nil
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +309,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
|
||||||
|
contractAddr := createAddress()
|
||||||
|
|
||||||
evm.StateDB.CreateAccount(contractAddr)
|
evm.StateDB.CreateAccount(contractAddr)
|
||||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||||
evm.StateDB.SetNonce(contractAddr, 1)
|
evm.StateDB.SetNonce(contractAddr, 1)
|
||||||
|
|
@ -361,3 +363,5 @@ func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||||
|
|
||||||
// Interpreter returns the EVM interpreter
|
// Interpreter returns the EVM interpreter
|
||||||
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||||
|
|
||||||
|
type addressCreationFn func() common.Address
|
||||||
|
|
|
||||||
|
|
@ -541,6 +541,18 @@ func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateAddressFn(chainConfig *params.ChainConfig, blockNumber *big.Int, senderAddress common.Address, nonce uint64, input []byte) func() common.Address {
|
||||||
|
if chainConfig.IsMetropolis(blockNumber) {
|
||||||
|
return func() common.Address {
|
||||||
|
return common.BytesToAddress(crypto.Keccak256(senderAddress.Bytes(), crypto.Keccak256(input))[12:])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return func() common.Address {
|
||||||
|
return crypto.CreateAddress(senderAddress, nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
value = stack.pop()
|
value = stack.pop()
|
||||||
|
|
@ -552,8 +564,46 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createAddressFn := CreateAddressFn(evm.ChainConfig(), evm.BlockNumber, contract.Address(), evm.StateDB.GetNonce(contract.Address()), input)
|
||||||
|
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
_, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
|
_, addr, returnGas, suberr := evm.Create(contract, createAddressFn, input, gas, value)
|
||||||
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
// ignore this error and pretend the operation was successful.
|
||||||
|
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||||
|
stack.push(new(big.Int))
|
||||||
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
|
stack.push(new(big.Int))
|
||||||
|
} else {
|
||||||
|
stack.push(addr.Big())
|
||||||
|
}
|
||||||
|
contract.Gas += returnGas
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(value, offset, size)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opCreate2(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
value = stack.pop()
|
||||||
|
salt = stack.pop()
|
||||||
|
offset, size = stack.pop(), stack.pop()
|
||||||
|
input = memory.Get(offset.Int64(), size.Int64())
|
||||||
|
gas = contract.Gas
|
||||||
|
)
|
||||||
|
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
||||||
|
gas -= gas / 64
|
||||||
|
}
|
||||||
|
|
||||||
|
createAddress := func() common.Address {
|
||||||
|
return common.BytesToAddress(crypto.Keccak256(contract.Address().Bytes(), salt.Bytes(), crypto.Keccak256(input))[12:])
|
||||||
|
}
|
||||||
|
|
||||||
|
contract.UseGas(gas)
|
||||||
|
_, addr, returnGas, suberr := evm.Create(contract, createAddress, input, gas, value)
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
|
|
||||||
|
|
@ -891,6 +891,15 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
writes: true,
|
writes: true,
|
||||||
clearsReturndata: true,
|
clearsReturndata: true,
|
||||||
},
|
},
|
||||||
|
CREATE2: {
|
||||||
|
execute: opCreate2,
|
||||||
|
gasCost: gasCreate,
|
||||||
|
validateStack: makeStackFunc(4, 1),
|
||||||
|
memorySize: memoryCreate2,
|
||||||
|
valid: true,
|
||||||
|
writes: true,
|
||||||
|
clearsReturndata: true,
|
||||||
|
},
|
||||||
CALL: {
|
CALL: {
|
||||||
execute: opCall,
|
execute: opCall,
|
||||||
gasCost: gasCall,
|
gasCost: gasCall,
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(1), stack.Back(2))
|
return calcMemSize(stack.Back(1), stack.Back(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memoryCreate2(stack *Stack) *big.Int {
|
||||||
|
return calcMemSize(stack.Back(2), stack.Back(3))
|
||||||
|
}
|
||||||
|
|
||||||
func memoryCall(stack *Stack) *big.Int {
|
func memoryCall(stack *Stack) *big.Int {
|
||||||
x := calcMemSize(stack.Back(5), stack.Back(6))
|
x := calcMemSize(stack.Back(5), stack.Back(6))
|
||||||
y := calcMemSize(stack.Back(3), stack.Back(4))
|
y := calcMemSize(stack.Back(3), stack.Back(4))
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,8 @@ const (
|
||||||
DELEGATECALL
|
DELEGATECALL
|
||||||
STATIC_CALL
|
STATIC_CALL
|
||||||
|
|
||||||
|
CREATE2 OpCode = 0xfb
|
||||||
|
|
||||||
REVERT = 0xfd
|
REVERT = 0xfd
|
||||||
SELFDESTRUCT = 0xff
|
SELFDESTRUCT = 0xff
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue