aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/bloombits/matcher.go10
-rw-r--r--core/bloombits/matcher_test.go2
-rw-r--r--core/state_transition.go6
-rw-r--r--core/tx_pool.go2
-rw-r--r--core/vm/evm.go48
-rw-r--r--core/vm/gas_table.go16
-rw-r--r--core/vm/instructions.go60
-rw-r--r--core/vm/jump_table.go15
-rw-r--r--core/vm/memory_table.go4
-rw-r--r--core/vm/opcodes.go6
10 files changed, 142 insertions, 27 deletions
diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go
index 8d78adb75..3ec0d5ae9 100644
--- a/core/bloombits/matcher.go
+++ b/core/bloombits/matcher.go
@@ -59,7 +59,7 @@ type partialMatches struct {
// It can also have the actual results set to be used as a delivery data struct.
//
// The contest and error fields are used by the light client to terminate matching
-// early if an error is enountered on some path of the pipeline.
+// early if an error is encountered on some path of the pipeline.
type Retrieval struct {
Bit uint
Sections []uint64
@@ -218,7 +218,7 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin
// run creates a daisy-chain of sub-matchers, one for the address set and one
// for each topic set, each sub-matcher receiving a section only if the previous
// ones have all found a potential match in one of the blocks of the section,
-// then binary AND-ing its own matches and forwaring the result to the next one.
+// then binary AND-ing its own matches and forwarding the result to the next one.
//
// The method starts feeding the section indexes into the first sub-matcher on a
// new goroutine and returns a sink channel receiving the results.
@@ -543,7 +543,7 @@ func (s *MatcherSession) Error() error {
}
// AllocateRetrieval assigns a bloom bit index to a client process that can either
-// immediately reuest and fetch the section contents assigned to this bit or wait
+// immediately request and fetch the section contents assigned to this bit or wait
// a little while for more sections to be requested.
func (s *MatcherSession) AllocateRetrieval() (uint, bool) {
fetcher := make(chan uint)
@@ -599,8 +599,8 @@ func (s *MatcherSession) DeliverSections(bit uint, sections []uint64, bitsets []
}
}
-// Multiplex polls the matcher session for rerieval tasks and multiplexes it into
-// the reuested retrieval queue to be serviced together with other sessions.
+// Multiplex polls the matcher session for retrieval tasks and multiplexes it into
+// the requested retrieval queue to be serviced together with other sessions.
//
// This method will block for the lifetime of the session. Even after termination
// of the session, any request in-flight need to be responded to! Empty responses
diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go
index 7a5f78ef3..91143e525 100644
--- a/core/bloombits/matcher_test.go
+++ b/core/bloombits/matcher_test.go
@@ -156,7 +156,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in
// Track the number of retrieval requests made
var requested uint32
- // Start the matching session for the filter and the retriver goroutines
+ // Start the matching session for the filter and the retriever goroutines
quit := make(chan struct{})
matches := make(chan uint64, 16)
diff --git a/core/state_transition.go b/core/state_transition.go
index 5654cd01e..fda081b7d 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -35,7 +35,7 @@ var (
The State Transitioning Model
A state transition is a change made when a transaction is applied to the current world state
-The state transitioning model does all all the necessary work to work out a valid new state root.
+The state transitioning model does all the necessary work to work out a valid new state root.
1) Nonce handling
2) Pre pay gas
@@ -178,8 +178,8 @@ func (st *StateTransition) preCheck() error {
}
// TransitionDb will transition the state by applying the current message and
-// returning the result including the the used gas. It returns an error if it
-// failed. An error indicates a consensus issue.
+// returning the result including the used gas. It returns an error if failed.
+// An error indicates a consensus issue.
func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) {
if err = st.preCheck(); err != nil {
return
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 9c958e3b6..cfc92eb8b 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -130,7 +130,7 @@ type TxPoolConfig struct {
PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)
- AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account
+ AccountSlots uint64 // Number of executable transaction slots guaranteed per account
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 69c8ec478..0189351e7 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -319,9 +319,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
return ret, contract.Gas, err
}
-// 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) {
-
+// create creates a new contract using code as deployment code.
+func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth) {
@@ -330,39 +329,38 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, common.Address{}, gas, ErrInsufficientBalance
}
- // Ensure there's no existing contract already at the designated address
nonce := evm.StateDB.GetNonce(caller.Address())
evm.StateDB.SetNonce(caller.Address(), nonce+1)
- contractAddr = crypto.CreateAddress(caller.Address(), nonce)
- contractHash := evm.StateDB.GetCodeHash(contractAddr)
- if evm.StateDB.GetNonce(contractAddr) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
+ // Ensure there's no existing contract already at the designated address
+ contractHash := evm.StateDB.GetCodeHash(address)
+ if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
return nil, common.Address{}, 0, ErrContractAddressCollision
}
// Create a new account on the state
snapshot := evm.StateDB.Snapshot()
- evm.StateDB.CreateAccount(contractAddr)
+ evm.StateDB.CreateAccount(address)
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
- evm.StateDB.SetNonce(contractAddr, 1)
+ evm.StateDB.SetNonce(address, 1)
}
- evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
+ evm.Transfer(evm.StateDB, caller.Address(), address, value)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
- contract := NewContract(caller, AccountRef(contractAddr), value, gas)
- contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
+ contract := NewContract(caller, AccountRef(address), value, gas)
+ contract.SetCallCode(&address, crypto.Keccak256Hash(code), code)
if evm.vmConfig.NoRecursion && evm.depth > 0 {
- return nil, contractAddr, gas, nil
+ return nil, address, gas, nil
}
if evm.vmConfig.Debug && evm.depth == 0 {
- evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value)
+ evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value)
}
start := time.Now()
- ret, err = run(evm, contract, nil)
+ ret, err := run(evm, contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
@@ -373,7 +371,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if err == nil && !maxCodeSizeExceeded {
createDataGas := uint64(len(ret)) * params.CreateDataGas
if contract.UseGas(createDataGas) {
- evm.StateDB.SetCode(contractAddr, ret)
+ evm.StateDB.SetCode(address, ret)
} else {
err = ErrCodeStoreOutOfGas
}
@@ -395,7 +393,23 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
}
- return ret, contractAddr, contract.Gas, err
+ return ret, address, contract.Gas, err
+
+}
+
+// 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) {
+ contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
+ return evm.create(caller, code, gas, value, contractAddr)
+}
+
+// Create2 creates a new contract using code as deployment code.
+//
+// The different between Create2 with Create is Create2 uses sha3(msg.sender ++ salt ++ init_code)[12:]
+// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
+func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
+ contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), code)
+ return evm.create(caller, code, gas, endowment, contractAddr)
}
// ChainConfig returns the environment's chain configuration
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 0764c67a4..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)
@@ -289,6 +293,18 @@ func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
return gas, nil
}
+func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+ var overflow bool
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow {
+ return 0, errGasUintOverflow
+ }
+ return gas, nil
+}
+
func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.Balance, nil
}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 1ec13ba35..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
@@ -665,6 +697,34 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
return nil, nil
}
+func opCreate2(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+ var (
+ endowment = stack.pop()
+ offset, size = stack.pop(), stack.pop()
+ salt = stack.pop()
+ input = memory.Get(offset.Int64(), size.Int64())
+ gas = contract.Gas
+ )
+
+ // Apply EIP150
+ gas -= gas / 64
+ contract.UseGas(gas)
+ res, addr, returnGas, suberr := evm.Create2(contract, input, gas, endowment, salt)
+ // Push item on the stack based on the returned error.
+ if suberr != nil {
+ stack.push(evm.interpreter.intPool.getZero())
+ } else {
+ stack.push(addr.Big())
+ }
+ contract.Gas += returnGas
+ evm.interpreter.intPool.put(endowment, offset, size, salt)
+
+ if suberr == errExecutionReverted {
+ return res, nil
+ }
+ return nil, nil
+}
+
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// Pop gas. The actual gas in in evm.callGasTemp.
evm.interpreter.intPool.put(stack.pop())
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 111a9b798..f387e6133 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -80,6 +80,21 @@ 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,
+ validateStack: makeStackFunc(4, 1),
+ memorySize: memoryCreate2,
+ valid: true,
+ writes: true,
+ returns: true,
+ }
return instructionSet
}
diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go
index ab49ebb38..8fa6c90ca 100644
--- a/core/vm/memory_table.go
+++ b/core/vm/memory_table.go
@@ -58,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(2))
}
+func memoryCreate2(stack *Stack) *big.Int {
+ return calcMemSize(stack.Back(1), stack.Back(2))
+}
+
func memoryCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go
index 6c12c50e5..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.
@@ -209,6 +210,7 @@ const (
CALLCODE
RETURN
DELEGATECALL
+ CREATE2
STATICCALL = 0xfa
REVERT = 0xfd
@@ -266,6 +268,7 @@ var opCodeToString = map[OpCode]string{
EXTCODECOPY: "EXTCODECOPY",
RETURNDATASIZE: "RETURNDATASIZE",
RETURNDATACOPY: "RETURNDATACOPY",
+ EXTCODEHASH: "EXTCODEHASH",
// 0x40 range - block operations.
BLOCKHASH: "BLOCKHASH",
@@ -370,6 +373,7 @@ var opCodeToString = map[OpCode]string{
RETURN: "RETURN",
CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL",
+ CREATE2: "CREATE2",
STATICCALL: "STATICCALL",
REVERT: "REVERT",
SELFDESTRUCT: "SELFDESTRUCT",
@@ -433,6 +437,7 @@ var stringToOp = map[string]OpCode{
"EXTCODECOPY": EXTCODECOPY,
"RETURNDATASIZE": RETURNDATASIZE,
"RETURNDATACOPY": RETURNDATACOPY,
+ "EXTCODEHASH": EXTCODEHASH,
"BLOCKHASH": BLOCKHASH,
"COINBASE": COINBASE,
"TIMESTAMP": TIMESTAMP,
@@ -521,6 +526,7 @@ var stringToOp = map[string]OpCode{
"LOG3": LOG3,
"LOG4": LOG4,
"CREATE": CREATE,
+ "CREATE2": CREATE2,
"CALL": CALL,
"RETURN": RETURN,
"CALLCODE": CALLCODE,