github.com/karalabe/go-ethereum@v0.8.5/core/chain_manager.go (about)

     1  package core
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/big"
     7  	"sync"
     8  
     9  	"github.com/ethereum/go-ethereum/core/types"
    10  	"github.com/ethereum/go-ethereum/ethutil"
    11  	"github.com/ethereum/go-ethereum/event"
    12  	"github.com/ethereum/go-ethereum/logger"
    13  	"github.com/ethereum/go-ethereum/rlp"
    14  	"github.com/ethereum/go-ethereum/state"
    15  )
    16  
    17  var chainlogger = logger.NewLogger("CHAIN")
    18  
    19  type ChainEvent struct {
    20  	Block *types.Block
    21  	Td    *big.Int
    22  }
    23  
    24  type StateQuery interface {
    25  	GetAccount(addr []byte) *state.StateObject
    26  }
    27  
    28  func CalcDifficulty(block, parent *types.Block) *big.Int {
    29  	diff := new(big.Int)
    30  
    31  	adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
    32  	if block.Time() >= parent.Time()+8 {
    33  		diff.Sub(parent.Difficulty(), adjust)
    34  	} else {
    35  		diff.Add(parent.Difficulty(), adjust)
    36  	}
    37  
    38  	return diff
    39  }
    40  
    41  func CalculateTD(block, parent *types.Block) *big.Int {
    42  	uncleDiff := new(big.Int)
    43  	for _, uncle := range block.Uncles() {
    44  		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
    45  	}
    46  
    47  	// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
    48  	td := new(big.Int)
    49  	td = td.Add(parent.Td, uncleDiff)
    50  	td = td.Add(td, block.Header().Difficulty)
    51  
    52  	return td
    53  }
    54  
    55  func CalcGasLimit(parent, block *types.Block) *big.Int {
    56  	if block.Number().Cmp(big.NewInt(0)) == 0 {
    57  		return ethutil.BigPow(10, 6)
    58  	}
    59  
    60  	// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
    61  
    62  	previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
    63  	current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
    64  	curInt := new(big.Int).Div(current.Num(), current.Denom())
    65  
    66  	result := new(big.Int).Add(previous, curInt)
    67  	result.Div(result, big.NewInt(1024))
    68  
    69  	min := big.NewInt(125000)
    70  
    71  	return ethutil.BigMax(min, result)
    72  }
    73  
    74  type ChainManager struct {
    75  	//eth          EthManager
    76  	db           ethutil.Database
    77  	processor    types.BlockProcessor
    78  	eventMux     *event.TypeMux
    79  	genesisBlock *types.Block
    80  	// Last known total difficulty
    81  	mu            sync.RWMutex
    82  	tsmu          sync.RWMutex
    83  	td            *big.Int
    84  	currentBlock  *types.Block
    85  	lastBlockHash []byte
    86  
    87  	transState *state.StateDB
    88  }
    89  
    90  func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
    91  	bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
    92  	bc.setLastBlock()
    93  	bc.transState = bc.State().Copy()
    94  
    95  	return bc
    96  }
    97  
    98  func (self *ChainManager) Td() *big.Int {
    99  	self.mu.RLock()
   100  	defer self.mu.RUnlock()
   101  
   102  	return self.td
   103  }
   104  
   105  func (self *ChainManager) LastBlockHash() []byte {
   106  	self.mu.RLock()
   107  	defer self.mu.RUnlock()
   108  
   109  	return self.lastBlockHash
   110  }
   111  
   112  func (self *ChainManager) CurrentBlock() *types.Block {
   113  	self.mu.RLock()
   114  	defer self.mu.RUnlock()
   115  
   116  	return self.currentBlock
   117  }
   118  
   119  func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
   120  	self.mu.RLock()
   121  	defer self.mu.RUnlock()
   122  
   123  	return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
   124  }
   125  
   126  func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
   127  	self.processor = proc
   128  }
   129  
   130  func (self *ChainManager) State() *state.StateDB {
   131  	return state.New(self.CurrentBlock().Root(), self.db)
   132  }
   133  
   134  func (self *ChainManager) TransState() *state.StateDB {
   135  	self.tsmu.RLock()
   136  	defer self.tsmu.RUnlock()
   137  
   138  	return self.transState
   139  }
   140  
   141  func (self *ChainManager) setTransState(statedb *state.StateDB) {
   142  	self.transState = statedb
   143  }
   144  
   145  func (bc *ChainManager) setLastBlock() {
   146  	data, _ := bc.db.Get([]byte("LastBlock"))
   147  	if len(data) != 0 {
   148  		var block types.Block
   149  		rlp.Decode(bytes.NewReader(data), &block)
   150  		bc.currentBlock = &block
   151  		bc.lastBlockHash = block.Hash()
   152  
   153  		// Set the last know difficulty (might be 0x0 as initial value, Genesis)
   154  		bc.td = ethutil.BigD(bc.db.LastKnownTD())
   155  	} else {
   156  		bc.Reset()
   157  	}
   158  
   159  	chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
   160  }
   161  
   162  // Block creation & chain handling
   163  func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
   164  	bc.mu.RLock()
   165  	defer bc.mu.RUnlock()
   166  
   167  	var root []byte
   168  	parentHash := ZeroHash256
   169  
   170  	if bc.currentBlock != nil {
   171  		root = bc.currentBlock.Header().Root
   172  		parentHash = bc.lastBlockHash
   173  	}
   174  
   175  	block := types.NewBlock(
   176  		parentHash,
   177  		coinbase,
   178  		root,
   179  		ethutil.BigPow(2, 32),
   180  		nil,
   181  		"")
   182  	block.SetUncles(nil)
   183  	block.SetTransactions(nil)
   184  	block.SetReceipts(nil)
   185  
   186  	parent := bc.currentBlock
   187  	if parent != nil {
   188  		header := block.Header()
   189  		header.Difficulty = CalcDifficulty(block, parent)
   190  		header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
   191  		header.GasLimit = CalcGasLimit(parent, block)
   192  
   193  	}
   194  
   195  	return block
   196  }
   197  
   198  func (bc *ChainManager) Reset() {
   199  	bc.mu.Lock()
   200  	defer bc.mu.Unlock()
   201  
   202  	for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
   203  		bc.db.Delete(block.Hash())
   204  	}
   205  
   206  	// Prepare the genesis block
   207  	bc.write(bc.genesisBlock)
   208  	bc.insert(bc.genesisBlock)
   209  	bc.currentBlock = bc.genesisBlock
   210  
   211  	bc.setTotalDifficulty(ethutil.Big("0"))
   212  }
   213  
   214  func (self *ChainManager) Export() []byte {
   215  	self.mu.RLock()
   216  	defer self.mu.RUnlock()
   217  
   218  	chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
   219  
   220  	blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
   221  	for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
   222  		blocks[block.NumberU64()] = block
   223  	}
   224  
   225  	return ethutil.Encode(blocks)
   226  }
   227  
   228  func (bc *ChainManager) insert(block *types.Block) {
   229  	encodedBlock := ethutil.Encode(block)
   230  	bc.db.Put([]byte("LastBlock"), encodedBlock)
   231  	bc.currentBlock = block
   232  	bc.lastBlockHash = block.Hash()
   233  }
   234  
   235  func (bc *ChainManager) write(block *types.Block) {
   236  	encodedBlock := ethutil.Encode(block.RlpDataForStorage())
   237  	bc.db.Put(block.Hash(), encodedBlock)
   238  }
   239  
   240  // Accessors
   241  func (bc *ChainManager) Genesis() *types.Block {
   242  	return bc.genesisBlock
   243  }
   244  
   245  // Block fetching methods
   246  func (bc *ChainManager) HasBlock(hash []byte) bool {
   247  	data, _ := bc.db.Get(hash)
   248  	return len(data) != 0
   249  }
   250  
   251  func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
   252  	block := self.GetBlock(hash)
   253  	if block == nil {
   254  		return
   255  	}
   256  
   257  	// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
   258  	for i := uint64(0); i < max; i++ {
   259  		parentHash := block.Header().ParentHash
   260  		block = self.GetBlock(parentHash)
   261  		if block == nil {
   262  			chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
   263  			break
   264  		}
   265  
   266  		chain = append(chain, block.Hash())
   267  		if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
   268  			break
   269  		}
   270  	}
   271  	fmt.Printf("get hash %x (%d)\n", hash, len(chain))
   272  
   273  	return
   274  }
   275  
   276  func (self *ChainManager) GetBlock(hash []byte) *types.Block {
   277  	data, _ := self.db.Get(hash)
   278  	if len(data) == 0 {
   279  		return nil
   280  	}
   281  	var block types.Block
   282  	if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
   283  		fmt.Println(err)
   284  		return nil
   285  	}
   286  
   287  	return &block
   288  }
   289  
   290  func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
   291  	for i := 0; block != nil && i < length; i++ {
   292  		uncles = append(uncles, block.Uncles()...)
   293  		block = self.GetBlock(block.ParentHash())
   294  	}
   295  
   296  	return
   297  }
   298  
   299  func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
   300  	for i := 0; i < length; i++ {
   301  		block = self.GetBlock(block.ParentHash())
   302  		if block == nil {
   303  			break
   304  		}
   305  
   306  		blocks = append(blocks, block)
   307  	}
   308  
   309  	return
   310  }
   311  
   312  func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
   313  	self.mu.RLock()
   314  	defer self.mu.RUnlock()
   315  
   316  	var block *types.Block
   317  
   318  	if num <= self.currentBlock.Number().Uint64() {
   319  		block = self.currentBlock
   320  		for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
   321  			if block.Header().Number.Uint64() == num {
   322  				break
   323  			}
   324  		}
   325  	}
   326  
   327  	return block
   328  }
   329  
   330  func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
   331  	bc.db.Put([]byte("LTD"), td.Bytes())
   332  	bc.td = td
   333  }
   334  
   335  func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
   336  	parent := self.GetBlock(block.Header().ParentHash)
   337  	if parent == nil {
   338  		return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
   339  	}
   340  
   341  	parentTd := parent.Td
   342  
   343  	uncleDiff := new(big.Int)
   344  	for _, uncle := range block.Uncles() {
   345  		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
   346  	}
   347  
   348  	td := new(big.Int)
   349  	td = td.Add(parentTd, uncleDiff)
   350  	td = td.Add(td, block.Header().Difficulty)
   351  
   352  	return td, nil
   353  }
   354  
   355  func (bc *ChainManager) Stop() {
   356  	if bc.CurrentBlock != nil {
   357  		chainlogger.Infoln("Stopped")
   358  	}
   359  }
   360  
   361  func (self *ChainManager) InsertChain(chain types.Blocks) error {
   362  	self.tsmu.Lock()
   363  	defer self.tsmu.Unlock()
   364  
   365  	for _, block := range chain {
   366  		td, err := self.processor.Process(block)
   367  		if err != nil {
   368  			if IsKnownBlockErr(err) {
   369  				continue
   370  			}
   371  
   372  			h := block.Header()
   373  			chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
   374  			chainlogger.Infoln(block)
   375  			chainlogger.Infoln(err)
   376  			return err
   377  		}
   378  		block.Td = td
   379  
   380  		var chain, split bool
   381  		self.mu.Lock()
   382  		{
   383  			self.write(block)
   384  			cblock := self.currentBlock
   385  			if td.Cmp(self.td) > 0 {
   386  				if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
   387  					chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
   388  					split = true
   389  				}
   390  
   391  				self.setTotalDifficulty(td)
   392  				self.insert(block)
   393  
   394  				chain = true
   395  			}
   396  		}
   397  		self.mu.Unlock()
   398  
   399  		if chain {
   400  			self.eventMux.Post(ChainEvent{block, td})
   401  		}
   402  
   403  		if split {
   404  			self.setTransState(state.New(block.Root(), self.db))
   405  			self.eventMux.Post(ChainSplitEvent{block})
   406  		}
   407  	}
   408  
   409  	return nil
   410  }
   411  
   412  // Satisfy state query interface
   413  func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
   414  	return self.State().GetAccount(addr)
   415  }