aboutsummaryrefslogtreecommitdiffstats
path: root/core/state_processor.go
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2015-10-19 22:08:17 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2015-11-18 21:24:42 +0800
commita1d9ef48c505ab4314ca8e3ee1fc272032da3034 (patch)
tree032db4314c562459e1f1298b6b80eed57a219af2 /core/state_processor.go
parent9422eec55460aaca300cabd52124ed0cbd8dedd3 (diff)
downloadgo-tangerine-a1d9ef48c505ab4314ca8e3ee1fc272032da3034.tar.gz
go-tangerine-a1d9ef48c505ab4314ca8e3ee1fc272032da3034.tar.zst
go-tangerine-a1d9ef48c505ab4314ca8e3ee1fc272032da3034.zip
core, eth, rpc: split out block validator and state processor
This removes the burden on a single object to take care of all validation and state processing. Now instead the validation is done by the `core.BlockValidator` (`types.Validator`) that takes care of both header and uncle validation through the `ValidateBlock` method and state validation through the `ValidateState` method. The state processing is done by a new object `core.StateProcessor` (`types.Processor`) and accepts a new state as input and uses that to process the given block's transactions (and uncles for rewords) to calculate the state root for the next block (P_n + 1).
Diffstat (limited to 'core/state_processor.go')
-rw-r--r--core/state_processor.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/core/state_processor.go b/core/state_processor.go
new file mode 100644
index 000000000..d9c24935d
--- /dev/null
+++ b/core/state_processor.go
@@ -0,0 +1,107 @@
+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)
+)
+
+type StateProcessor struct {
+ bc *BlockChain
+}
+
+func NewStateProcessor(bc *BlockChain) *StateProcessor {
+ return &StateProcessor{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) (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())
+ )
+
+ for i, tx := range block.Transactions() {
+ statedb.StartRecord(tx.Hash(), block.Hash(), i)
+
+ receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas)
+ 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 attemps 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(bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) {
+ _, gas, err := ApplyMessage(NewEnv(statedb, bc, tx, header), 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())
+ }
+
+ logs := statedb.GetLogs(tx.Hash())
+ receipt.Logs = logs
+ receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+
+ glog.V(logger.Debug).Infoln(receipt)
+
+ return 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)
+}