core/vm, params: implement EXTCODEHASH opcode (#17202)

* core/vm, params: implement EXTCODEHASH opcode

* core, params: tiny fixes and polish

* core: add function description
This commit is contained in:
gary rong 2018-07-24 23:06:40 +08:00 committed by Péter Szilágyi
parent cab1cff11c
commit 2433349c80
6 changed files with 63 additions and 1 deletions

View File

@ -241,6 +241,10 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta
return gas, nil return gas, nil
} }
func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.ExtcodeHash, nil
}
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool var overflow bool
gas, err := memoryGasCost(mem, memorySize) gas, err := memoryGasCost(mem, memorySize)

View File

@ -496,6 +496,38 @@ func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
return nil, nil return nil, nil
} }
// opExtCodeHash returns the code hash of a specified account.
// There are several cases when the function is called, while we can relay everything
// to `state.GetCodeHash` function to ensure the correctness.
// (1) Caller tries to get the code hash of a normal contract account, state
// should return the relative code hash and set it as the result.
//
// (2) Caller tries to get the code hash of a non-existent account, state should
// return common.Hash{} and zero will be set as the result.
//
// (3) Caller tries to get the code hash for an account without contract code,
// state should return emptyCodeHash(0xc5d246...) as the result.
//
// (4) Caller tries to get the code hash of a precompiled account, the result
// should be zero or emptyCodeHash.
//
// It is worth noting that in order to avoid unnecessary create and clean,
// all precompile accounts on mainnet have been transferred 1 wei, so the return
// here should be emptyCodeHash.
// If the precompile account is not transferred any amount on a private or
// customized chain, the return value will be zero.
//
// (5) Caller tries to get the code hash for an account which is marked as suicided
// in the current transaction, the code hash of this account should be returned.
//
// (6) Caller tries to get the code hash for an account which is marked as deleted,
// this account should be regarded as a non-existent account and zero should be returned.
func opExtCodeHash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
slot := stack.peek()
slot.SetBytes(evm.StateDB.GetCodeHash(common.BigToAddress(slot)).Bytes())
return nil, nil
}
func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice)) stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
return nil, nil return nil, nil

View File

@ -80,6 +80,12 @@ func newConstantinopleInstructionSet() [256]operation {
validateStack: makeStackFunc(2, 1), validateStack: makeStackFunc(2, 1),
valid: true, valid: true,
} }
instructionSet[EXTCODEHASH] = operation{
execute: opExtCodeHash,
gasCost: gasExtCodeHash,
validateStack: makeStackFunc(1, 1),
valid: true,
}
instructionSet[CREATE2] = operation{ instructionSet[CREATE2] = operation{
execute: opCreate2, execute: opCreate2,
gasCost: gasCreate2, gasCost: gasCreate2,

View File

@ -90,6 +90,7 @@ const (
EXTCODECOPY EXTCODECOPY
RETURNDATASIZE RETURNDATASIZE
RETURNDATACOPY RETURNDATACOPY
EXTCODEHASH
) )
// 0x40 range - block operations. // 0x40 range - block operations.
@ -267,6 +268,7 @@ var opCodeToString = map[OpCode]string{
EXTCODECOPY: "EXTCODECOPY", EXTCODECOPY: "EXTCODECOPY",
RETURNDATASIZE: "RETURNDATASIZE", RETURNDATASIZE: "RETURNDATASIZE",
RETURNDATACOPY: "RETURNDATACOPY", RETURNDATACOPY: "RETURNDATACOPY",
EXTCODEHASH: "EXTCODEHASH",
// 0x40 range - block operations. // 0x40 range - block operations.
BLOCKHASH: "BLOCKHASH", BLOCKHASH: "BLOCKHASH",
@ -435,6 +437,7 @@ var stringToOp = map[string]OpCode{
"EXTCODECOPY": EXTCODECOPY, "EXTCODECOPY": EXTCODECOPY,
"RETURNDATASIZE": RETURNDATASIZE, "RETURNDATASIZE": RETURNDATASIZE,
"RETURNDATACOPY": RETURNDATACOPY, "RETURNDATACOPY": RETURNDATACOPY,
"EXTCODEHASH": EXTCODEHASH,
"BLOCKHASH": BLOCKHASH, "BLOCKHASH": BLOCKHASH,
"COINBASE": COINBASE, "COINBASE": COINBASE,
"TIMESTAMP": TIMESTAMP, "TIMESTAMP": TIMESTAMP,

View File

@ -211,6 +211,8 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
return GasTableHomestead return GasTableHomestead
} }
switch { switch {
case c.IsConstantinople(num):
return GasTableConstantinople
case c.IsEIP158(num): case c.IsEIP158(num):
return GasTableEIP158 return GasTableEIP158
case c.IsEIP150(num): case c.IsEIP150(num):

View File

@ -20,6 +20,7 @@ package params
type GasTable struct { type GasTable struct {
ExtcodeSize uint64 ExtcodeSize uint64
ExtcodeCopy uint64 ExtcodeCopy uint64
ExtcodeHash uint64
Balance uint64 Balance uint64
SLoad uint64 SLoad uint64
Calls uint64 Calls uint64
@ -63,7 +64,7 @@ var (
CreateBySuicide: 25000, CreateBySuicide: 25000,
} }
// GasTableEIP158 contain the gas re-prices for // GasTableEIP158 contain the gas re-prices for
// the EIP15* phase. // the EIP155/EIP158 phase.
GasTableEIP158 = GasTable{ GasTableEIP158 = GasTable{
ExtcodeSize: 700, ExtcodeSize: 700,
ExtcodeCopy: 700, ExtcodeCopy: 700,
@ -73,6 +74,20 @@ var (
Suicide: 5000, Suicide: 5000,
ExpByte: 50, ExpByte: 50,
CreateBySuicide: 25000,
}
// GasTableConstantinople contain the gas re-prices for
// the constantinople phase.
GasTableConstantinople = GasTable{
ExtcodeSize: 700,
ExtcodeCopy: 700,
ExtcodeHash: 400,
Balance: 400,
SLoad: 200,
Calls: 700,
Suicide: 5000,
ExpByte: 50,
CreateBySuicide: 25000, CreateBySuicide: 25000,
} }
) )