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