aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/vm/gas_table.go4
-rw-r--r--core/vm/instructions.go32
-rw-r--r--core/vm/jump_table.go6
-rw-r--r--core/vm/opcodes.go3
-rw-r--r--params/config.go2
-rw-r--r--params/gas_table.go17
6 files changed, 63 insertions, 1 deletions
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index e130406ec..f9eea319e 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -241,6 +241,10 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta
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) {
var overflow bool
gas, err := memoryGasCost(mem, memorySize)
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index b25c0111a..122fc21e4 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -496,6 +496,38 @@ func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
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) {
stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
return nil, nil
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 014496567..f387e6133 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -80,6 +80,12 @@ func newConstantinopleInstructionSet() [256]operation {
validateStack: makeStackFunc(2, 1),
valid: true,
}
+ instructionSet[EXTCODEHASH] = operation{
+ execute: opExtCodeHash,
+ gasCost: gasExtCodeHash,
+ validateStack: makeStackFunc(1, 1),
+ valid: true,
+ }
instructionSet[CREATE2] = operation{
execute: opCreate2,
gasCost: gasCreate2,
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index 84426a28a..4349ffd29 100644
--- a/core/vm/opcodes.go
+++ b/core/vm/opcodes.go
@@ -90,6 +90,7 @@ const (
EXTCODECOPY
RETURNDATASIZE
RETURNDATACOPY
+ EXTCODEHASH
)
// 0x40 range - block operations.
@@ -267,6 +268,7 @@ var opCodeToString = map[OpCode]string{
EXTCODECOPY: "EXTCODECOPY",
RETURNDATASIZE: "RETURNDATASIZE",
RETURNDATACOPY: "RETURNDATACOPY",
+ EXTCODEHASH: "EXTCODEHASH",
// 0x40 range - block operations.
BLOCKHASH: "BLOCKHASH",
@@ -435,6 +437,7 @@ var stringToOp = map[string]OpCode{
"EXTCODECOPY": EXTCODECOPY,
"RETURNDATASIZE": RETURNDATASIZE,
"RETURNDATACOPY": RETURNDATACOPY,
+ "EXTCODEHASH": EXTCODEHASH,
"BLOCKHASH": BLOCKHASH,
"COINBASE": COINBASE,
"TIMESTAMP": TIMESTAMP,
diff --git a/params/config.go b/params/config.go
index 6e6a5cb8b..b9e9bb8d6 100644
--- a/params/config.go
+++ b/params/config.go
@@ -211,6 +211,8 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
return GasTableHomestead
}
switch {
+ case c.IsConstantinople(num):
+ return GasTableConstantinople
case c.IsEIP158(num):
return GasTableEIP158
case c.IsEIP150(num):
diff --git a/params/gas_table.go b/params/gas_table.go
index d33bebbe5..6c4a38269 100644
--- a/params/gas_table.go
+++ b/params/gas_table.go
@@ -20,6 +20,7 @@ package params
type GasTable struct {
ExtcodeSize uint64
ExtcodeCopy uint64
+ ExtcodeHash uint64
Balance uint64
SLoad uint64
Calls uint64
@@ -63,7 +64,7 @@ var (
CreateBySuicide: 25000,
}
// GasTableEIP158 contain the gas re-prices for
- // the EIP15* phase.
+ // the EIP155/EIP158 phase.
GasTableEIP158 = GasTable{
ExtcodeSize: 700,
ExtcodeCopy: 700,
@@ -75,4 +76,18 @@ var (
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,
+ }
)