Block verification, TD calculations and overall block processing

This commit is contained in:
obscuren 2014-01-12 01:51:52 +01:00
parent dfb8e65ca7
commit bee05d52bf

View File

@ -3,40 +3,63 @@ package main
import ( import (
"fmt" "fmt"
"github.com/ethereum/ethutil-go" "github.com/ethereum/ethutil-go"
"errors"
"log"
"math/big"
) )
type BlockChain struct { type BlockChain struct {
lastBlock *ethutil.Block LastBlock *ethutil.Block
genesisBlock *ethutil.Block genesisBlock *ethutil.Block
TD *big.Int
} }
func NewBlockChain() *BlockChain { func NewBlockChain() *BlockChain {
bc := &BlockChain{} bc := &BlockChain{}
bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis)) bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis))
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.TD = new(big.Int)
bc.TD.SetBytes(ethutil.Config.Db.LastKnownTD())
return bc return bc
} }
type BlockManager struct { func (bc *BlockChain) HasBlock(hash string) bool {
vm *Vm return bc.LastBlock.State().Get(hash) != ""
}
blockChain *BlockChain type BlockManager struct {
// Ethereum virtual machine for processing contracts
vm *Vm
// The block chain :)
bc *BlockChain
} }
func NewBlockManager() *BlockManager { func NewBlockManager() *BlockManager {
bm := &BlockManager{vm: NewVm()} bm := &BlockManager{
vm: NewVm(),
bc: NewBlockChain(),
}
return bm return bm
} }
// Process a block. // Process a block.
func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error { func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
// TODO Validation (Or move to other part of the application) // Block validation
if err := bm.ValidateBlock(block); err != nil { if err := bm.ValidateBlock(block); err != nil {
return err return err
} }
// I'm not sure, but I don't know if there should be thrown
// any errors at this time.
if err := bm.AccumelateRewards(block); err != nil {
return err
}
// Get the tx count. Used to create enough channels to 'join' the go routines // Get the tx count. Used to create enough channels to 'join' the go routines
txCount := len(block.Transactions()) txCount := len(block.Transactions())
// Locking channel. When it has been fully buffered this method will return // Locking channel. When it has been fully buffered this method will return
@ -58,10 +81,80 @@ func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
<-lockChan <-lockChan
} }
if bm.CalculateTD(block) {
ethutil.Config.Db.Put(block.Hash(), block.MarshalRlp())
bm.bc.LastBlock = block
}
return nil return nil
} }
func (bm *BlockManager) CalculateTD(block *ethutil.Block) bool {
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
}
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
td := new(big.Int)
td = td.Add(bm.bc.TD, uncleDiff)
td = td.Add(td, block.Difficulty)
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
if td.Cmp(bm.bc.TD) > 0 {
bm.bc.LastBlock = block
// Set the new total difficulty back to the block chain
bm.bc.TD = td
return true
}
return false
}
// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain
func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error { func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error {
// TODO
// 1. Check if the nonce of the block is valid
// 2. Check if the difficulty is correct
// Check if we have the parent hash, if it isn't known we discard it
// Reasons might be catching up or simply an invalid block
if bm.bc.HasBlock(block.PrevHash) {
// Check each uncle's previous hash. In order for it to be valid
// is if it has the same block hash as the current
for _, uncle := range block.Uncles {
if uncle.PrevHash != block.PrevHash {
if Debug {
log.Printf("Uncle prvhash mismatch %x %x\n", block.PrevHash, uncle.PrevHash)
}
return errors.New("Mismatching Prvhash from uncle")
}
}
} else {
return errors.New("Block's parent unknown")
}
return nil
}
func (bm *BlockManager) AccumelateRewards(block *ethutil.Block) error {
// Get the coinbase rlp data
d := block.State().Get(block.Coinbase)
ether := ethutil.NewEtherFromData([]byte(d))
// Reward amount of ether to the coinbase address
ether.AddFee(ethutil.CalculateBlockReward(block, len(block.Uncles)))
block.State().Update(block.Coinbase, string(ether.MarshalRlp()))
// TODO Reward each uncle
return nil return nil
} }