mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
Reduced the overhead caused by all the diffirent implementations of the vm.Environment interface. Where previously the Environment was an interface it has now become an implementation it self using several new easy to implement interfaces such as the Backend that takes care of the state and CallContext which takes care of the EVM calling conventions. Most of these interfaces have been implemented in the core package with the exception of the test suit which uses a combination of the core package implementations and a mix of its own. This will reduce the amount of extra overhead when changing an interface, such as adding a new method or changing a method signature.
142 lines
4.9 KiB
Go
142 lines
4.9 KiB
Go
// Copyright 2015 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package core
|
|
|
|
import (
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/logger"
|
|
"github.com/ethereum/go-ethereum/logger/glog"
|
|
)
|
|
|
|
var (
|
|
big8 = big.NewInt(8)
|
|
big32 = big.NewInt(32)
|
|
)
|
|
|
|
// StateProcessor is a basic Processor, which takes care of transitioning
|
|
// state from one point to another.
|
|
//
|
|
// StateProcessor implements Processor.
|
|
type StateProcessor struct {
|
|
config *ChainConfig
|
|
bc *BlockChain
|
|
}
|
|
|
|
// NewStateProcessor initialises a new StateProcessor.
|
|
func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor {
|
|
return &StateProcessor{
|
|
config: config,
|
|
bc: bc,
|
|
}
|
|
}
|
|
|
|
// Process processes the state changes according to the Ethereum rules by running
|
|
// the transaction messages using the statedb and applying any rewards to both
|
|
// the processor (coinbase) and any included uncles.
|
|
//
|
|
// Process returns the receipts and logs accumulated during the process and
|
|
// returns the amount of gas that was used in the process. If any of the
|
|
// transactions failed to execute due to insufficient gas it will return an error.
|
|
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
|
var (
|
|
receipts types.Receipts
|
|
totalUsedGas = big.NewInt(0)
|
|
err error
|
|
header = block.Header()
|
|
allLogs vm.Logs
|
|
gp = new(GasPool).AddGas(block.GasLimit())
|
|
)
|
|
// Mutate the the block and state according to any hard-fork specs
|
|
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
|
ApplyDAOHardFork(statedb)
|
|
}
|
|
// Iterate over and process the individual transactions
|
|
for i, tx := range block.Transactions() {
|
|
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
|
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
|
if err != nil {
|
|
return nil, nil, totalUsedGas, err
|
|
}
|
|
receipts = append(receipts, receipt)
|
|
allLogs = append(allLogs, logs...)
|
|
}
|
|
AccumulateRewards(statedb, header, block.Uncles())
|
|
|
|
return receipts, allLogs, totalUsedGas, err
|
|
}
|
|
|
|
// ApplyTransaction attempts to apply a transaction to the given state database
|
|
// and uses the input parameters for its environment.
|
|
//
|
|
// ApplyTransactions returns the generated receipts and vm logs during the
|
|
// execution of the state transition phase.
|
|
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
|
backend := &EVMBackend{
|
|
GetHashFn: GetHashFn(header.ParentHash, bc),
|
|
State: statedb,
|
|
}
|
|
context := ToEVMContext(config, tx, header)
|
|
|
|
env := vm.NewEnvironment(context, backend, config, cfg)
|
|
|
|
_, gas, err := ApplyMessage(env, tx, gp)
|
|
if err != nil {
|
|
return nil, nil, nil, err
|
|
}
|
|
|
|
// Update the state with pending changes
|
|
usedGas.Add(usedGas, gas)
|
|
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
|
|
receipt.TxHash = tx.Hash()
|
|
receipt.GasUsed = new(big.Int).Set(gas)
|
|
if MessageCreatesContract(tx) {
|
|
from, _ := tx.From()
|
|
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
|
|
}
|
|
|
|
receipt.Logs = statedb.GetLogs(tx.Hash())
|
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
|
|
|
glog.V(logger.Debug).Infoln(receipt)
|
|
|
|
return receipt, receipt.Logs, gas, err
|
|
}
|
|
|
|
// AccumulateRewards credits the coinbase of the given block with the
|
|
// mining reward. The total reward consists of the static block reward
|
|
// and rewards for included uncles. The coinbase of each uncle block is
|
|
// also rewarded.
|
|
func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) {
|
|
reward := new(big.Int).Set(BlockReward)
|
|
r := new(big.Int)
|
|
for _, uncle := range uncles {
|
|
r.Add(uncle.Number, big8)
|
|
r.Sub(r, header.Number)
|
|
r.Mul(r, BlockReward)
|
|
r.Div(r, big8)
|
|
statedb.AddBalance(uncle.Coinbase, r)
|
|
|
|
r.Div(BlockReward, big32)
|
|
reward.Add(reward, r)
|
|
}
|
|
statedb.AddBalance(header.Coinbase, reward)
|
|
}
|