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

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

obscuren's avatar
obscuren committed
9
	"github.com/ethereum/go-ethereum/common"
obscuren's avatar
obscuren committed
10
	"github.com/ethereum/go-ethereum/core/state"
obscuren's avatar
obscuren committed
11
	"github.com/ethereum/go-ethereum/core/types"
12
	"github.com/ethereum/go-ethereum/event"
obscuren's avatar
obscuren committed
13
	"github.com/ethereum/go-ethereum/logger"
obscuren's avatar
obscuren committed
14
	"github.com/ethereum/go-ethereum/logger/glog"
15
	"github.com/ethereum/go-ethereum/params"
obscuren's avatar
obscuren committed
16
	"github.com/ethereum/go-ethereum/pow"
17
	"github.com/ethereum/go-ethereum/rlp"
18
	"gopkg.in/fatih/set.v0"
obscuren's avatar
obscuren committed
19 20
)

21 22 23
const (
	// must be bumped when consensus algorithm is changed, this forces the upgradedb
	// command to be run (forces the blocks to be imported again using the new algorithm)
24
	BlockChainVersion = 3
25 26
)

27 28
var receiptsPre = []byte("receipts-")

29
type BlockProcessor struct {
obscuren's avatar
obscuren committed
30 31
	db      common.Database
	extraDb common.Database
obscuren's avatar
obscuren committed
32 33
	// Mutex for locking the block processor. Blocks can only be handled one at a time
	mutex sync.Mutex
34
	// Canonical block chain
35
	bc *ChainManager
obscuren's avatar
obscuren committed
36 37
	// non-persistent key/value memory storage
	mem map[string]*big.Int
obscuren's avatar
obscuren committed
38
	// Proof of work used for validating
obscuren's avatar
obscuren committed
39
	Pow pow.PoW
40

41
	events event.Subscription
obscuren's avatar
obscuren committed
42 43

	eventMux *event.TypeMux
obscuren's avatar
obscuren committed
44 45
}

46
func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
47
	sm := &BlockProcessor{
obscuren's avatar
obscuren committed
48
		db:       db,
49
		extraDb:  extra,
obscuren's avatar
obscuren committed
50
		mem:      make(map[string]*big.Int),
obscuren's avatar
obscuren committed
51
		Pow:      pow,
52 53
		bc:       chainManager,
		eventMux: eventMux,
obscuren's avatar
obscuren committed
54
	}
55

56
	return sm
obscuren's avatar
obscuren committed
57 58
}

59
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
60
	coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
61
	coinbase.SetGasPool(block.Header().GasLimit)
obscuren's avatar
obscuren committed
62

63
	// Process the transactions on to parent state
64
	receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
obscuren's avatar
obscuren committed
65 66 67 68 69 70 71
	if err != nil {
		return nil, err
	}

	return receipts, nil
}

72
func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
obscuren's avatar
obscuren committed
73 74
	// If we are mining this block and validating we want to set the logs back to 0

75
	cb := statedb.GetStateObject(coinbase.Address())
76
	_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb)
77
	if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
78 79
		return nil, nil, err
	}
obscuren's avatar
obscuren committed
80 81

	// Update the state with pending changes
obscuren's avatar
obscuren committed
82
	statedb.Update()
obscuren's avatar
obscuren committed
83

84
	cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas))
obscuren's avatar
obscuren committed
85
	receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
86 87 88

	logs := statedb.GetLogs(tx.Hash())
	receipt.SetLogs(logs)
obscuren's avatar
obscuren committed
89
	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
obscuren's avatar
obscuren committed
90 91

	glog.V(logger.Debug).Infoln(receipt)
obscuren's avatar
obscuren committed
92 93 94 95

	// Notify all subscribers
	if !transientProcess {
		go self.eventMux.Post(TxPostEvent{tx})
obscuren's avatar
obscuren committed
96
		go self.eventMux.Post(logs)
obscuren's avatar
obscuren committed
97 98
	}

99
	return receipt, gas, err
obscuren's avatar
obscuren committed
100
}
101 102 103
func (self *BlockProcessor) ChainManager() *ChainManager {
	return self.bc
}
obscuren's avatar
obscuren committed
104

105
func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
106
	var (
107 108 109 110
		receipts      types.Receipts
		totalUsedGas  = big.NewInt(0)
		err           error
		cumulativeSum = new(big.Int)
111 112
	)

113 114 115
	for i, tx := range txs {
		statedb.StartRecord(tx.Hash(), block.Hash(), i)

116
		receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
117
		if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
118
			return nil, err
119 120
		}

obscuren's avatar
obscuren committed
121
		if err != nil {
obscuren's avatar
obscuren committed
122
			glog.V(logger.Core).Infoln("TX err:", err)
obscuren's avatar
obscuren committed
123 124
		}
		receipts = append(receipts, receipt)
125

obscuren's avatar
obscuren committed
126
		cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
obscuren's avatar
obscuren committed
127
	}
obscuren's avatar
obscuren committed
128

129 130 131
	if block.GasUsed().Cmp(totalUsedGas) != 0 {
		return nil, ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), totalUsedGas))
	}
Maran's avatar
Maran committed
132

obscuren's avatar
obscuren committed
133
	if transientProcess {
134
		go self.eventMux.Post(PendingBlockEvent{block, statedb.Logs()})
obscuren's avatar
obscuren committed
135 136
	}

137
	return receipts, err
obscuren's avatar
obscuren committed
138 139
}

140 141 142 143 144 145 146 147 148 149
func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err error) {
	// Processing a blocks may never happen simultaneously
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	header := block.Header()
	if !sm.bc.HasBlock(header.ParentHash) {
		return nil, ParentError(header.ParentHash)
	}
	parent := sm.bc.GetBlock(header.ParentHash)
150 151 152 153 154 155 156

	// FIXME Change to full header validation. See #1225
	errch := make(chan bool)
	go func() { errch <- sm.Pow.Verify(block) }()

	logs, err = sm.processWithParent(block, parent)
	if !<-errch {
157 158
		return nil, ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
	}
159

160
	return logs, err
161 162
}

163 164 165
// Process block will attempt to process the given block's transactions and applies them
// on top of the block's parent state (given it exists) and will return wether it was
// successful or not.
166
func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err error) {
obscuren's avatar
obscuren committed
167
	// Processing a blocks may never happen simultaneously
168 169
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
obscuren's avatar
obscuren committed
170

171 172
	header := block.Header()
	if sm.bc.HasBlock(header.Hash()) {
173
		return nil, &KnownBlockError{header.Number, header.Hash()}
obscuren's avatar
obscuren committed
174 175
	}

176
	if !sm.bc.HasBlock(header.ParentHash) {
177
		return nil, ParentError(header.ParentHash)
obscuren's avatar
obscuren committed
178
	}
179
	parent := sm.bc.GetBlock(header.ParentHash)
180
	return sm.processWithParent(block, parent)
181
}
obscuren's avatar
obscuren committed
182

183
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) {
184
	// Create a new state based on the parent's root (e.g., create copy)
185
	state := state.New(parent.Root(), sm.db)
obscuren's avatar
obscuren committed
186

187
	// Block validation
188
	if err = ValidateHeader(sm.Pow, block.Header(), parent.Header(), false); err != nil {
obscuren's avatar
obscuren committed
189
		return
190 191
	}

obscuren's avatar
obscuren committed
192 193
	// There can be at most two uncles
	if len(block.Uncles()) > 2 {
194
		return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
obscuren's avatar
obscuren committed
195 196
	}

197
	receipts, err := sm.TransitionState(state, parent, block, false)
198
	if err != nil {
199
		return
200 201
	}

202 203
	header := block.Header()

204 205
	// Validate the received block's bloom with the one derived from the generated receipts.
	// For valid blocks this should always validate to true.
206
	rbloom := types.CreateBloom(receipts)
obscuren's avatar
obscuren committed
207
	if rbloom != header.Bloom {
208 209 210 211
		err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
		return
	}

212
	// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
213
	// can be used by light clients to make sure they've received the correct Txs
214
	txSha := types.DeriveSha(block.Transactions())
obscuren's avatar
obscuren committed
215
	if txSha != header.TxHash {
216
		err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
obscuren's avatar
obscuren committed
217 218
		return
	}
obscuren's avatar
obscuren committed
219

220
	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
221
	receiptSha := types.DeriveSha(receipts)
obscuren's avatar
obscuren committed
222
	if receiptSha != header.ReceiptHash {
223 224 225 226 227 228 229 230
		err = fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
		return
	}

	// Verify UncleHash before running other uncle validations
	unclesSha := block.CalculateUnclesHash()
	if unclesSha != header.UncleHash {
		err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
231 232
		return
	}
obscuren's avatar
obscuren committed
233

obscuren's avatar
obscuren committed
234 235
	// Verify uncles
	if err = sm.VerifyUncles(state, block, parent); err != nil {
236
		return
obscuren's avatar
obscuren committed
237
	}
obscuren's avatar
obscuren committed
238 239
	// Accumulate static rewards; block reward, uncle's and uncle inclusion.
	AccumulateRewards(state, block)
obscuren's avatar
obscuren committed
240

241 242
	// Commit state objects/accounts to a temporary trie (does not save)
	// used to calculate the state root.
obscuren's avatar
obscuren committed
243
	state.Update()
obscuren's avatar
obscuren committed
244
	if header.Root != state.Root() {
245
		err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
246
		return
obscuren's avatar
obscuren committed
247 248
	}

obscuren's avatar
obscuren committed
249
	// Sync the current block's state to the database
250
	state.Sync()
obscuren's avatar
obscuren committed
251

252 253 254 255
	// This puts transactions in a extra db for rpc
	for i, tx := range block.Transactions() {
		putTx(sm.extraDb, tx, block, uint64(i))
	}
256

257 258
	// store the receipts
	putReceipts(sm.extraDb, block.Hash(), receipts)
zsfelfoldi's avatar
zsfelfoldi committed
259

260
	return state.Logs(), nil
obscuren's avatar
obscuren committed
261 262
}

obscuren's avatar
obscuren committed
263
func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
264 265
	ancestors := set.New()
	uncles := set.New()
obscuren's avatar
obscuren committed
266
	ancestorHeaders := make(map[common.Hash]*types.Header)
obscuren's avatar
obscuren committed
267
	for _, ancestor := range sm.bc.GetAncestors(block, 7) {
obscuren's avatar
obscuren committed
268
		ancestorHeaders[ancestor.Hash()] = ancestor.Header()
269
		ancestors.Add(ancestor.Hash())
obscuren's avatar
obscuren committed
270 271
		// Include ancestors uncles in the uncle set. Uncles must be unique.
		for _, uncle := range ancestor.Uncles() {
272
			uncles.Add(uncle.Hash())
obscuren's avatar
obscuren committed
273
		}
274 275
	}

276
	uncles.Add(block.Hash())
277
	for i, uncle := range block.Uncles() {
278
		hash := uncle.Hash()
279
		if uncles.Has(hash) {
obscuren's avatar
obscuren committed
280
			// Error not unique
281
			return UncleError("uncle[%d](%x) not unique", i, hash[:4])
obscuren's avatar
obscuren committed
282
		}
283
		uncles.Add(hash)
obscuren's avatar
obscuren committed
284

285 286 287
		if ancestors.Has(hash) {
			branch := fmt.Sprintf("  O - %x\n  |\n", block.Hash())
			ancestors.Each(func(item interface{}) bool {
288
				branch += fmt.Sprintf("  O - %x\n  |\n", hash)
289 290
				return true
			})
obscuren's avatar
obscuren committed
291 292
			glog.Infoln(branch)

293
			return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
obscuren's avatar
obscuren committed
294 295
		}

Gustav Simonsson's avatar
Gustav Simonsson committed
296 297
		if !ancestors.Has(uncle.ParentHash) || uncle.ParentHash == parent.Hash() {
			return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
obscuren's avatar
obscuren committed
298
		}
obscuren's avatar
obscuren committed
299

300
		if err := ValidateHeader(sm.Pow, uncle, ancestorHeaders[uncle.ParentHash], true); err != nil {
301
			return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
obscuren's avatar
obscuren committed
302
		}
obscuren's avatar
obscuren committed
303
	}
obscuren's avatar
obscuren committed
304 305 306 307

	return nil
}

308 309 310 311 312 313 314 315
// GetBlockReceipts returns the receipts beloniging to the block hash
func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
	return getBlockReceipts(sm.extraDb, bhash)
}

// GetLogs returns the logs of the given block. This method is using a two step approach
// where it tries to get it from the (updated) method which gets them from the receipts or
// the depricated way by re-processing the block.
obscuren's avatar
obscuren committed
316
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
317 318 319 320 321 322 323
	receipts, err := sm.GetBlockReceipts(block.Hash())
	if err == nil && len(receipts) > 0 {
		// coalesce logs
		for _, receipt := range receipts {
			logs = append(logs, receipt.Logs()...)
		}
		return
obscuren's avatar
obscuren committed
324 325
	}

326
	// TODO: remove backward compatibility
obscuren's avatar
obscuren committed
327 328
	var (
		parent = sm.bc.GetBlock(block.Header().ParentHash)
329
		state  = state.New(parent.Root(), sm.db)
obscuren's avatar
obscuren committed
330 331
	)

332
	sm.TransitionState(state, parent, block, true)
obscuren's avatar
obscuren committed
333 334 335

	return state.Logs(), nil
}
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
// See YP section 4.3.4. "Block Header Validity"
// Validates a block. Returns an error if the block is invalid.
func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) error {
	if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
		return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
	}

	expd := CalcDifficulty(block, parent)
	if expd.Cmp(block.Difficulty) != 0 {
		return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
	}

	a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
	a.Abs(a)
	b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor)
	if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) {
		return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
	}

	if int64(block.Time) > time.Now().Unix() {
		return BlockFutureErr
	}

	if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 {
		return BlockNumberErr
	}

	if block.Time <= parent.Time {
		return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
	}

	if checkPow {
		// Verify the nonce of the block. Return an error if it's not valid
		if !pow.Verify(types.NewBlockWithHeader(block)) {
			return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
		}
	}

	return nil
}

func AccumulateRewards(statedb *state.StateDB, block *types.Block) {
	reward := new(big.Int).Set(BlockReward)

	for _, uncle := range block.Uncles() {
		num := new(big.Int).Add(big.NewInt(8), uncle.Number)
		num.Sub(num, block.Number())

		r := new(big.Int)
		r.Mul(BlockReward, num)
		r.Div(r, big.NewInt(8))

		statedb.AddBalance(uncle.Coinbase, r)

		reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
	}

	// Get the account associated with the coinbase
	statedb.AddBalance(block.Header().Coinbase, reward)
}

398 399 400 401 402 403
func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
	var rdata []byte
	rdata, err = db.Get(append(receiptsPre, bhash[:]...))

	if err == nil {
		err = rlp.DecodeBytes(rdata, &receipts)
404 405
	} else {
		glog.V(logger.Detail).Infof("getBlockReceipts error %v\n", err)
406 407 408 409
	}
	return
}

410
func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) {
411 412
	rlpEnc, err := rlp.EncodeToBytes(tx)
	if err != nil {
obscuren's avatar
obscuren committed
413
		glog.V(logger.Debug).Infoln("Failed encoding tx", err)
414 415
		return
	}
obscuren's avatar
obscuren committed
416
	db.Put(tx.Hash().Bytes(), rlpEnc)
417

418 419 420 421
	var txExtra struct {
		BlockHash  common.Hash
		BlockIndex uint64
		Index      uint64
422
	}
423 424 425 426
	txExtra.BlockHash = block.Hash()
	txExtra.BlockIndex = block.NumberU64()
	txExtra.Index = i
	rlpMeta, err := rlp.EncodeToBytes(txExtra)
427
	if err != nil {
obscuren's avatar
obscuren committed
428
		glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err)
429 430
		return
	}
431
	db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
432
}
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448

func putReceipts(db common.Database, hash common.Hash, receipts types.Receipts) error {
	storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
	for i, receipt := range receipts {
		storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
	}

	bytes, err := rlp.EncodeToBytes(storageReceipts)
	if err != nil {
		return err
	}

	db.Put(append(receiptsPre, hash[:]...), bytes)

	return nil
}