core/types: make blocks immutable

This commit is contained in:
Felix Lange 2015-06-16 12:41:50 +02:00 committed by Jeffrey Wilcke
parent 654564e164
commit 1d42888d30
17 changed files with 457 additions and 587 deletions

View File

@ -11,12 +11,12 @@ import (
func newChain(size int) (chain []*types.Block) { func newChain(size int) (chain []*types.Block) {
var parentHash common.Hash var parentHash common.Hash
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
block := types.NewBlock(parentHash, common.Address{}, common.Hash{}, new(big.Int), 0, nil) head := &types.Header{ParentHash: parentHash, Number: big.NewInt(int64(i))}
block.Header().Number = big.NewInt(int64(i)) block := types.NewBlock(head, nil, nil, nil)
chain = append(chain, block) chain = append(chain, block)
parentHash = block.Hash() parentHash = block.Hash()
} }
return return chain
} }
func insertChainCache(cache *BlockCache, chain []*types.Block) { func insertChainCache(cache *BlockCache, chain []*types.Block) {

View File

@ -57,8 +57,8 @@ func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *Cha
} }
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) coinbase := statedb.GetOrNewStateObject(block.Coinbase())
coinbase.SetGasLimit(block.Header().GasLimit) coinbase.SetGasLimit(block.GasLimit())
// Process the transactions on to parent state // Process the transactions on to parent state
receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
@ -69,11 +69,11 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
return receipts, nil return receipts, nil
} }
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) { func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
// If we are mining this block and validating we want to set the logs back to 0 // If we are mining this block and validating we want to set the logs back to 0
cb := statedb.GetStateObject(coinbase.Address()) cb := statedb.GetStateObject(coinbase.Address())
_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb) _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, cb)
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
return nil, nil, err return nil, nil, err
} }
@ -108,12 +108,13 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
totalUsedGas = big.NewInt(0) totalUsedGas = big.NewInt(0)
err error err error
cumulativeSum = new(big.Int) cumulativeSum = new(big.Int)
header = block.Header()
) )
for i, tx := range txs { for i, tx := range txs {
statedb.StartRecord(tx.Hash(), block.Hash(), i) statedb.StartRecord(tx.Hash(), block.Hash(), i)
receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess) receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, header, tx, totalUsedGas, transientProcess)
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
return nil, err return nil, err
} }
@ -142,11 +143,10 @@ func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err
sm.mutex.Lock() sm.mutex.Lock()
defer sm.mutex.Unlock() defer sm.mutex.Unlock()
header := block.Header() if !sm.bc.HasBlock(block.ParentHash()) {
if !sm.bc.HasBlock(header.ParentHash) { return nil, ParentError(block.ParentHash())
return nil, ParentError(header.ParentHash)
} }
parent := sm.bc.GetBlock(header.ParentHash) parent := sm.bc.GetBlock(block.ParentHash())
// FIXME Change to full header validation. See #1225 // FIXME Change to full header validation. See #1225
errch := make(chan bool) errch := make(chan bool)
@ -168,30 +168,32 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err erro
sm.mutex.Lock() sm.mutex.Lock()
defer sm.mutex.Unlock() defer sm.mutex.Unlock()
header := block.Header() if sm.bc.HasBlock(block.Hash()) {
if sm.bc.HasBlock(header.Hash()) { return nil, &KnownBlockError{block.Number(), block.Hash()}
return nil, &KnownBlockError{header.Number, header.Hash()}
} }
if !sm.bc.HasBlock(header.ParentHash) { if !sm.bc.HasBlock(block.ParentHash()) {
return nil, ParentError(header.ParentHash) return nil, ParentError(block.ParentHash())
} }
parent := sm.bc.GetBlock(header.ParentHash) parent := sm.bc.GetBlock(block.ParentHash())
return sm.processWithParent(block, parent) return sm.processWithParent(block, parent)
} }
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) { func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) {
// Create a new state based on the parent's root (e.g., create copy) // Create a new state based on the parent's root (e.g., create copy)
state := state.New(parent.Root(), sm.db) state := state.New(parent.Root(), sm.db)
header := block.Header()
uncles := block.Uncles()
txs := block.Transactions()
// Block validation // Block validation
if err = ValidateHeader(sm.Pow, block.Header(), parent.Header(), false); err != nil { if err = ValidateHeader(sm.Pow, header, parent.Header(), false); err != nil {
return return
} }
// There can be at most two uncles // There can be at most two uncles
if len(block.Uncles()) > 2 { if len(uncles) > 2 {
return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles())) return nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(uncles))
} }
receipts, err := sm.TransitionState(state, parent, block, false) receipts, err := sm.TransitionState(state, parent, block, false)
@ -199,8 +201,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
return return
} }
header := block.Header()
// Validate the received block's bloom with the one derived from the generated receipts. // Validate the received block's bloom with the one derived from the generated receipts.
// For valid blocks this should always validate to true. // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts) rbloom := types.CreateBloom(receipts)
@ -211,7 +211,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]])) // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
// can be used by light clients to make sure they've received the correct Txs // can be used by light clients to make sure they've received the correct Txs
txSha := types.DeriveSha(block.Transactions()) txSha := types.DeriveSha(txs)
if txSha != header.TxHash { if txSha != header.TxHash {
err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
return return
@ -225,7 +225,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
} }
// Verify UncleHash before running other uncle validations // Verify UncleHash before running other uncle validations
unclesSha := block.CalculateUnclesHash() unclesSha := types.CalcUncleHash(uncles)
if unclesSha != header.UncleHash { if unclesSha != header.UncleHash {
err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
return return
@ -236,7 +236,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
return return
} }
// Accumulate static rewards; block reward, uncle's and uncle inclusion. // Accumulate static rewards; block reward, uncle's and uncle inclusion.
AccumulateRewards(state, block) AccumulateRewards(state, header, uncles)
// Commit state objects/accounts to a temporary trie (does not save) // Commit state objects/accounts to a temporary trie (does not save)
// used to calculate the state root. // used to calculate the state root.
@ -260,11 +260,34 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
return state.Logs(), nil return state.Logs(), nil
} }
// 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.
func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) {
reward := new(big.Int).Set(BlockReward)
for _, uncle := range uncles {
num := new(big.Int).Add(big.NewInt(8), uncle.Number)
num.Sub(num, header.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(header.Coinbase, reward)
}
func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error { func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
ancestors := set.New() ancestors := set.New()
uncles := set.New() uncles := set.New()
ancestorHeaders := make(map[common.Hash]*types.Header) ancestorHeaders := make(map[common.Hash]*types.Header)
for _, ancestor := range sm.bc.GetAncestors(block, 7) { for _, ancestor := range sm.bc.GetBlocksFromHash(block.ParentHash(), 7) {
ancestorHeaders[ancestor.Hash()] = ancestor.Header() ancestorHeaders[ancestor.Hash()] = ancestor.Header()
ancestors.Add(ancestor.Hash()) ancestors.Add(ancestor.Hash())
// Include ancestors uncles in the uncle set. Uncles must be unique. // Include ancestors uncles in the uncle set. Uncles must be unique.
@ -325,7 +348,7 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
// TODO: remove backward compatibility // TODO: remove backward compatibility
var ( var (
parent = sm.bc.GetBlock(block.Header().ParentHash) parent = sm.bc.GetBlock(block.ParentHash())
state = state.New(parent.Root(), sm.db) state = state.New(parent.Root(), sm.db)
) )
@ -341,7 +364,7 @@ func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) err
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
} }
expd := CalcDifficulty(block, parent) expd := CalcDifficulty(int64(block.Time), int64(parent.Time), parent.Difficulty)
if expd.Cmp(block.Difficulty) != 0 { if expd.Cmp(block.Difficulty) != 0 {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
} }
@ -375,26 +398,6 @@ func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) err
return nil 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)
}
func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) { func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
var rdata []byte var rdata []byte
rdata, err = db.Get(append(receiptsPre, bhash[:]...)) rdata, err = db.Get(append(receiptsPre, bhash[:]...))

View File

@ -26,20 +26,18 @@ func proc() (*BlockProcessor, *ChainManager) {
} }
func TestNumber(t *testing.T) { func TestNumber(t *testing.T) {
_, chain := proc()
block1 := chain.NewBlock(common.Address{})
block1.Header().Number = big.NewInt(3)
block1.Header().Time--
pow := ezp.New() pow := ezp.New()
err := ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false) bp, chain := proc()
header := makeHeader(chain.Genesis(), 0, bp.db, 0)
header.Number = big.NewInt(3)
err := ValidateHeader(pow, header, chain.Genesis().Header(), false)
if err != BlockNumberErr { if err != BlockNumberErr {
t.Errorf("expected block number error %v", err) t.Errorf("expected block number error, got %q", err)
} }
block1 = chain.NewBlock(common.Address{}) header = makeHeader(chain.Genesis(), 0, bp.db, 0)
err = ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false) err = ValidateHeader(pow, header, chain.Genesis().Header(), false)
if err == BlockNumberErr { if err == BlockNumberErr {
t.Errorf("didn't expect block number error") t.Errorf("didn't expect block number error")
} }

View File

@ -29,12 +29,8 @@ var (
// Utility functions for making chains on the fly // Utility functions for making chains on the fly
// Exposed for sake of testing from other packages (eg. go-ethash) // Exposed for sake of testing from other packages (eg. go-ethash)
func NewBlockFromParent(addr common.Address, parent *types.Block) *types.Block {
return newBlockFromParent(addr, parent)
}
func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block { func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block {
return makeBlock(bman, parent, i, db, seed) return types.NewBlock(makeHeader(parent, i, db, seed), nil, nil, nil)
} }
func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks { func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks {
@ -53,46 +49,38 @@ func NewCanonical(n int, db common.Database) (*BlockProcessor, error) {
return newCanonical(n, db) return newCanonical(n, db)
} }
// block time is fixed at 10 seconds // makeHeader creates the header for a new empty block, simulating
func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block { // what miner would do. We seed chains by the first byte of the coinbase.
block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, nil) func makeHeader(parent *types.Block, i int, db common.Database, seed int) *types.Header {
block.SetUncles(nil)
block.SetTransactions(nil)
block.SetReceipts(nil)
header := block.Header()
header.Difficulty = CalcDifficulty(block.Header(), parent.Header())
header.Number = new(big.Int).Add(parent.Header().Number, common.Big1)
header.Time = parent.Header().Time + 10
header.GasLimit = CalcGasLimit(parent)
block.Td = parent.Td
return block
}
// Actually make a block by simulating what miner would do
// we seed chains by the first byte of the coinbase
func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Database, seed int) *types.Block {
var addr common.Address var addr common.Address
addr[0], addr[19] = byte(seed), byte(i) addr[0], addr[19] = byte(seed), byte(i) // 'random' coinbase
block := newBlockFromParent(addr, parent) time := parent.Time() + 10 // block time is fixed at 10 seconds
state := state.New(block.Root(), db)
// ensure that the block's coinbase has the block reward in the state.
state := state.New(parent.Root(), db)
cbase := state.GetOrNewStateObject(addr) cbase := state.GetOrNewStateObject(addr)
cbase.SetGasLimit(CalcGasLimit(parent)) cbase.SetGasLimit(CalcGasLimit(parent))
cbase.AddBalance(BlockReward) cbase.AddBalance(BlockReward)
state.Update() state.Update()
block.SetRoot(state.Root())
return block return &types.Header{
Root: state.Root(),
ParentHash: parent.Hash(),
Coinbase: addr,
Difficulty: CalcDifficulty(time, parent.Time(), parent.Difficulty()),
Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: uint64(time),
GasLimit: CalcGasLimit(parent),
}
} }
// Make a chain with real blocks // makeChain creates a valid chain of empty blocks.
// Runs ProcessWithParent to get proper state roots
func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks { func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Database, seed int) types.Blocks {
bman.bc.currentBlock = parent bman.bc.currentBlock = parent
blocks := make(types.Blocks, max) blocks := make(types.Blocks, max)
for i := 0; i < max; i++ { for i := 0; i < max; i++ {
block := makeBlock(bman, parent, i, db, seed) block := types.NewBlock(makeHeader(parent, i, db, seed), nil, nil, nil)
// Use ProcessWithParent to verify that we have produced a valid block.
_, err := bman.processWithParent(block, parent) _, err := bman.processWithParent(block, parent)
if err != nil { if err != nil {
fmt.Println("process with parent failed", err) fmt.Println("process with parent failed", err)
@ -129,7 +117,7 @@ func newBlockProcessor(db common.Database, cman *ChainManager, eventMux *event.T
} }
// Make a new, deterministic canonical chain by running InsertChain // Make a new, deterministic canonical chain by running InsertChain
// on result of makeChain // on result of makeChain.
func newCanonical(n int, db common.Database) (*BlockProcessor, error) { func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
eventMux := &event.TypeMux{} eventMux := &event.TypeMux{}

View File

@ -38,23 +38,24 @@ const (
maxTimeFutureBlocks = 30 maxTimeFutureBlocks = 30
) )
func CalcDifficulty(block, parent *types.Header) *big.Int { // CalcDifficulty is the difficulty adjustment algorithm. It returns
// the difficulty that a new block b should have when created at time
// given the parent block's time and difficulty.
func CalcDifficulty(time int64, parentTime int64, parentDiff *big.Int) *big.Int {
diff := new(big.Int) diff := new(big.Int)
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) if big.NewInt(time-parentTime).Cmp(params.DurationLimit) < 0 {
if big.NewInt(int64(block.Time)-int64(parent.Time)).Cmp(params.DurationLimit) < 0 { diff.Add(parentDiff, adjust)
diff.Add(parent.Difficulty, adjust)
} else { } else {
diff.Sub(parent.Difficulty, adjust) diff.Sub(parentDiff, adjust)
} }
if diff.Cmp(params.MinimumDifficulty) < 0 { if diff.Cmp(params.MinimumDifficulty) < 0 {
return params.MinimumDifficulty return params.MinimumDifficulty
} }
return diff return diff
} }
// CalcTD computes the total difficulty of block.
func CalcTD(block, parent *types.Block) *big.Int { func CalcTD(block, parent *types.Block) *big.Int {
if parent == nil { if parent == nil {
return block.Difficulty() return block.Difficulty()
@ -62,6 +63,8 @@ func CalcTD(block, parent *types.Block) *big.Int {
return new(big.Int).Add(parent.Td, block.Header().Difficulty) return new(big.Int).Add(parent.Td, block.Header().Difficulty)
} }
// CalcGasLimit computes the gas limit of the next block after parent.
// The result may be modified by the caller.
func CalcGasLimit(parent *types.Block) *big.Int { func CalcGasLimit(parent *types.Block) *big.Int {
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
@ -71,11 +74,11 @@ func CalcGasLimit(parent *types.Block) *big.Int {
gl := new(big.Int).Sub(parent.GasLimit(), decay) gl := new(big.Int).Sub(parent.GasLimit(), decay)
gl = gl.Add(gl, contrib) gl = gl.Add(gl, contrib)
gl = gl.Add(gl, big.NewInt(1)) gl = gl.Add(gl, big.NewInt(1))
gl = common.BigMax(gl, params.MinGasLimit) gl.Set(common.BigMax(gl, params.MinGasLimit))
if gl.Cmp(params.GenesisGasLimit) < 0 { if gl.Cmp(params.GenesisGasLimit) < 0 {
gl2 := new(big.Int).Add(parent.GasLimit(), decay) gl.Add(parent.GasLimit(), decay)
return common.BigMin(params.GenesisGasLimit, gl2) gl.Set(common.BigMin(gl, params.GenesisGasLimit))
} }
return gl return gl
} }
@ -255,50 +258,11 @@ func (bc *ChainManager) makeCache() {
bc.cache = NewBlockCache(blockCacheLimit) bc.cache = NewBlockCache(blockCacheLimit)
} }
// load in last `blockCacheLimit` - 1 blocks. Last block is the current. // load in last `blockCacheLimit` - 1 blocks. Last block is the current.
ancestors := bc.GetAncestors(bc.currentBlock, blockCacheLimit-1) for _, block := range bc.GetBlocksFromHash(bc.currentBlock.Hash(), blockCacheLimit) {
ancestors = append(ancestors, bc.currentBlock)
for _, block := range ancestors {
bc.cache.Push(block) bc.cache.Push(block)
} }
} }
// Block creation & chain handling
func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block {
bc.mu.RLock()
defer bc.mu.RUnlock()
var (
root common.Hash
parentHash common.Hash
)
if bc.currentBlock != nil {
root = bc.currentBlock.Header().Root
parentHash = bc.lastBlockHash
}
block := types.NewBlock(
parentHash,
coinbase,
root,
common.BigPow(2, 32),
0,
nil)
block.SetUncles(nil)
block.SetTransactions(nil)
block.SetReceipts(nil)
parent := bc.currentBlock
if parent != nil {
header := block.Header()
header.Difficulty = CalcDifficulty(block.Header(), parent.Header())
header.Number = new(big.Int).Add(parent.Header().Number, common.Big1)
header.GasLimit = CalcGasLimit(parent)
}
return block
}
func (bc *ChainManager) Reset() { func (bc *ChainManager) Reset() {
bc.mu.Lock() bc.mu.Lock()
defer bc.mu.Unlock() defer bc.mu.Unlock()
@ -463,6 +427,19 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
} }
// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors.
func (self *ChainManager) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) {
for i := 0; i < n; i++ {
block := self.GetBlock(hash)
if block == nil {
break
}
blocks = append(blocks, block)
hash = block.ParentHash()
}
return
}
// non blocking version // non blocking version
func (self *ChainManager) getBlockByNumber(num uint64) *types.Block { func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
key, _ := self.blockDb.Get(append(blockNumPre, big.NewInt(int64(num)).Bytes()...)) key, _ := self.blockDb.Get(append(blockNumPre, big.NewInt(int64(num)).Bytes()...))
@ -482,19 +459,6 @@ func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncl
return return
} }
func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
for i := 0; i < length; i++ {
block = self.GetBlock(block.ParentHash())
if block == nil {
break
}
blocks = append(blocks, block)
}
return
}
// setTotalDifficulty updates the TD of the chain manager. Note, this function // setTotalDifficulty updates the TD of the chain manager. Note, this function
// assumes that the `mu` mutex is held! // assumes that the `mu` mutex is held!
func (bc *ChainManager) setTotalDifficulty(td *big.Int) { func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
@ -621,14 +585,12 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max) return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
} }
block.SetQueued(true)
self.futureBlocks.Push(block) self.futureBlocks.Push(block)
stats.queued++ stats.queued++
continue continue
} }
if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) { if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) {
block.SetQueued(true)
self.futureBlocks.Push(block) self.futureBlocks.Push(block)
stats.queued++ stats.queued++
continue continue

View File

@ -117,7 +117,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
} }
func loadChain(fn string, t *testing.T) (types.Blocks, error) { func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm) fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -265,7 +265,7 @@ func TestBrokenChain(t *testing.T) {
} }
func TestChainInsertions(t *testing.T) { func TestChainInsertions(t *testing.T) {
t.Skip() // travil fails. t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
@ -303,7 +303,7 @@ func TestChainInsertions(t *testing.T) {
} }
func TestChainMultipleInsertions(t *testing.T) { func TestChainMultipleInsertions(t *testing.T) {
t.Skip() // travil fails. t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
@ -346,8 +346,8 @@ func TestChainMultipleInsertions(t *testing.T) {
} }
} }
func TestGetAncestors(t *testing.T) { func TestGetBlocksFromHash(t *testing.T) {
t.Skip() // travil fails. t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
chainMan := theChainManager(db, t) chainMan := theChainManager(db, t)
@ -361,8 +361,8 @@ func TestGetAncestors(t *testing.T) {
chainMan.write(block) chainMan.write(block)
} }
ancestors := chainMan.GetAncestors(chain[len(chain)-1], 4) blocks := chainMan.GetBlocksFromHash(chain[len(chain)-1].Hash(), 4)
fmt.Println(ancestors) fmt.Println(blocks)
} }
type bproc struct{} type bproc struct{}
@ -372,15 +372,17 @@ func (bproc) Process(*types.Block) (state.Logs, error) { return nil, nil }
func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {
var chain []*types.Block var chain []*types.Block
for i, difficulty := range d { for i, difficulty := range d {
header := &types.Header{Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty))} header := &types.Header{
block := types.NewBlockWithHeader(header) Coinbase: common.Address{seed},
copy(block.HeaderHash[:2], []byte{byte(i + 1), seed}) Number: big.NewInt(int64(i + 1)),
if i == 0 { Difficulty: big.NewInt(int64(difficulty)),
block.ParentHeaderHash = genesis.Hash()
} else {
copy(block.ParentHeaderHash[:2], []byte{byte(i), seed})
} }
if i == 0 {
header.ParentHash = genesis.Hash()
} else {
header.ParentHash = chain[i-1].Hash()
}
block := types.NewBlockWithHeader(header)
chain = append(chain, block) chain = append(chain, block)
} }
return chain return chain
@ -399,7 +401,6 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
} }
func TestReorgLongest(t *testing.T) { func TestReorgLongest(t *testing.T) {
t.Skip("skipped while cache is removed")
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis := GenesisBlock(0, db) genesis := GenesisBlock(0, db)
bc := chm(genesis, db) bc := chm(genesis, db)
@ -419,7 +420,6 @@ func TestReorgLongest(t *testing.T) {
} }
func TestReorgShortest(t *testing.T) { func TestReorgShortest(t *testing.T) {
t.Skip("skipped while cache is removed")
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis := GenesisBlock(0, db) genesis := GenesisBlock(0, db)
bc := chm(genesis, db) bc := chm(genesis, db)

View File

@ -11,38 +11,18 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
/* // GenesisBlock creates a genesis block with the given nonce.
* This is the special genesis block.
*/
var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var ZeroHash512 = make([]byte, 64)
func GenesisBlock(nonce uint64, db common.Database) *types.Block { func GenesisBlock(nonce uint64, db common.Database) *types.Block {
genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, nonce, nil)
genesis.Header().Number = common.Big0
genesis.Header().GasLimit = params.GenesisGasLimit
genesis.Header().GasUsed = common.Big0
genesis.Header().Time = 0
genesis.Td = common.Big0
genesis.SetUncles([]*types.Header{})
genesis.SetTransactions(types.Transactions{})
genesis.SetReceipts(types.Receipts{})
var accounts map[string]struct { var accounts map[string]struct {
Balance string Balance string
Code string Code string
} }
err := json.Unmarshal(GenesisAccounts, &accounts) err := json.Unmarshal(GenesisAccounts, &accounts)
if err != nil { if err != nil {
fmt.Println("enable to decode genesis json data:", err) fmt.Println("unable to decode genesis json data:", err)
os.Exit(1) os.Exit(1)
} }
statedb := state.New(common.Hash{}, db)
statedb := state.New(genesis.Root(), db)
for addr, account := range accounts { for addr, account := range accounts {
codedAddr := common.Hex2Bytes(addr) codedAddr := common.Hex2Bytes(addr)
accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr)) accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
@ -51,10 +31,15 @@ func GenesisBlock(nonce uint64, db common.Database) *types.Block {
statedb.UpdateStateObject(accountState) statedb.UpdateStateObject(accountState)
} }
statedb.Sync() statedb.Sync()
genesis.Header().Root = statedb.Root()
genesis.Td = params.GenesisDifficulty
return genesis block := types.NewBlock(&types.Header{
Difficulty: params.GenesisDifficulty,
GasLimit: params.GenesisGasLimit,
Nonce: types.EncodeNonce(nonce),
Root: statedb.Root(),
}, nil, nil, nil)
block.Td = params.GenesisDifficulty
return block
} }
var GenesisAccounts = []byte(`{ var GenesisAccounts = []byte(`{

View File

@ -73,16 +73,17 @@ func MessageGasValue(msg Message) *big.Int {
return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
} }
func IntrinsicGas(msg Message) *big.Int { // IntrinsicGas computes the 'intrisic gas' for a message
// with the given data.
func IntrinsicGas(data []byte) *big.Int {
igas := new(big.Int).Set(params.TxGas) igas := new(big.Int).Set(params.TxGas)
for _, byt := range msg.Data() { for _, byt := range data {
if byt != 0 { if byt != 0 {
igas.Add(igas, params.TxDataNonZeroGas) igas.Add(igas, params.TxDataNonZeroGas)
} else { } else {
igas.Add(igas, params.TxDataZeroGas) igas.Add(igas, params.TxDataZeroGas)
} }
} }
return igas return igas
} }
@ -195,7 +196,7 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
sender, _ := self.From() // err checked in preCheck sender, _ := self.From() // err checked in preCheck
// Pay intrinsic gas // Pay intrinsic gas
if err = self.UseGas(IntrinsicGas(self.msg)); err != nil { if err = self.UseGas(IntrinsicGas(self.msg.Data())); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, InvalidTxError(err)
} }

View File

@ -180,7 +180,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
} }
// Should supply enough intrinsic gas // Should supply enough intrinsic gas
if tx.Gas().Cmp(IntrinsicGas(tx)) < 0 { if tx.Gas().Cmp(IntrinsicGas(tx.Data())) < 0 {
return ErrIntrinsicGas return ErrIntrinsicGas
} }

View File

@ -15,71 +15,59 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a suffcient amount of computation has been carried
// out on a block.
type BlockNonce [8]byte
func EncodeNonce(i uint64) BlockNonce {
var n BlockNonce
binary.BigEndian.PutUint64(n[:], i)
return n
}
func (n BlockNonce) Uint64() uint64 {
return binary.BigEndian.Uint64(n[:])
}
type Header struct { type Header struct {
// Hash to the previous block ParentHash common.Hash // Hash to the previous block
ParentHash common.Hash UncleHash common.Hash // Uncles of this block
// Uncles of this block Coinbase common.Address // The coin base address
UncleHash common.Hash Root common.Hash // Block Trie state
// The coin base address TxHash common.Hash // Tx sha
Coinbase common.Address ReceiptHash common.Hash // Receipt sha
// Block Trie state Bloom Bloom // Bloom
Root common.Hash Difficulty *big.Int // Difficulty for the current block
// Tx sha Number *big.Int // The block number
TxHash common.Hash GasLimit *big.Int // Gas limit
// Receipt sha GasUsed *big.Int // Gas used
ReceiptHash common.Hash Time uint64 // Creation time
// Bloom Extra []byte // Extra data
Bloom Bloom MixDigest common.Hash // for quick difficulty verification
// Difficulty for the current block Nonce BlockNonce
Difficulty *big.Int
// The block number
Number *big.Int
// Gas limit
GasLimit *big.Int
// Gas used
GasUsed *big.Int
// Creation time
Time uint64
// Extra data
Extra []byte
// Mix digest for quick checking to prevent DOS
MixDigest common.Hash
// Nonce
Nonce [8]byte
} }
func (self *Header) Hash() common.Hash { func (h *Header) Hash() common.Hash {
return rlpHash(self.rlpData(true)) return rlpHash(h)
} }
func (self *Header) HashNoNonce() common.Hash { func (h *Header) HashNoNonce() common.Hash {
return rlpHash(self.rlpData(false)) return rlpHash([]interface{}{
} h.ParentHash,
h.UncleHash,
func (self *Header) rlpData(withNonce bool) []interface{} { h.Coinbase,
fields := []interface{}{ h.Root,
self.ParentHash, h.TxHash,
self.UncleHash, h.ReceiptHash,
self.Coinbase, h.Bloom,
self.Root, h.Difficulty,
self.TxHash, h.Number,
self.ReceiptHash, h.GasLimit,
self.Bloom, h.GasUsed,
self.Difficulty, h.Time,
self.Number, h.Extra,
self.GasLimit, })
self.GasUsed,
self.Time,
self.Extra,
}
if withNonce {
fields = append(fields, self.MixDigest, self.Nonce)
}
return fields
}
func (self *Header) RlpData() interface{} {
return self.rlpData(true)
} }
func (h *Header) UnmarshalJSON(data []byte) error { func (h *Header) UnmarshalJSON(data []byte) error {
@ -112,20 +100,14 @@ func rlpHash(x interface{}) (h common.Hash) {
} }
type Block struct { type Block struct {
// Preset Hash for mock (Tests)
HeaderHash common.Hash
ParentHeaderHash common.Hash
// ^^^^ ignore ^^^^
header *Header header *Header
uncles []*Header uncles []*Header
transactions Transactions transactions Transactions
Td *big.Int receipts Receipts
queued bool // flag for blockpool to skip TD check
Td *big.Int
queued bool // flag for blockpool to skip TD check
ReceivedAt time.Time ReceivedAt time.Time
receipts Receipts
} }
// StorageBlock defines the RLP encoding of a Block stored in the // StorageBlock defines the RLP encoding of a Block stored in the
@ -148,43 +130,90 @@ type storageblock struct {
TD *big.Int TD *big.Int
} }
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra []byte) *Block { var (
header := &Header{ emptyRootHash = DeriveSha(Transactions{})
Root: root, emptyUncleHash = CalcUncleHash(nil)
ParentHash: parentHash, )
Coinbase: coinbase,
Difficulty: difficulty, // NewBlock creates a new block. The input data is copied,
Time: uint64(time.Now().Unix()), // changes to header and to the field values will not affect the
Extra: extra, // block.
GasUsed: new(big.Int), //
GasLimit: new(big.Int), // The values of TxHash, UncleHash, ReceiptHash and Bloom in header
Number: new(big.Int), // are ignored and set to values derived from the given txs, uncles
// and receipts.
func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block {
b := &Block{header: copyHeader(header), Td: new(big.Int)}
// TODO: panic if len(txs) != len(receipts)
if len(txs) == 0 {
b.header.TxHash = emptyRootHash
} else {
b.header.TxHash = DeriveSha(Transactions(txs))
b.transactions = make(Transactions, len(txs))
copy(b.transactions, txs)
} }
header.SetNonce(nonce)
block := &Block{header: header}
block.Td = new(big.Int)
return block if len(receipts) == 0 {
} b.header.ReceiptHash = emptyRootHash
} else {
func (self *Header) SetNonce(nonce uint64) { b.header.ReceiptHash = DeriveSha(Receipts(receipts))
binary.BigEndian.PutUint64(self.Nonce[:], nonce) b.header.Bloom = CreateBloom(receipts)
b.receipts = make([]*Receipt, len(receipts))
copy(b.receipts, receipts)
}
if len(uncles) == 0 {
b.header.UncleHash = emptyUncleHash
} else {
b.header.UncleHash = CalcUncleHash(uncles)
b.uncles = make([]*Header, len(uncles))
for i := range uncles {
b.uncles[i] = copyHeader(uncles[i])
}
}
return b
} }
// NewBlockWithHeader creates a block with the given header data. The
// header data is copied, changes to header and to the field values
// will not affect the block.
func NewBlockWithHeader(header *Header) *Block { func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header} return &Block{header: copyHeader(header)}
} }
func (self *Block) ValidateFields() error { func copyHeader(h *Header) *Header {
if self.header == nil { cpy := *h
if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
cpy.Difficulty.Set(h.Difficulty)
}
if cpy.Number = new(big.Int); h.Number != nil {
cpy.Number.Set(h.Number)
}
if cpy.GasLimit = new(big.Int); h.GasLimit != nil {
cpy.GasLimit.Set(h.GasLimit)
}
if cpy.GasUsed = new(big.Int); h.GasUsed != nil {
cpy.GasUsed.Set(h.GasUsed)
}
if len(h.Extra) > 0 {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
return &cpy
}
func (b *Block) ValidateFields() error {
if b.header == nil {
return fmt.Errorf("header is nil") return fmt.Errorf("header is nil")
} }
for i, transaction := range self.transactions { for i, transaction := range b.transactions {
if transaction == nil { if transaction == nil {
return fmt.Errorf("transaction %d is nil", i) return fmt.Errorf("transaction %d is nil", i)
} }
} }
for i, uncle := range self.uncles { for i, uncle := range b.uncles {
if uncle == nil { if uncle == nil {
return fmt.Errorf("uncle %d is nil", i) return fmt.Errorf("uncle %d is nil", i)
} }
@ -192,64 +221,48 @@ func (self *Block) ValidateFields() error {
return nil return nil
} }
func (self *Block) DecodeRLP(s *rlp.Stream) error { func (b *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock var eb extblock
if err := s.Decode(&eb); err != nil { if err := s.Decode(&eb); err != nil {
return err return err
} }
self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs
return nil return nil
} }
func (self Block) EncodeRLP(w io.Writer) error { func (b Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, extblock{ return rlp.Encode(w, extblock{
Header: self.header, Header: b.header,
Txs: self.transactions, Txs: b.transactions,
Uncles: self.uncles, Uncles: b.uncles,
}) })
} }
func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error { func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
var sb storageblock var sb storageblock
if err := s.Decode(&sb); err != nil { if err := s.Decode(&sb); err != nil {
return err return err
} }
self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD b.header, b.uncles, b.transactions, b.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD
return nil return nil
} }
func (self StorageBlock) EncodeRLP(w io.Writer) error { func (b StorageBlock) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, storageblock{ return rlp.Encode(w, storageblock{
Header: self.header, Header: b.header,
Txs: self.transactions, Txs: b.transactions,
Uncles: self.uncles, Uncles: b.uncles,
TD: self.Td, TD: b.Td,
}) })
} }
func (self *Block) Header() *Header { // TODO: copies
return self.header func (b *Block) Uncles() []*Header { return b.uncles }
} func (b *Block) Transactions() Transactions { return b.transactions }
func (b *Block) Receipts() Receipts { return b.receipts }
func (self *Block) Uncles() []*Header { func (b *Block) Transaction(hash common.Hash) *Transaction {
return self.uncles for _, transaction := range b.transactions {
}
func (self *Block) CalculateUnclesHash() common.Hash {
return rlpHash(self.uncles)
}
func (self *Block) SetUncles(uncleHeaders []*Header) {
self.uncles = uncleHeaders
self.header.UncleHash = rlpHash(uncleHeaders)
}
func (self *Block) Transactions() Transactions {
return self.transactions
}
func (self *Block) Transaction(hash common.Hash) *Transaction {
for _, transaction := range self.transactions {
if transaction.Hash() == hash { if transaction.Hash() == hash {
return transaction return transaction
} }
@ -257,74 +270,33 @@ func (self *Block) Transaction(hash common.Hash) *Transaction {
return nil return nil
} }
func (self *Block) SetTransactions(transactions Transactions) { func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
self.transactions = transactions func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) }
self.header.TxHash = DeriveSha(transactions) func (b *Block) GasUsed() *big.Int { return new(big.Int).Set(b.header.GasUsed) }
} func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
func (self *Block) AddTransaction(transaction *Transaction) {
self.transactions = append(self.transactions, transaction) func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
self.SetTransactions(self.transactions) func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
func (b *Block) Bloom() Bloom { return b.header.Bloom }
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
func (b *Block) Time() int64 { return int64(b.header.Time) }
func (b *Block) Root() common.Hash { return b.header.Root }
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
func (b *Block) TxHash() common.Hash { return b.header.TxHash }
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) Header() *Header { return copyHeader(b.header) }
func (b *Block) HashNoNonce() common.Hash {
return b.header.HashNoNonce()
} }
func (self *Block) Receipts() Receipts { func (b *Block) Size() common.StorageSize {
return self.receipts
}
func (self *Block) SetReceipts(receipts Receipts) {
self.receipts = receipts
self.header.ReceiptHash = DeriveSha(receipts)
self.header.Bloom = CreateBloom(receipts)
}
func (self *Block) AddReceipt(receipt *Receipt) {
self.receipts = append(self.receipts, receipt)
self.SetReceipts(self.receipts)
}
func (self *Block) RlpData() interface{} {
return []interface{}{self.header, self.transactions, self.uncles}
}
func (self *Block) RlpDataForStorage() interface{} {
return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
}
// Header accessors (add as you need them)
func (self *Block) Number() *big.Int { return self.header.Number }
func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
func (self *Block) MixDigest() common.Hash { return self.header.MixDigest }
func (self *Block) Nonce() uint64 {
return binary.BigEndian.Uint64(self.header.Nonce[:])
}
func (self *Block) SetNonce(nonce uint64) {
self.header.SetNonce(nonce)
}
func (self *Block) Queued() bool { return self.queued }
func (self *Block) SetQueued(q bool) { self.queued = q }
func (self *Block) Bloom() Bloom { return self.header.Bloom }
func (self *Block) Coinbase() common.Address { return self.header.Coinbase }
func (self *Block) Time() int64 { return int64(self.header.Time) }
func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
func (self *Block) Root() common.Hash { return self.header.Root }
func (self *Block) SetRoot(root common.Hash) { self.header.Root = root }
func (self *Block) GetTransaction(i int) *Transaction {
if len(self.transactions) > i {
return self.transactions[i]
}
return nil
}
func (self *Block) GetUncle(i int) *Header {
if len(self.uncles) > i {
return self.uncles[i]
}
return nil
}
func (self *Block) Size() common.StorageSize {
c := writeCounter(0) c := writeCounter(0)
rlp.Encode(&c, self) rlp.Encode(&c, b)
return common.StorageSize(c) return common.StorageSize(c)
} }
@ -335,48 +307,32 @@ func (c *writeCounter) Write(b []byte) (int, error) {
return len(b), nil return len(b), nil
} }
func CalcUncleHash(uncles []*Header) common.Hash {
return rlpHash(uncles)
}
// WithMiningResult returns a new block with the data from b
// where nonce and mix digest are set to the provided values.
func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block {
cpy := *b.header
binary.BigEndian.PutUint64(cpy.Nonce[:], nonce)
cpy.MixDigest = mixDigest
return &Block{
header: &cpy,
transactions: b.transactions,
receipts: b.receipts,
uncles: b.uncles,
Td: b.Td,
}
}
// Implement pow.Block // Implement pow.Block
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() }
func (self *Block) Hash() common.Hash { func (b *Block) Hash() common.Hash {
if (self.HeaderHash != common.Hash{}) { return b.header.Hash()
return self.HeaderHash
} else {
return self.header.Hash()
}
} }
func (self *Block) ParentHash() common.Hash { func (b *Block) String() string {
if (self.ParentHeaderHash != common.Hash{}) {
return self.ParentHeaderHash
} else {
return self.header.ParentHash
}
}
func (self *Block) Copy() *Block {
block := NewBlock(self.header.ParentHash, self.Coinbase(), self.Root(), new(big.Int), self.Nonce(), self.header.Extra)
block.header.Bloom = self.header.Bloom
block.header.TxHash = self.header.TxHash
block.transactions = self.transactions
block.header.UncleHash = self.header.UncleHash
block.uncles = self.uncles
block.header.GasLimit.Set(self.header.GasLimit)
block.header.GasUsed.Set(self.header.GasUsed)
block.header.ReceiptHash = self.header.ReceiptHash
block.header.Difficulty.Set(self.header.Difficulty)
block.header.Number.Set(self.header.Number)
block.header.Time = self.header.Time
block.header.MixDigest = self.header.MixDigest
if self.Td != nil {
block.Td.Set(self.Td)
}
return block
}
func (self *Block) String() string {
str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v { str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v {
MinerHash: %x MinerHash: %x
%v %v
@ -385,20 +341,11 @@ Transactions:
Uncles: Uncles:
%v %v
} }
`, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) `, b.Number(), b.Size(), b.Td, b.header.HashNoNonce(), b.header, b.transactions, b.uncles)
if (self.HeaderHash != common.Hash{}) {
str += fmt.Sprintf("\nFake hash = %x", self.HeaderHash)
}
if (self.ParentHeaderHash != common.Hash{}) {
str += fmt.Sprintf("\nFake parent hash = %x", self.ParentHeaderHash)
}
return str return str
} }
func (self *Header) String() string { func (h *Header) String() string {
return fmt.Sprintf(`Header(%x): return fmt.Sprintf(`Header(%x):
[ [
ParentHash: %x ParentHash: %x
@ -414,9 +361,9 @@ func (self *Header) String() string {
GasUsed: %v GasUsed: %v
Time: %v Time: %v
Extra: %s Extra: %s
MixDigest: %x MixDigest: %x
Nonce: %x Nonce: %x
]`, self.Hash(), self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce) ]`, h.Hash(), h.ParentHash, h.UncleHash, h.Coinbase, h.Root, h.TxHash, h.ReceiptHash, h.Bloom, h.Difficulty, h.Number, h.GasLimit, h.GasUsed, h.Time, h.Extra, h.MixDigest, h.Nonce)
} }
type Blocks []*Block type Blocks []*Block
@ -442,4 +389,4 @@ func (self blockSorter) Swap(i, j int) {
} }
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 } func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 }

View File

@ -10,32 +10,32 @@ import (
) )
type VMEnv struct { type VMEnv struct {
state *state.StateDB state *state.StateDB
block *types.Block header *types.Header
msg Message msg Message
depth int depth int
chain *ChainManager chain *ChainManager
typ vm.Type typ vm.Type
// structured logging // structured logging
logs []vm.StructLog logs []vm.StructLog
} }
func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv { func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, header *types.Header) *VMEnv {
return &VMEnv{ return &VMEnv{
chain: chain, chain: chain,
state: state, state: state,
block: block, header: header,
msg: msg, msg: msg,
typ: vm.StdVmTy, typ: vm.StdVmTy,
} }
} }
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
func (self *VMEnv) Coinbase() common.Address { return self.block.Coinbase() } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time() } func (self *VMEnv) Time() int64 { return int64(self.header.Time) }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) Depth() int { return self.depth }

View File

@ -40,7 +40,10 @@ func createHashes(amount int, root common.Hash) (hashes []common.Hash) {
// createBlock assembles a new block at the given chain height. // createBlock assembles a new block at the given chain height.
func createBlock(i int, parent, hash common.Hash) *types.Block { func createBlock(i int, parent, hash common.Hash) *types.Block {
header := &types.Header{Number: big.NewInt(int64(i))} header := &types.Header{
Hash: hash,
Number: big.NewInt(int64(i))
}
block := types.NewBlockWithHeader(header) block := types.NewBlockWithHeader(header)
block.HeaderHash = hash block.HeaderHash = hash
block.ParentHeaderHash = parent block.ParentHeaderHash = parent

View File

@ -90,15 +90,13 @@ done:
} }
} }
func (self *CpuAgent) mine(block *types.Block, stop <- chan struct{}) { func (self *CpuAgent) mine(block *types.Block, stop <-chan struct{}) {
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index) glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
// Mine // Mine
nonce, mixDigest := self.pow.Search(block, stop) nonce, mixDigest := self.pow.Search(block, stop)
if nonce != 0 { if nonce != 0 {
block.SetNonce(nonce) self.returnCh <- block.WithMiningResult(nonce, common.BytesToHash(mixDigest))
block.Header().MixDigest = common.BytesToHash(mixDigest)
self.returnCh <- block
} else { } else {
self.returnCh <- nil self.returnCh <- nil
} }

View File

@ -81,9 +81,7 @@ func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, seedHash common.Hash)
// Make sure the external miner was working on the right hash // Make sure the external miner was working on the right hash
if a.currentWork != nil && a.work != nil { if a.currentWork != nil && a.work != nil {
a.currentWork.SetNonce(nonce) a.returnCh <- a.currentWork.WithMiningResult(nonce, mixDigest)
a.currentWork.Header().MixDigest = mixDigest
a.returnCh <- a.currentWork
//a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()} //a.returnCh <- Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()}
return true return true
} }

View File

@ -49,10 +49,8 @@ type uint64RingBuffer struct {
// environment is the workers current environment and holds // environment is the workers current environment and holds
// all of the current state information // all of the current state information
type environment struct { type environment struct {
totalUsedGas *big.Int // total gas usage in the cycle
state *state.StateDB // apply state changes here state *state.StateDB // apply state changes here
coinbase *state.StateObject // the miner's account coinbase *state.StateObject // the miner's account
block *types.Block // the new block
ancestors *set.Set // ancestor set (used for checking uncle parent validity) ancestors *set.Set // ancestor set (used for checking uncle parent validity)
family *set.Set // family set (used for checking uncle invalidity) family *set.Set // family set (used for checking uncle invalidity)
uncles *set.Set // uncle set uncles *set.Set // uncle set
@ -63,22 +61,12 @@ type environment struct {
ownedAccounts *set.Set ownedAccounts *set.Set
lowGasTxs types.Transactions lowGasTxs types.Transactions
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion) localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
}
// env returns a new environment for the current cycle block *types.Block // the new block
func env(block *types.Block, eth core.Backend) *environment {
state := state.New(block.Root(), eth.StateDb())
env := &environment{
totalUsedGas: new(big.Int),
state: state,
block: block,
ancestors: set.New(),
family: set.New(),
uncles: set.New(),
coinbase: state.GetOrNewStateObject(block.Coinbase()),
}
return env header *types.Header
txs []*types.Transaction
receipts []*types.Receipt
} }
// worker is the main object which takes care of applying messages to the new state // worker is the main object which takes care of applying messages to the new state
@ -137,14 +125,20 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
func (self *worker) pendingState() *state.StateDB { func (self *worker) pendingState() *state.StateDB {
self.currentMu.Lock() self.currentMu.Lock()
defer self.currentMu.Unlock() defer self.currentMu.Unlock()
return self.current.state return self.current.state
} }
func (self *worker) pendingBlock() *types.Block { func (self *worker) pendingBlock() *types.Block {
self.currentMu.Lock() self.currentMu.Lock()
defer self.currentMu.Unlock() defer self.currentMu.Unlock()
if atomic.LoadInt32(&self.mining) == 0 {
return types.NewBlock(
self.current.header,
self.current.txs,
nil,
self.current.receipts,
)
}
return self.current.block return self.current.block
} }
@ -206,7 +200,7 @@ out:
// Apply transaction to the pending state if we're not mining // Apply transaction to the pending state if we're not mining
if atomic.LoadInt32(&self.mining) == 0 { if atomic.LoadInt32(&self.mining) == 0 {
self.mu.Lock() self.mu.Lock()
self.commitTransactions(types.Transactions{ev.Tx}) self.current.commitTransactions(types.Transactions{ev.Tx}, self.gasPrice, self.proc)
self.mu.Unlock() self.mu.Unlock()
} }
} }
@ -259,8 +253,8 @@ func (self *worker) wait() {
jsonlogger.LogJson(&logger.EthMinerNewBlock{ jsonlogger.LogJson(&logger.EthMinerNewBlock{
BlockHash: block.Hash().Hex(), BlockHash: block.Hash().Hex(),
BlockNumber: block.Number(), BlockNumber: block.Number(),
ChainHeadHash: block.ParentHeaderHash.Hex(), ChainHeadHash: block.ParentHash().Hex(),
BlockPrevHash: block.ParentHeaderHash.Hex(), BlockPrevHash: block.ParentHash().Hex(),
}) })
} else { } else {
self.commitNewWork() self.commitNewWork()
@ -271,14 +265,12 @@ func (self *worker) wait() {
func (self *worker) push() { func (self *worker) push() {
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
self.current.block.SetRoot(self.current.state.Root())
// push new work to agents // push new work to agents
for _, agent := range self.agents { for _, agent := range self.agents {
atomic.AddInt32(&self.atWork, 1) atomic.AddInt32(&self.atWork, 1)
if agent.Work() != nil { if agent.Work() != nil {
agent.Work() <- self.current.block.Copy() agent.Work() <- self.current.block
} else { } else {
common.Report(fmt.Sprintf("%v %T\n", agent, agent)) common.Report(fmt.Sprintf("%v %T\n", agent, agent))
} }
@ -286,22 +278,20 @@ func (self *worker) push() {
} }
} }
func (self *worker) makeCurrent() { // makeCurrent creates a new environment for the current cycle.
block := self.chain.NewBlock(self.coinbase) func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
parent := self.chain.GetBlock(block.ParentHash()) state := state.New(parent.Root(), self.eth.StateDb())
// TMP fix for build server ... current := &environment{
if parent == nil { state: state,
return ancestors: set.New(),
family: set.New(),
uncles: set.New(),
header: header,
coinbase: state.GetOrNewStateObject(self.coinbase),
} }
if block.Time() <= parent.Time() {
block.Header().Time = parent.Header().Time + 1
}
block.Header().Extra = self.extra
// when 08 is processed ancestors contain 07 (quick block) // when 08 is processed ancestors contain 07 (quick block)
current := env(block, self.eth) for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
for _, ancestor := range self.chain.GetAncestors(block, 7) {
for _, uncle := range ancestor.Uncles() { for _, uncle := range ancestor.Uncles() {
current.family.Add(uncle.Hash()) current.family.Add(uncle.Hash())
} }
@ -309,6 +299,7 @@ func (self *worker) makeCurrent() {
current.ancestors.Add(ancestor.Hash()) current.ancestors.Add(ancestor.Hash())
} }
accounts, _ := self.eth.AccountManager().Accounts() accounts, _ := self.eth.AccountManager().Accounts()
// Keep track of transactions which return errors so they can be removed // Keep track of transactions which return errors so they can be removed
current.remove = set.New() current.remove = set.New()
current.tcount = 0 current.tcount = 0
@ -318,9 +309,6 @@ func (self *worker) makeCurrent() {
if self.current != nil { if self.current != nil {
current.localMinedBlocks = self.current.localMinedBlocks current.localMinedBlocks = self.current.localMinedBlocks
} }
current.coinbase.SetGasLimit(core.CalcGasLimit(parent))
self.current = current self.current = current
} }
@ -352,13 +340,13 @@ func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool {
//Does the block at {deepBlockNum} send earnings to my coinbase? //Does the block at {deepBlockNum} send earnings to my coinbase?
var block = self.chain.GetBlockByNumber(deepBlockNum) var block = self.chain.GetBlockByNumber(deepBlockNum)
return block != nil && block.Header().Coinbase == self.coinbase return block != nil && block.Coinbase() == self.coinbase
} }
func (self *worker) logLocalMinedBlocks(previous *environment) { func (self *worker) logLocalMinedBlocks(previous *environment) {
if previous != nil && self.current.localMinedBlocks != nil { if previous != nil && self.current.localMinedBlocks != nil {
nextBlockNum := self.current.block.Number().Uint64() nextBlockNum := self.current.block.NumberU64()
for checkBlockNum := previous.block.Number().Uint64(); checkBlockNum < nextBlockNum; checkBlockNum++ { for checkBlockNum := previous.block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
inspectBlockNum := checkBlockNum - miningLogAtDepth inspectBlockNum := checkBlockNum - miningLogAtDepth
if self.isBlockLocallyMined(inspectBlockNum) { if self.isBlockLocallyMined(inspectBlockNum) {
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum) glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
@ -376,18 +364,35 @@ func (self *worker) commitNewWork() {
defer self.currentMu.Unlock() defer self.currentMu.Unlock()
tstart := time.Now() tstart := time.Now()
parent := self.chain.CurrentBlock()
tstamp := tstart.Unix()
if tstamp <= parent.Time() {
tstamp = parent.Time() + 1
}
num := parent.Number()
header := &types.Header{
ParentHash: parent.Hash(),
Number: num.Add(num, common.Big1),
Difficulty: core.CalcDifficulty(tstamp, parent.Time(), parent.Difficulty()),
GasLimit: core.CalcGasLimit(parent),
GasUsed: new(big.Int),
Coinbase: self.coinbase,
Extra: self.extra,
Time: uint64(tstamp),
}
previous := self.current previous := self.current
self.makeCurrent() self.makeCurrent(parent, header)
current := self.current current := self.current
// commit transactions for this run.
transactions := self.eth.TxPool().GetTransactions() transactions := self.eth.TxPool().GetTransactions()
sort.Sort(types.TxByNonce{transactions}) sort.Sort(types.TxByNonce{transactions})
current.coinbase.SetGasLimit(header.GasLimit)
// commit transactions for this run current.commitTransactions(transactions, self.gasPrice, self.proc)
self.commitTransactions(transactions)
self.eth.TxPool().RemoveTransactions(current.lowGasTxs) self.eth.TxPool().RemoveTransactions(current.lowGasTxs)
// compute uncles for the new block.
var ( var (
uncles []*types.Header uncles []*types.Header
badUncles []common.Hash badUncles []common.Hash
@ -396,88 +401,76 @@ func (self *worker) commitNewWork() {
if len(uncles) == 2 { if len(uncles) == 2 {
break break
} }
if err := self.commitUncle(uncle.Header()); err != nil { if err := self.commitUncle(uncle.Header()); err != nil {
if glog.V(logger.Ridiculousness) { if glog.V(logger.Ridiculousness) {
glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4]) glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
glog.V(logger.Detail).Infoln(uncle) glog.V(logger.Detail).Infoln(uncle)
} }
badUncles = append(badUncles, hash) badUncles = append(badUncles, hash)
} else { } else {
glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4]) glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4])
uncles = append(uncles, uncle.Header()) uncles = append(uncles, uncle.Header())
} }
} }
for _, hash := range badUncles {
delete(self.possibleUncles, hash)
}
// We only care about logging if we're actually mining // commit state root after all state transitions.
core.AccumulateRewards(self.current.state, header, uncles)
current.state.Update()
header.Root = current.state.Root()
// create the new block whose nonce will be mined.
current.block = types.NewBlock(header, current.txs, uncles, current.receipts)
// We only care about logging if we're actually mining.
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", current.block.Number(), current.tcount, len(uncles), time.Since(tstart)) glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", current.block.Number(), current.tcount, len(uncles), time.Since(tstart))
self.logLocalMinedBlocks(previous) self.logLocalMinedBlocks(previous)
} }
for _, hash := range badUncles {
delete(self.possibleUncles, hash)
}
self.current.block.SetUncles(uncles)
core.AccumulateRewards(self.current.state, self.current.block)
self.current.state.Update()
self.push() self.push()
} }
var (
inclusionReward = new(big.Int).Div(core.BlockReward, big.NewInt(32))
_uncleReward = new(big.Int).Mul(core.BlockReward, big.NewInt(15))
uncleReward = new(big.Int).Div(_uncleReward, big.NewInt(16))
)
func (self *worker) commitUncle(uncle *types.Header) error { func (self *worker) commitUncle(uncle *types.Header) error {
if self.current.uncles.Has(uncle.Hash()) { hash := uncle.Hash()
// Error not unique if self.current.uncles.Has(hash) {
return core.UncleError("Uncle not unique") return core.UncleError("Uncle not unique")
} }
if !self.current.ancestors.Has(uncle.ParentHash) { if !self.current.ancestors.Has(uncle.ParentHash) {
return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
} }
if self.current.family.Has(hash) {
if self.current.family.Has(uncle.Hash()) { return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
} }
self.current.uncles.Add(uncle.Hash()) self.current.uncles.Add(uncle.Hash())
return nil return nil
} }
func (self *worker) commitTransactions(transactions types.Transactions) { func (env *environment) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
current := self.current
for _, tx := range transactions { for _, tx := range transactions {
// We can skip err. It has already been validated in the tx pool // We can skip err. It has already been validated in the tx pool
from, _ := tx.From() from, _ := tx.From()
// Check if it falls within margin. Txs from owned accounts are always processed. // Check if it falls within margin. Txs from owned accounts are always processed.
if tx.GasPrice().Cmp(self.gasPrice) < 0 && !current.ownedAccounts.Has(from) { if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
// ignore the transaction and transactor. We ignore the transactor // ignore the transaction and transactor. We ignore the transactor
// because nonce will fail after ignoring this transaction so there's // because nonce will fail after ignoring this transaction so there's
// no point // no point
current.lowGasTransactors.Add(from) env.lowGasTransactors.Add(from)
glog.V(logger.Info).Infof("transaction(%x) below gas price (tx=%v ask=%v). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], common.CurrencyToString(tx.GasPrice()), common.CurrencyToString(self.gasPrice), from[:4]) glog.V(logger.Info).Infof("transaction(%x) below gas price (tx=%v ask=%v). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], common.CurrencyToString(tx.GasPrice()), common.CurrencyToString(gasPrice), from[:4])
} }
// Continue with the next transaction if the transaction sender is included in // Continue with the next transaction if the transaction sender is included in
// the low gas tx set. This will also remove the tx and all sequential transaction // the low gas tx set. This will also remove the tx and all sequential transaction
// from this transactor // from this transactor
if current.lowGasTransactors.Has(from) { if env.lowGasTransactors.Has(from) {
// add tx to the low gas set. This will be removed at the end of the run // add tx to the low gas set. This will be removed at the end of the run
// owned accounts are ignored // owned accounts are ignored
if !current.ownedAccounts.Has(from) { if !env.ownedAccounts.Has(from) {
current.lowGasTxs = append(current.lowGasTxs, tx) env.lowGasTxs = append(env.lowGasTxs, tx)
} }
continue continue
} }
@ -487,46 +480,41 @@ func (self *worker) commitTransactions(transactions types.Transactions) {
// the transaction is processed (that could potentially be included in the block) it // the transaction is processed (that could potentially be included in the block) it
// will throw a nonce error because the previous transaction hasn't been processed. // will throw a nonce error because the previous transaction hasn't been processed.
// Therefor we need to ignore any transaction after the ignored one. // Therefor we need to ignore any transaction after the ignored one.
if current.ignoredTransactors.Has(from) { if env.ignoredTransactors.Has(from) {
continue continue
} }
self.current.state.StartRecord(tx.Hash(), common.Hash{}, 0) env.state.StartRecord(tx.Hash(), common.Hash{}, 0)
err := self.commitTransaction(tx) err := env.commitTransaction(tx, proc)
switch { switch {
case core.IsNonceErr(err) || core.IsInvalidTxErr(err): case core.IsNonceErr(err) || core.IsInvalidTxErr(err):
current.remove.Add(tx.Hash()) env.remove.Add(tx.Hash())
if glog.V(logger.Detail) { if glog.V(logger.Detail) {
glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err) glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
} }
case state.IsGasLimitErr(err): case state.IsGasLimitErr(err):
from, _ := tx.From()
// ignore the transactor so no nonce errors will be thrown for this account // ignore the transactor so no nonce errors will be thrown for this account
// next time the worker is run, they'll be picked up again. // next time the worker is run, they'll be picked up again.
current.ignoredTransactors.Add(from) env.ignoredTransactors.Add(from)
glog.V(logger.Detail).Infof("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4]) glog.V(logger.Detail).Infof("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4])
default: default:
current.tcount++ env.tcount++
} }
} }
self.current.block.Header().GasUsed = self.current.totalUsedGas
} }
func (self *worker) commitTransaction(tx *types.Transaction) error { func (env *environment) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error {
snap := self.current.state.Copy() snap := env.state.Copy()
receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true) receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true)
if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) { if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
self.current.state.Set(snap) env.state.Set(snap)
return err return err
} }
env.txs = append(env.txs, tx)
self.current.block.AddTransaction(tx) env.receipts = append(env.receipts, receipt)
self.current.block.AddReceipt(receipt)
return nil return nil
} }

View File

@ -245,7 +245,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
if b.BlockHeader == nil { if b.BlockHeader == nil {
continue // OK - block is supposed to be invalid, continue with next block continue // OK - block is supposed to be invalid, continue with next block
} else { } else {
return fmt.Errorf("Block RLP decoding failed when expected to succeed: ", err) return fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err)
} }
} }
// RLP decoding worked, try to insert into chain: // RLP decoding worked, try to insert into chain:
@ -254,7 +254,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
if b.BlockHeader == nil { if b.BlockHeader == nil {
continue // OK - block is supposed to be invalid, continue with next block continue // OK - block is supposed to be invalid, continue with next block
} else { } else {
return fmt.Errorf("Block insertion into chain failed: ", err) return fmt.Errorf("Block insertion into chain failed: %v", err)
} }
} }
if b.BlockHeader == nil { if b.BlockHeader == nil {
@ -262,7 +262,7 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error {
} }
err = t.validateBlockHeader(b.BlockHeader, cb.Header()) err = t.validateBlockHeader(b.BlockHeader, cb.Header())
if err != nil { if err != nil {
return fmt.Errorf("Block header validation failed: ", err) return fmt.Errorf("Block header validation failed: %v", err)
} }
} }
return nil return nil
@ -286,7 +286,7 @@ func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
expectedNonce := mustConvertBytes(h.Nonce) expectedNonce := mustConvertBytes(h.Nonce)
if !bytes.Equal(expectedNonce, h2.Nonce[:]) { if !bytes.Equal(expectedNonce, h2.Nonce[:]) {
return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, h2.Nonce[:]) return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, h2.Nonce)
} }
expectedNumber := mustConvertBigInt(h.Number, 16) expectedNumber := mustConvertBigInt(h.Number, 16)
@ -423,9 +423,8 @@ func mustConvertHeader(in btHeader) *types.Header {
GasLimit: mustConvertBigInt(in.GasLimit, 16), GasLimit: mustConvertBigInt(in.GasLimit, 16),
Difficulty: mustConvertBigInt(in.Difficulty, 16), Difficulty: mustConvertBigInt(in.Difficulty, 16),
Time: mustConvertUint(in.Timestamp, 16), Time: mustConvertUint(in.Timestamp, 16),
Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
} }
// XXX cheats? :-)
header.SetNonce(mustConvertUint(in.Nonce, 16))
return header return header
} }

View File

@ -209,8 +209,8 @@ func (self *XEth) AtStateNum(num int64) *XEth {
// - could be removed in favour of mining on testdag (natspec e2e + networking) // - could be removed in favour of mining on testdag (natspec e2e + networking)
// + filters // + filters
func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) { func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, txc uint64) (uint64, *XEth) {
chain := self.backend.ChainManager()
block := self.backend.ChainManager().NewBlock(address) header := chain.CurrentBlock().Header()
coinbase := statedb.GetStateObject(address) coinbase := statedb.GetStateObject(address)
coinbase.SetGasLimit(big.NewInt(10000000)) coinbase.SetGasLimit(big.NewInt(10000000))
txs := self.backend.TxPool().GetQueuedTransactions() txs := self.backend.TxPool().GetQueuedTransactions()
@ -218,7 +218,7 @@ func (self *XEth) ApplyTestTxs(statedb *state.StateDB, address common.Address, t
for i := 0; i < len(txs); i++ { for i := 0; i < len(txs); i++ {
for _, tx := range txs { for _, tx := range txs {
if tx.Nonce() == txc { if tx.Nonce() == txc {
_, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, block), tx, coinbase) _, _, err := core.ApplyMessage(core.NewEnv(statedb, self.backend.ChainManager(), tx, header), tx, coinbase)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -845,8 +845,8 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
msg.gasPrice = self.DefaultGasPrice() msg.gasPrice = self.DefaultGasPrice()
} }
block := self.CurrentBlock() header := self.CurrentBlock().Header()
vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, block) vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, header)
res, gas, err := core.ApplyMessage(vmenv, msg, from) res, gas, err := core.ApplyMessage(vmenv, msg, from)
return common.ToHex(res), gas.String(), err return common.ToHex(res), gas.String(), err