diff options
author | obscuren <geffobscura@gmail.com> | 2014-02-15 06:56:09 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-02-15 06:56:09 +0800 |
commit | f6d1bfe45bf3709d7bad40bf563b5c09228622e3 (patch) | |
tree | df48311a5a494c66c74dcd51f1056cc699f01507 /ethchain/block_chain.go | |
parent | c2fb9f06ad018d01ce335c82b3542de16045a32d (diff) | |
download | go-tangerine-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.tar.gz go-tangerine-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.tar.zst go-tangerine-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.zip |
The great merge
Diffstat (limited to 'ethchain/block_chain.go')
-rw-r--r-- | ethchain/block_chain.go | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go new file mode 100644 index 000000000..56bc43a8e --- /dev/null +++ b/ethchain/block_chain.go @@ -0,0 +1,184 @@ +package ethchain + +import ( + "bytes" + "github.com/ethereum/eth-go/ethutil" + "log" + "math" + "math/big" +) + +type BlockChain struct { + // The famous, the fabulous Mister GENESIIIIIIS (block) + genesisBlock *Block + // Last known total difficulty + TD *big.Int + + LastBlockNumber uint64 + + CurrentBlock *Block + LastBlockHash []byte +} + +func NewBlockChain() *BlockChain { + bc := &BlockChain{} + bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + + bc.setLastBlock() + + return bc +} + +func (bc *BlockChain) Genesis() *Block { + return bc.genesisBlock +} + +func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { + var root interface{} + var lastBlockTime int64 + hash := ZeroHash256 + + if bc.CurrentBlock != nil { + root = bc.CurrentBlock.State().Root + hash = bc.LastBlockHash + lastBlockTime = bc.CurrentBlock.Time + } + + block := CreateBlock( + root, + hash, + coinbase, + ethutil.BigPow(2, 32), + nil, + "", + txs) + + if bc.CurrentBlock != nil { + var mul *big.Int + if block.Time < lastBlockTime+42 { + mul = big.NewInt(1) + } else { + mul = big.NewInt(-1) + } + + diff := new(big.Int) + diff.Add(diff, bc.CurrentBlock.Difficulty) + diff.Div(diff, big.NewInt(1024)) + diff.Mul(diff, mul) + diff.Add(diff, bc.CurrentBlock.Difficulty) + block.Difficulty = diff + } + + return block +} + +func (bc *BlockChain) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + +func (bc *BlockChain) GenesisBlock() *Block { + return bc.genesisBlock +} + +// Get chain return blocks from hash up to max in RLP format +func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { + var chain []interface{} + // Get the current hash to start with + currentHash := bc.CurrentBlock.Hash() + // Get the last number on the block chain + lastNumber := bc.BlockInfo(bc.CurrentBlock).Number + // Get the parents number + parentNumber := bc.BlockInfoByHash(hash).Number + // Get the min amount. We might not have max amount of blocks + count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) + startNumber := parentNumber + count + + num := lastNumber + for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash { + num-- + } + for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { + // Get the block of the chain + block := bc.GetBlock(currentHash) + currentHash = block.PrevHash + + chain = append(chain, block.RlpValue().Value) + //chain = append([]interface{}{block.RlpValue().Value}, chain...) + + num-- + } + + return chain +} + +func (bc *BlockChain) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + block := NewBlockFromBytes(data) + info := bc.BlockInfo(block) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = info.Number + + log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + } + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + +func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes()) + bc.TD = td +} + +// Add a block to the chain and record addition information +func (bc *BlockChain) Add(block *Block) { + bc.writeBlockInfo(block) + + // Prepare the genesis block + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + + ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) +} + +func (bc *BlockChain) GetBlock(hash []byte) *Block { + data, _ := ethutil.Config.Db.Get(hash) + + return NewBlockFromData(data) +} + +func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (bc *BlockChain) BlockInfo(block *Block) BlockInfo { + bi := BlockInfo{} + 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 +func (bc *BlockChain) writeBlockInfo(block *Block) { + bc.LastBlockNumber++ + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash} + + // 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()) +} + +func (bc *BlockChain) Stop() { + if bc.CurrentBlock != nil { + ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode()) + + log.Println("[CHAIN] Stopped") + } +} |