aboutsummaryrefslogtreecommitdiffstats
path: root/core/state_processor.go
blob: b9793b1570aa82ceb682402cc774da3239ef4241 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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)
}