2014-12-04 09:28:02 +00:00
package core
2014-02-14 22:56:09 +00:00
import (
2014-09-24 09:39:17 +00:00
"fmt"
2014-07-29 22:31:15 +00:00
"math/big"
2014-12-04 09:28:02 +00:00
"github.com/ethereum/go-ethereum/core/types"
2014-10-23 13:01:27 +00:00
"github.com/ethereum/go-ethereum/ethutil"
2014-12-03 13:05:19 +00:00
"github.com/ethereum/go-ethereum/event"
2014-10-31 11:56:05 +00:00
"github.com/ethereum/go-ethereum/logger"
2014-12-10 18:59:12 +00:00
"github.com/ethereum/go-ethereum/state"
2014-02-14 22:56:09 +00:00
)
2014-10-31 11:56:05 +00:00
var chainlogger = logger . NewLogger ( "CHAIN" )
2014-06-23 11:54:10 +00:00
2014-11-18 15:58:22 +00:00
func AddTestNetFunds ( block * types . Block ) {
2014-11-17 11:12:55 +00:00
for _ , addr := range [ ] string {
"51ba59315b3a95761d0863b05ccc7a7f54703d99" ,
"e4157b34ea9615cfbde6b4fda419828124b70c78" ,
"b9c015918bdaba24b4ff057a92a3873d6eb201be" ,
"6c386a4b26f73c802f34673f7248bb118f97424a" ,
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826" ,
"2ef47100e0787b915105fd5e3f4ff6752079d5cb" ,
"e6716f9544a56c530d868e4bfbacb172315bdead" ,
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4" ,
} {
codedAddr := ethutil . Hex2Bytes ( addr )
2014-11-18 15:58:22 +00:00
account := block . State ( ) . GetAccount ( codedAddr )
2014-11-17 11:12:55 +00:00
account . SetBalance ( ethutil . Big ( "1606938044258990275541962092341162602522202993782792835301376" ) ) //ethutil.BigPow(2, 200)
2014-11-18 15:58:22 +00:00
block . State ( ) . UpdateStateObject ( account )
2014-11-17 11:12:55 +00:00
}
}
2014-11-18 15:58:22 +00:00
func CalcDifficulty ( block , parent * types . Block ) * big . Int {
2014-11-17 11:12:55 +00:00
diff := new ( big . Int )
adjust := new ( big . Int ) . Rsh ( parent . Difficulty , 10 )
if block . Time >= parent . Time + 5 {
diff . Sub ( parent . Difficulty , adjust )
} else {
diff . Add ( parent . Difficulty , adjust )
}
return diff
}
2014-10-20 09:53:11 +00:00
type ChainManager struct {
2014-11-18 15:58:22 +00:00
//eth EthManager
processor types . BlockProcessor
2014-12-03 13:05:19 +00:00
eventMux * event . TypeMux
2014-11-18 15:58:22 +00:00
genesisBlock * types . Block
2014-02-14 22:56:09 +00:00
// Last known total difficulty
TD * big . Int
LastBlockNumber uint64
2014-11-18 15:58:22 +00:00
CurrentBlock * types . Block
2014-02-14 22:56:09 +00:00
LastBlockHash [ ] byte
2014-12-10 18:59:12 +00:00
transState * state . StateDB
2014-02-14 22:56:09 +00:00
}
2014-12-03 13:05:19 +00:00
func NewChainManager ( mux * event . TypeMux ) * ChainManager {
2014-10-20 09:53:11 +00:00
bc := & ChainManager { }
2014-11-18 15:58:22 +00:00
bc . genesisBlock = types . NewBlockFromBytes ( ethutil . Encode ( Genesis ) )
2014-12-03 13:05:19 +00:00
bc . eventMux = mux
2014-02-14 22:56:09 +00:00
bc . setLastBlock ( )
2014-12-10 18:59:12 +00:00
bc . transState = bc . State ( ) . Copy ( )
2014-02-14 22:56:09 +00:00
return bc
}
2014-11-18 15:58:22 +00:00
func ( self * ChainManager ) SetProcessor ( proc types . BlockProcessor ) {
self . processor = proc
}
2014-12-10 18:59:12 +00:00
func ( self * ChainManager ) State ( ) * state . StateDB {
return self . CurrentBlock . State ( )
}
func ( self * ChainManager ) TransState ( ) * state . StateDB {
return self . transState
}
2014-11-17 11:12:55 +00:00
func ( bc * ChainManager ) setLastBlock ( ) {
data , _ := ethutil . Config . Db . Get ( [ ] byte ( "LastBlock" ) )
if len ( data ) != 0 {
// Prep genesis
AddTestNetFunds ( bc . genesisBlock )
2014-11-18 15:58:22 +00:00
block := types . NewBlockFromBytes ( data )
2014-11-17 11:12:55 +00:00
bc . CurrentBlock = block
bc . LastBlockHash = block . Hash ( )
bc . LastBlockNumber = block . Number . Uint64 ( )
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc . TD = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
} else {
bc . Reset ( )
}
chainlogger . Infof ( "Last block (#%d) %x\n" , bc . LastBlockNumber , bc . CurrentBlock . Hash ( ) )
2014-02-14 22:56:09 +00:00
}
2014-11-17 11:12:55 +00:00
// Block creation & chain handling
2014-11-18 15:58:22 +00:00
func ( bc * ChainManager ) NewBlock ( coinbase [ ] byte ) * types . Block {
2014-02-14 22:56:09 +00:00
var root interface { }
hash := ZeroHash256
if bc . CurrentBlock != nil {
2014-11-12 00:36:36 +00:00
root = bc . CurrentBlock . Root ( )
2014-02-14 22:56:09 +00:00
hash = bc . LastBlockHash
}
2014-04-23 13:53:53 +00:00
2014-11-18 15:58:22 +00:00
block := types . CreateBlock (
2014-02-14 22:56:09 +00:00
root ,
hash ,
coinbase ,
ethutil . BigPow ( 2 , 32 ) ,
nil ,
2014-05-22 15:35:26 +00:00
"" )
2014-02-14 22:56:09 +00:00
2014-09-15 13:42:12 +00:00
parent := bc . CurrentBlock
if parent != nil {
2014-10-10 15:00:06 +00:00
block . Difficulty = CalcDifficulty ( block , parent )
2014-05-20 13:02:46 +00:00
block . Number = new ( big . Int ) . Add ( bc . CurrentBlock . Number , ethutil . Big1 )
2014-06-10 15:22:43 +00:00
block . GasLimit = block . CalcGasLimit ( bc . CurrentBlock )
2014-09-15 13:42:12 +00:00
2014-02-14 22:56:09 +00:00
}
return block
}
2014-10-20 09:53:11 +00:00
func ( bc * ChainManager ) Reset ( ) {
2014-10-08 09:59:44 +00:00
AddTestNetFunds ( bc . genesisBlock )
2014-11-18 15:58:22 +00:00
bc . genesisBlock . Trie ( ) . Sync ( )
2014-10-08 09:59:44 +00:00
// Prepare the genesis block
2014-12-05 15:26:39 +00:00
bc . write ( bc . genesisBlock )
bc . insert ( bc . genesisBlock )
2014-10-08 09:59:44 +00:00
bc . CurrentBlock = bc . genesisBlock
bc . SetTotalDifficulty ( ethutil . Big ( "0" ) )
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc . TD = ethutil . BigD ( ethutil . Config . Db . LastKnownTD ( ) )
}
2014-12-17 11:57:35 +00:00
func ( self * ChainManager ) Export ( ) [ ] byte {
chainlogger . Infoln ( "exporting" , self . CurrentBlock . Number , "blocks" )
blocks := make ( types . Blocks , 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 )
}
2014-12-05 15:26:39 +00:00
func ( bc * ChainManager ) insert ( block * types . Block ) {
encodedBlock := block . RlpEncode ( )
ethutil . Config . Db . Put ( [ ] byte ( "LastBlock" ) , encodedBlock )
2014-11-17 11:12:55 +00:00
bc . CurrentBlock = block
bc . LastBlockHash = block . Hash ( )
2014-12-05 15:26:39 +00:00
}
func ( bc * ChainManager ) write ( block * types . Block ) {
bc . writeBlockInfo ( block )
2014-03-21 14:06:23 +00:00
2014-11-17 11:12:55 +00:00
encodedBlock := block . RlpEncode ( )
ethutil . Config . Db . Put ( block . Hash ( ) , encodedBlock )
2014-03-21 14:06:23 +00:00
}
2014-11-17 11:12:55 +00:00
// Accessors
2014-11-18 15:58:22 +00:00
func ( bc * ChainManager ) Genesis ( ) * types . Block {
2014-02-14 22:56:09 +00:00
return bc . genesisBlock
}
2014-11-17 11:12:55 +00:00
// Block fetching methods
func ( bc * ChainManager ) HasBlock ( hash [ ] byte ) bool {
data , _ := ethutil . Config . Db . Get ( hash )
return len ( data ) != 0
}
2014-10-20 09:53:11 +00:00
func ( self * ChainManager ) GetChainHashesFromHash ( hash [ ] byte , max uint64 ) ( chain [ ] [ ] byte ) {
2014-08-21 12:47:58 +00:00
block := self . GetBlock ( hash )
if block == nil {
return
}
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64 ( 0 ) ; i < max ; i ++ {
chain = append ( chain , block . Hash ( ) )
if block . Number . Cmp ( ethutil . Big0 ) <= 0 {
break
}
block = self . GetBlock ( block . PrevHash )
}
return
}
2014-11-18 15:58:22 +00:00
func ( self * ChainManager ) GetBlock ( hash [ ] byte ) * types . Block {
2014-02-14 22:56:09 +00:00
data , _ := ethutil . Config . Db . Get ( hash )
2014-02-21 12:05:59 +00:00
if len ( data ) == 0 {
return nil
}
2014-02-14 22:56:09 +00:00
2014-11-18 15:58:22 +00:00
return types . NewBlockFromBytes ( data )
2014-02-14 22:56:09 +00:00
}
2014-11-18 15:58:22 +00:00
func ( self * ChainManager ) GetBlockByNumber ( num uint64 ) * types . Block {
2014-08-06 07:53:00 +00:00
block := self . CurrentBlock
2014-09-19 11:19:19 +00:00
for ; block != nil ; block = self . GetBlock ( block . PrevHash ) {
if block . Number . Uint64 ( ) == num {
break
}
2014-08-06 07:53:00 +00:00
}
2014-09-19 11:19:19 +00:00
if block != nil && block . Number . Uint64 ( ) == 0 && num != 0 {
2014-08-06 07:53:00 +00:00
return nil
}
return block
}
2014-11-17 11:12:55 +00:00
func ( bc * ChainManager ) SetTotalDifficulty ( td * big . Int ) {
ethutil . Config . Db . Put ( [ ] byte ( "LTD" ) , td . Bytes ( ) )
bc . TD = td
}
2014-09-26 11:32:54 +00:00
2014-11-18 15:58:22 +00:00
func ( self * ChainManager ) CalcTotalDiff ( block * types . Block ) ( * big . Int , error ) {
2014-11-17 11:12:55 +00:00
parent := self . GetBlock ( block . PrevHash )
if parent == nil {
return nil , fmt . Errorf ( "Unable to calculate total diff without known parent %x" , block . PrevHash )
2014-09-26 11:32:54 +00:00
}
2014-11-17 11:12:55 +00:00
parentTd := parent . BlockInfo ( ) . TD
2014-09-26 11:32:54 +00:00
2014-11-17 11:12:55 +00:00
uncleDiff := new ( big . Int )
for _ , uncle := range block . Uncles {
uncleDiff = uncleDiff . Add ( uncleDiff , uncle . Difficulty )
}
2014-02-14 22:56:09 +00:00
2014-11-17 11:12:55 +00:00
td := new ( big . Int )
td = td . Add ( parentTd , uncleDiff )
td = td . Add ( td , block . Difficulty )
return td , nil
2014-02-14 22:56:09 +00:00
}
2014-11-18 15:58:22 +00:00
func ( bc * ChainManager ) BlockInfo ( block * types . Block ) types . BlockInfo {
bi := types . BlockInfo { }
2014-02-14 22:56:09 +00:00
data , _ := ethutil . Config . Db . Get ( append ( block . Hash ( ) , [ ] byte ( "Info" ) ... ) )
bi . RlpDecode ( data )
return bi
}
// Unexported method for writing extra non-essential block info to the db
2014-11-18 15:58:22 +00:00
func ( bc * ChainManager ) writeBlockInfo ( block * types . Block ) {
2014-02-14 22:56:09 +00:00
bc . LastBlockNumber ++
2014-11-18 15:58:22 +00:00
bi := types . BlockInfo { Number : bc . LastBlockNumber , Hash : block . Hash ( ) , Parent : block . PrevHash , TD : bc . TD }
2014-02-14 22:56:09 +00:00
// 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 ( ) )
}
2014-10-20 09:53:11 +00:00
func ( bc * ChainManager ) Stop ( ) {
2014-02-14 22:56:09 +00:00
if bc . CurrentBlock != nil {
2014-06-23 11:54:10 +00:00
chainlogger . Infoln ( "Stopped" )
2014-02-14 22:56:09 +00:00
}
}
2014-11-04 11:46:33 +00:00
2014-12-03 13:05:19 +00:00
func ( self * ChainManager ) InsertChain ( chain types . Blocks ) error {
2014-12-01 19:18:09 +00:00
for _ , block := range chain {
2014-12-03 13:05:19 +00:00
td , messages , err := self . processor . Process ( block )
2014-11-04 11:46:33 +00:00
if err != nil {
2014-12-02 10:37:33 +00:00
if IsKnownBlockErr ( err ) {
continue
}
2014-11-04 11:46:33 +00:00
2014-12-02 16:22:33 +00:00
chainlogger . Infof ( "block #%v process failed (%x)\n" , block . Number , block . Hash ( ) [ : 4 ] )
chainlogger . Infoln ( block )
chainlogger . Infoln ( err )
2014-12-01 19:18:09 +00:00
return err
2014-11-04 11:46:33 +00:00
}
2014-12-05 15:26:39 +00:00
self . write ( block )
2014-12-04 14:35:21 +00:00
if td . Cmp ( self . TD ) > 0 {
2014-12-05 15:26:39 +00:00
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 . CurrentBlock . Number , self . CurrentBlock . Hash ( ) [ : 4 ] )
}
2014-12-04 14:35:21 +00:00
self . SetTotalDifficulty ( td )
2014-12-05 15:26:39 +00:00
self . insert ( block )
2014-12-10 19:26:55 +00:00
self . transState = self . State ( ) . Copy ( )
//sm.eth.TxPool().RemoveSet(block.Transactions())
2014-12-04 14:35:21 +00:00
}
2014-12-03 13:05:19 +00:00
self . eventMux . Post ( NewBlockEvent { block } )
self . eventMux . Post ( messages )
2014-11-04 11:46:33 +00:00
}
2014-12-01 19:18:09 +00:00
return nil
2014-11-17 11:12:55 +00:00
}