block_processor.go 9.31 KB
Newer Older
obscuren's avatar
obscuren committed
1
package core
obscuren's avatar
obscuren committed
2 3 4

import (
	"bytes"
obscuren's avatar
obscuren committed
5
	"fmt"
obscuren's avatar
obscuren committed
6 7
	"math/big"
	"sync"
obscuren's avatar
obscuren committed
8
	"time"
obscuren's avatar
obscuren committed
9

obscuren's avatar
obscuren committed
10
	"github.com/ethereum/go-ethereum/core/types"
obscuren's avatar
obscuren committed
11
	"github.com/ethereum/go-ethereum/crypto"
12 13
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
obscuren's avatar
obscuren committed
14
	"github.com/ethereum/go-ethereum/logger"
zelig's avatar
zelig committed
15
	"github.com/ethereum/go-ethereum/p2p"
obscuren's avatar
obscuren committed
16 17
	"github.com/ethereum/go-ethereum/pow"
	"github.com/ethereum/go-ethereum/pow/ezp"
obscuren's avatar
obscuren committed
18
	"github.com/ethereum/go-ethereum/state"
19
	"gopkg.in/fatih/set.v0"
obscuren's avatar
obscuren committed
20 21
)

obscuren's avatar
obscuren committed
22
var statelogger = logger.NewLogger("BLOCK")
zelig's avatar
zelig committed
23

24
type EthManager interface {
25
	BlockProcessor() *BlockProcessor
26
	ChainManager() *ChainManager
27
	TxPool() *TxPool
28 29 30
	PeerCount() int
	IsMining() bool
	IsListening() bool
zelig's avatar
zelig committed
31
	Peers() []*p2p.Peer
obscuren's avatar
obscuren committed
32
	KeyManager() *crypto.KeyManager
zelig's avatar
zelig committed
33
	ClientIdentity() p2p.ClientIdentity
obscuren's avatar
obscuren committed
34
	Db() ethutil.Database
35
	EventMux() *event.TypeMux
36 37
}

38
type BlockProcessor struct {
39
	db ethutil.Database
obscuren's avatar
obscuren committed
40 41
	// Mutex for locking the block processor. Blocks can only be handled one at a time
	mutex sync.Mutex
42
	// Canonical block chain
43
	bc *ChainManager
obscuren's avatar
obscuren committed
44 45
	// non-persistent key/value memory storage
	mem map[string]*big.Int
obscuren's avatar
obscuren committed
46
	// Proof of work used for validating
obscuren's avatar
obscuren committed
47
	Pow pow.PoW
48 49

	txpool *TxPool
obscuren's avatar
obscuren committed
50 51 52 53

	// The last attempted block is mainly used for debugging purposes
	// This does not have to be a valid block and will be set during
	// 'Process' & canonical validation.
54
	lastAttemptedBlock *types.Block
55

56
	events event.Subscription
obscuren's avatar
obscuren committed
57 58

	eventMux *event.TypeMux
obscuren's avatar
obscuren committed
59 60
}

61
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
62
	sm := &BlockProcessor{
63
		db:       db,
obscuren's avatar
obscuren committed
64 65
		mem:      make(map[string]*big.Int),
		Pow:      ezp.New(),
66 67 68
		bc:       chainManager,
		eventMux: eventMux,
		txpool:   txpool,
obscuren's avatar
obscuren committed
69
	}
70

71
	return sm
obscuren's avatar
obscuren committed
72 73
}

74
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
75 76
	coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
	coinbase.SetGasPool(CalcGasLimit(parent, block))
obscuren's avatar
obscuren committed
77

78
	// Process the transactions on to parent state
79
	receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
obscuren's avatar
obscuren committed
80 81 82 83 84 85 86
	if err != nil {
		return nil, err
	}

	return receipts, nil
}

87
func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
88
	var (
89 90 91
		receipts           types.Receipts
		handled, unhandled types.Transactions
		erroneous          types.Transactions
92 93
		totalUsedGas       = big.NewInt(0)
		err                error
obscuren's avatar
obscuren committed
94
		cumulativeSum      = new(big.Int)
95 96 97 98
	)

done:
	for i, tx := range txs {
99 100 101
		// If we are mining this block and validating we want to set the logs back to 0
		state.EmptyLogs()

102
		txGas := new(big.Int).Set(tx.Gas())
obscuren's avatar
obscuren committed
103 104

		cb := state.GetStateObject(coinbase.Address())
105
		st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
obscuren's avatar
obscuren committed
106
		_, err = st.TransitionState()
obscuren's avatar
obscuren committed
107
		if err != nil {
108 109 110
			switch {
			case IsNonceErr(err):
				err = nil // ignore error
111
				continue
112 113
			case IsGasLimitErr(err):
				unhandled = txs[i:]
obscuren's avatar
obscuren committed
114

115 116
				break done
			default:
zelig's avatar
zelig committed
117
				statelogger.Infoln(err)
118
				erroneous = append(erroneous, tx)
119
				err = nil
120
			}
obscuren's avatar
obscuren committed
121 122
		}

obscuren's avatar
obscuren committed
123
		txGas.Sub(txGas, st.gas)
124
		cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
obscuren's avatar
obscuren committed
125

126
		// Update the state with pending changes
obscuren's avatar
obscuren committed
127
		state.Update(txGas)
128

obscuren's avatar
obscuren committed
129
		cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
130 131 132
		receipt := types.NewReceipt(state.Root(), cumulative)
		receipt.SetLogs(state.Logs())
		receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
133
		chainlogger.Debugln(receipt)
obscuren's avatar
obscuren committed
134

obscuren's avatar
obscuren committed
135
		// Notify all subscribers
136
		if !transientProcess {
obscuren's avatar
obscuren committed
137
			go self.eventMux.Post(TxPostEvent{tx})
138
		}
obscuren's avatar
obscuren committed
139

obscuren's avatar
obscuren committed
140
		receipts = append(receipts, receipt)
141
		handled = append(handled, tx)
142

143
		if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
144 145
			state.CreateOutputForDiff()
		}
obscuren's avatar
obscuren committed
146
	}
obscuren's avatar
obscuren committed
147

obscuren's avatar
obscuren committed
148
	block.Reward = cumulativeSum
149
	block.Header().GasUsed = totalUsedGas
Maran's avatar
Maran committed
150

151
	return receipts, handled, unhandled, erroneous, err
obscuren's avatar
obscuren committed
152 153
}

154
func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
obscuren's avatar
obscuren committed
155
	// Processing a blocks may never happen simultaneously
156 157
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
obscuren's avatar
obscuren committed
158

159 160 161
	header := block.Header()
	if sm.bc.HasBlock(header.Hash()) {
		return nil, nil, &KnownBlockError{header.Number, header.Hash()}
obscuren's avatar
obscuren committed
162 163
	}

164 165
	if !sm.bc.HasBlock(header.ParentHash) {
		return nil, nil, ParentError(header.ParentHash)
obscuren's avatar
obscuren committed
166
	}
167
	parent := sm.bc.GetBlock(header.ParentHash)
168 169 170

	return sm.ProcessWithParent(block, parent)
}
obscuren's avatar
obscuren committed
171

172
func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
obscuren's avatar
obscuren committed
173 174
	sm.lastAttemptedBlock = block

175 176
	state := state.New(parent.Root(), sm.db)
	//state := state.New(parent.Trie().Copy())
obscuren's avatar
obscuren committed
177

178 179 180
	// Block validation
	if err = sm.ValidateBlock(block, parent); err != nil {
		return
181 182
	}

183
	receipts, err := sm.TransitionState(state, parent, block)
184
	if err != nil {
185
		return
186 187
	}

188 189
	header := block.Header()

190
	rbloom := types.CreateBloom(receipts)
191
	if bytes.Compare(rbloom, header.Bloom) != 0 {
192 193 194 195
		err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
		return
	}

196
	txSha := types.DeriveSha(block.Transactions())
197 198
	if bytes.Compare(txSha, header.TxHash) != 0 {
		err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
obscuren's avatar
obscuren committed
199 200
		return
	}
obscuren's avatar
obscuren committed
201

202
	receiptSha := types.DeriveSha(receipts)
203
	if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
obscuren's avatar
obscuren committed
204
		fmt.Println("receipts", receipts)
205
		err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha)
206 207
		return
	}
obscuren's avatar
obscuren committed
208

obscuren's avatar
obscuren committed
209
	if err = sm.AccumelateRewards(state, block, parent); err != nil {
210
		return
obscuren's avatar
obscuren committed
211 212
	}

213
	state.Update(ethutil.Big0)
214

215 216
	if !bytes.Equal(header.Root, state.Root()) {
		err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
217
		return
obscuren's avatar
obscuren committed
218 219
	}

220 221 222 223 224 225 226 227 228 229 230
	// Calculate the td for this block
	td = CalculateTD(block, parent)
	// Sync the current block's state to the database and cancelling out the deferred Undo
	state.Sync()
	// Set the block hashes for the current messages
	state.Manifest().SetHash(block.Hash())
	messages = state.Manifest().Messages
	// Reset the manifest XXX We need this?
	state.Manifest().Reset()
	// Remove transactions from the pool
	sm.txpool.RemoveSet(block.Transactions())
obscuren's avatar
obscuren committed
231

232
	chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4])
233

234
	return td, messages, nil
obscuren's avatar
obscuren committed
235 236 237 238 239
}

// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
240
func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
obscuren's avatar
obscuren committed
241 242 243 244
	if len(block.Header().Extra) > 1024 {
		return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra))
	}

245
	expd := CalcDifficulty(block, parent)
obscuren's avatar
obscuren committed
246
	if expd.Cmp(block.Header().Difficulty) != 0 {
247
		return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
248 249
	}

250
	diff := block.Header().Time - parent.Header().Time
obscuren's avatar
obscuren committed
251
	if diff < 0 {
252
		return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
obscuren's avatar
obscuren committed
253 254
	}

obscuren's avatar
obscuren committed
255 256
	if block.Time() > time.Now().Unix() {
		return fmt.Errorf("block time is in the future")
obscuren's avatar
obscuren committed
257 258 259
	}

	// Verify the nonce of the block. Return an error if it's not valid
obscuren's avatar
obscuren committed
260
	if !sm.Pow.Verify(block) {
261
		return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
obscuren's avatar
obscuren committed
262 263 264 265 266
	}

	return nil
}

267
func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
268
	reward := new(big.Int).Set(BlockReward)
obscuren's avatar
obscuren committed
269

270
	ancestors := set.New()
obscuren's avatar
obscuren committed
271
	for _, ancestor := range sm.bc.GetAncestors(block, 7) {
272
		ancestors.Add(string(ancestor.Hash()))
273 274
	}

275 276
	uncles := set.New()
	uncles.Add(string(block.Hash()))
277
	for _, uncle := range block.Uncles() {
278
		if uncles.Has(string(uncle.Hash())) {
obscuren's avatar
obscuren committed
279 280 281
			// Error not unique
			return UncleError("Uncle not unique")
		}
282
		uncles.Add(string(uncle.Hash()))
obscuren's avatar
obscuren committed
283

284
		if !ancestors.Has(string(uncle.ParentHash)) {
285
			return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
obscuren's avatar
obscuren committed
286
		}
obscuren's avatar
obscuren committed
287

obscuren's avatar
obscuren committed
288 289
		r := new(big.Int)
		r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
obscuren's avatar
obscuren committed
290

obscuren's avatar
obscuren committed
291
		uncleAccount := statedb.GetAccount(uncle.Coinbase)
obscuren's avatar
obscuren committed
292
		uncleAccount.AddAmount(r)
obscuren's avatar
obscuren committed
293

obscuren's avatar
obscuren committed
294
		reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
obscuren's avatar
obscuren committed
295
	}
obscuren's avatar
obscuren committed
296

obscuren's avatar
obscuren committed
297
	// Get the account associated with the coinbase
298
	account := statedb.GetAccount(block.Header().Coinbase)
obscuren's avatar
obscuren committed
299 300 301
	// Reward amount of ether to the coinbase address
	account.AddAmount(reward)

obscuren's avatar
obscuren committed
302
	statedb.Manifest().AddMessage(&state.Message{
303 304 305 306
		To:        block.Header().Coinbase,
		Input:     nil,
		Origin:    nil,
		Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
obscuren's avatar
obscuren committed
307 308 309
		Value: new(big.Int).Add(reward, block.Reward),
	})

obscuren's avatar
obscuren committed
310 311 312
	return nil
}

313
func (sm *BlockProcessor) GetMessages(block *types.Block) (messages []*state.Message, err error) {
314 315
	if !sm.bc.HasBlock(block.Header().ParentHash) {
		return nil, ParentError(block.Header().ParentHash)
obscuren's avatar
obscuren committed
316 317 318 319 320
	}

	sm.lastAttemptedBlock = block

	var (
321
		parent = sm.bc.GetBlock(block.Header().ParentHash)
322 323
		//state  = state.New(parent.Trie().Copy())
		state = state.New(parent.Root(), sm.db)
obscuren's avatar
obscuren committed
324 325 326 327
	)

	defer state.Reset()

obscuren's avatar
obscuren committed
328
	sm.TransitionState(state, parent, block)
obscuren's avatar
obscuren committed
329
	sm.AccumelateRewards(state, block, parent)
obscuren's avatar
obscuren committed
330 331

	return state.Manifest().Messages, nil
332
}