@ -3,6 +3,7 @@ package core
import (
"fmt"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
@ -50,14 +51,34 @@ type ChainManager struct {
eventMux * event . TypeMux
genesisBlock * types . Block
// Last known total difficulty
TD * big . Int
mu sync . RWMutex
td * big . Int
lastBlockNumber uint64
currentBlock * types . Block
lastBlockHash [ ] byte
LastBlockNumber uint64
transState * state . StateDB
}
CurrentBlock * types . Block
LastBlockHash [ ] byte
func ( self * ChainManager ) Td ( ) * big . Int {
self . mu . RLock ( )
defer self . mu . RUnlock ( )
transState * state . StateDB
return self . td
}
func ( self * ChainManager ) LastBlockNumber ( ) uint64 {
self . mu . RLock ( )
defer self . mu . RUnlock ( )
return self . lastBlockNumber
}
func ( self * ChainManager ) CurrentBlock ( ) * types . Block {
self . mu . RLock ( )
defer self . mu . RUnlock ( )
return self . currentBlock
}
func NewChainManager ( mux * event . TypeMux ) * ChainManager {
@ -77,7 +98,7 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
}
func ( self * ChainManager ) State ( ) * state . StateDB {
return self . CurrentBlock . State ( )
return self . CurrentBlock ( ) . State ( )
}
func ( self * ChainManager ) TransState ( ) * state . StateDB {
@ -91,27 +112,30 @@ func (bc *ChainManager) setLastBlock() {
AddTestNetFunds ( bc . genesisBlock )
block := types . NewBlockFromBytes ( data )
bc . C urrentBlock = block
bc . L astBlockHash = block . Hash ( )
bc . L astBlockNumber = block . Number . Uint64 ( )
bc . c urrentBlock = block
bc . l astBlockHash = block . Hash ( )
bc . l astBlockNumber = block . Number . Uint64 ( )
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc . TD = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
bc . td = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
} else {
bc . Reset ( )
}
chainlogger . Infof ( "Last block (#%d) %x\n" , bc . L astBlockNumber, bc . C urrentBlock. Hash ( ) )
chainlogger . Infof ( "Last block (#%d) %x\n" , bc . l astBlockNumber, bc . c urrentBlock. Hash ( ) )
}
// Block creation & chain handling
func ( bc * ChainManager ) NewBlock ( coinbase [ ] byte ) * types . Block {
bc . mu . RLock ( )
defer bc . mu . RUnlock ( )
var root interface { }
hash := ZeroHash256
if bc . CurrentBlock != nil {
root = bc . C urrentBlock. Root ( )
hash = bc . L astBlockHash
root = bc . c urrentBlock. Root ( )
hash = bc . l astBlockHash
}
block := types . CreateBlock (
@ -122,11 +146,11 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
nil ,
"" )
parent := bc . C urrentBlock
parent := bc . c urrentBlock
if parent != nil {
block . Difficulty = CalcDifficulty ( block , parent )
block . Number = new ( big . Int ) . Add ( bc . C urrentBlock. Number , ethutil . Big1 )
block . GasLimit = block . CalcGasLimit ( bc . C urrentBlock)
block . Number = new ( big . Int ) . Add ( bc . c urrentBlock. Number , ethutil . Big1 )
block . GasLimit = block . CalcGasLimit ( bc . c urrentBlock)
}
@ -134,35 +158,42 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
}
func ( bc * ChainManager ) Reset ( ) {
bc . mu . Lock ( )
defer bc . mu . Unlock ( )
AddTestNetFunds ( bc . genesisBlock )
bc . genesisBlock . Trie ( ) . Sync ( )
// Prepare the genesis block
bc . write ( bc . genesisBlock )
bc . insert ( bc . genesisBlock )
bc . C urrentBlock = bc . genesisBlock
bc . c urrentBlock = bc . genesisBlock
bc . S etTotalDifficulty( ethutil . Big ( "0" ) )
bc . s etTotalDifficulty( ethutil . Big ( "0" ) )
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc . TD = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
bc . td = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
}
func ( self * ChainManager ) Export ( ) [ ] byte {
chainlogger . Infoln ( "exporting" , self . CurrentBlock . Number , "blocks" )
self . mu . RLock ( )
defer self . mu . RUnlock ( )
blocks := make ( types . Blocks , int ( self . CurrentBlock . Number . Int64 ( ) ) + 1 )
for block := self . CurrentBlock ; block != nil ; block = self . GetBlock ( block . PrevHash ) {
chainlogger . Infof ( "exporting %v blocks...\n" , self . currentBlock . Number )
blocks := make ( [ ] * types . Block , int ( self . currentBlock . Number . Int64 ( ) ) + 1 )
for block := self . currentBlock ; block != nil ; block = self . GetBlock ( block . PrevHash ) {
blocks [ block . Number . Int64 ( ) ] = block
}
return ethutil . Encode ( blocks )
}
func ( bc * ChainManager ) insert ( block * types . Block ) {
encodedBlock := block . RlpEncode ( )
ethutil . Config . Db . Put ( [ ] byte ( "LastBlock" ) , encodedBlock )
bc . C urrentBlock = block
bc . L astBlockHash = block . Hash ( )
bc . c urrentBlock = block
bc . l astBlockHash = block . Hash ( )
}
func ( bc * ChainManager ) write ( block * types . Block ) {
@ -213,7 +244,10 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block {
}
func ( self * ChainManager ) GetBlockByNumber ( num uint64 ) * types . Block {
block := self . CurrentBlock
self . mu . RLock ( )
defer self . mu . RUnlock ( )
block := self . currentBlock
for ; block != nil ; block = self . GetBlock ( block . PrevHash ) {
if block . Number . Uint64 ( ) == num {
break
@ -227,9 +261,9 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
return block
}
func ( bc * ChainManager ) S etTotalDifficulty( td * big . Int ) {
func ( bc * ChainManager ) s etTotalDifficulty( td * big . Int ) {
ethutil . Config . Db . Put ( [ ] byte ( "LTD" ) , td . Bytes ( ) )
bc . TD = td
bc . td = td
}
func ( self * ChainManager ) CalcTotalDiff ( block * types . Block ) ( * big . Int , error ) {
@ -262,8 +296,8 @@ func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo {
// Unexported method for writing extra non-essential block info to the db
func ( bc * ChainManager ) writeBlockInfo ( block * types . Block ) {
bc . L astBlockNumber++
bi := types . BlockInfo { Number : bc . L astBlockNumber, Hash : block . Hash ( ) , Parent : block . PrevHash , TD : bc . TD }
bc . l astBlockNumber++
bi := types . BlockInfo { Number : bc . l astBlockNumber, Hash : block . Hash ( ) , Parent : block . PrevHash , TD : bc . td }
// For now we use the block hash with the words "info" appended as key
ethutil . Config . Db . Put ( append ( block . Hash ( ) , [ ] byte ( "Info" ) ... ) , bi . RlpEncode ( ) )
@ -289,17 +323,22 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
return err
}
self . mu . Lock ( )
{
self . write ( block )
if td . Cmp ( self . TD ) > 0 {
if block . Number . Cmp ( new ( big . Int ) . Add ( self . CurrentBlock . Number , ethutil . Big1 ) ) < 0 {
chainlogger . Infof ( "Split detected. New head #%v (%x), was #%v (%x)\n" , block . Number , block . Hash ( ) [ : 4 ] , self . C urrentBlock. Number , self . C urrentBlock. Hash ( ) [ : 4 ] )
if td . Cmp ( self . td ) > 0 {
if block . Number . Cmp ( new ( big . Int ) . Add ( self . c urrentBlock. Number , ethutil . Big1 ) ) < 0 {
chainlogger . Infof ( "Split detected. New head #%v (%x), was #%v (%x)\n" , block . Number , block . Hash ( ) [ : 4 ] , self . c urrentBlock. Number , self . c urrentBlock. Hash ( ) [ : 4 ] )
}
self . S etTotalDifficulty( td )
self . s etTotalDifficulty( td )
self . insert ( block )
self . transState = self . State ( ) . Copy ( )
//sm.eth.TxPool().RemoveSet(block.Transactions())
self . transState = self . currentBlock . State ( ) . Copy ( )
}
}
self . mu . Unlock ( )
self . eventMux . Post ( NewBlockEvent { block } )
self . eventMux . Post ( messages )