aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/block.go3
-rw-r--r--ethchain/block_chain.go104
-rw-r--r--ethchain/dagger.go31
-rw-r--r--ethchain/state_manager.go21
-rw-r--r--ethchain/transaction_pool.go19
5 files changed, 150 insertions, 28 deletions
diff --git a/ethchain/block.go b/ethchain/block.go
index 1f63c2c9e..732739c1b 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -304,6 +304,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
func (block *Block) String() string {
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}
+func (block *Block) GetRoot() interface{} {
+ return block.state.trie.Root
+}
//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} {
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
index 2865e0a21..f25f0ca5a 100644
--- a/ethchain/block_chain.go
+++ b/ethchain/block_chain.go
@@ -3,6 +3,7 @@ package ethchain
import (
"bytes"
"github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/ethwire"
"log"
"math"
"math/big"
@@ -24,6 +25,7 @@ type BlockChain struct {
func NewBlockChain(ethereum EthManager) *BlockChain {
bc := &BlockChain{}
bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis))
+ bc.Ethereum = ethereum
bc.setLastBlock()
@@ -44,7 +46,6 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
hash = bc.LastBlockHash
lastBlockTime = bc.CurrentBlock.Time
}
-
block := CreateBlock(
root,
hash,
@@ -78,6 +79,104 @@ func (bc *BlockChain) HasBlock(hash []byte) bool {
return len(data) != 0
}
+// TODO: At one point we might want to save a block by prevHash in the db to optimise this...
+func (bc *BlockChain) HasBlockWithPrevHash(hash []byte) bool {
+ block := bc.CurrentBlock
+
+ for ; block != nil; block = bc.GetBlock(block.PrevHash) {
+ if bytes.Compare(hash, block.PrevHash) == 0 {
+ return true
+ }
+ }
+ return false
+}
+
+func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int {
+ blockDiff := new(big.Int)
+
+ for _, uncle := range block.Uncles {
+ blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty)
+ }
+ blockDiff = blockDiff.Add(blockDiff, block.Difficulty)
+
+ return blockDiff
+}
+
+// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one
+// Return true if we are the using the canonical chain false if not
+func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) bool {
+ // 1. Calculate TD of the current chain
+ // 2. Calculate TD of the new chain
+ // Reset state to the correct one
+
+ chainDifficulty := new(big.Int)
+
+ // Calculate the entire chain until the block we both have
+ // Start with the newest block we got, all the way back to the common block we both know
+ for i := 0; i < (msg.Data.Len() - 1); i++ {
+ block := NewBlockFromRlpValue(msg.Data.Get(i))
+ if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
+ log.Println("[BCHAIN] We have found the common parent block, breaking")
+ break
+ }
+ chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block))
+ }
+
+ log.Println("[BCHAIN] Incoming chain difficulty:", chainDifficulty)
+
+ curChainDifficulty := new(big.Int)
+ block := bc.CurrentBlock
+
+ for ; block != nil; block = bc.GetBlock(block.PrevHash) {
+ if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
+ log.Println("[BCHAIN] We have found the common parent block, breaking")
+ break
+ }
+ curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block))
+ }
+
+ log.Println("[BCHAIN] Current chain difficulty:", curChainDifficulty)
+ if chainDifficulty.Cmp(curChainDifficulty) == 1 {
+ log.Println("[BCHAIN] The incoming Chain beat our asses, resetting")
+ bc.ResetTillBlockHash(commonBlockHash)
+ return false
+ } else {
+ log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.")
+ return true
+ }
+}
+func (bc *BlockChain) ResetTillBlockHash(hash []byte) error {
+ lastBlock := bc.CurrentBlock
+ returnTo := bc.GetBlock(hash)
+
+ // TODO: REFACTOR TO FUNCTION, Used multiple times
+ bc.CurrentBlock = returnTo
+ bc.LastBlockHash = returnTo.Hash()
+ info := bc.BlockInfo(returnTo)
+ bc.LastBlockNumber = info.Number
+ // END TODO
+
+ bc.Ethereum.StateManager().PrepareDefault(returnTo)
+ err := ethutil.Config.Db.Delete(lastBlock.Hash())
+ if err != nil {
+ return err
+ }
+
+ var block *Block
+ for ; block != nil; block = bc.GetBlock(block.PrevHash) {
+ if bytes.Compare(block.Hash(), hash) == 0 {
+ log.Println("[CHAIN] We have arrived at the the common parent block, breaking")
+ break
+ }
+ err = ethutil.Config.Db.Delete(block.Hash())
+ if err != nil {
+ return err
+ }
+ }
+ log.Println("[CHAIN] Split chain deleted and reverted to common parent block.")
+ return nil
+}
+
func (bc *BlockChain) GenesisBlock() *Block {
return bc.genesisBlock
}
@@ -136,6 +235,7 @@ func AddTestNetFunds(block *Block) {
"e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran
} {
//log.Println("2^200 Wei to", addr)
codedAddr := ethutil.FromHex(addr)
@@ -180,8 +280,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
// 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()
diff --git a/ethchain/dagger.go b/ethchain/dagger.go
index 5b4f8b2cd..a80a9d421 100644
--- a/ethchain/dagger.go
+++ b/ethchain/dagger.go
@@ -11,7 +11,7 @@ import (
)
type PoW interface {
- Search(block *Block) []byte
+ Search(block *Block, reactChan chan ethutil.React) []byte
Verify(hash []byte, diff *big.Int, nonce []byte) bool
}
@@ -19,15 +19,30 @@ type EasyPow struct {
hash *big.Int
}
-func (pow *EasyPow) Search(block *Block) []byte {
+func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
-
hash := block.HashNoNonce()
diff := block.Difficulty
+ i := int64(0)
+ start := time.Now().UnixNano()
+
for {
- sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())
- if pow.Verify(hash, diff, sha) {
- return sha
+ select {
+ case <-reactChan:
+ log.Println("[pow] Received reactor event; breaking out.")
+ return nil
+ default:
+ i++
+ if i%1234567 == 0 {
+ elapsed := time.Now().UnixNano() - start
+ hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
+ log.Println("Hashing @", int64(hashes), "khash")
+ }
+
+ sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())
+ if pow.Verify(hash, diff, sha) {
+ return sha
+ }
}
}
@@ -98,9 +113,9 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
for k := 0; k < amountOfRoutines; k++ {
go dag.Find(obj, resChan)
- }
- // Wait for each go routine to finish
+ // Wait for each go routine to finish
+ }
for k := 0; k < amountOfRoutines; k++ {
// Get the result from the channel. 0 = quit
if r := <-resChan; r != 0 {
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 3b5507740..5692a1d88 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -19,6 +19,7 @@ type EthManager interface {
BlockChain() *BlockChain
TxPool() *TxPool
Broadcast(msgType ethwire.MsgType, data []interface{})
+ Reactor() *ethutil.ReactorEngine
}
type StateManager struct {
@@ -49,8 +50,6 @@ type StateManager struct {
// Comparative state it used for comparing and validating end
// results
compState *State
-
- miningState *State
}
func NewStateManager(ethereum EthManager) *StateManager {
@@ -63,7 +62,6 @@ func NewStateManager(ethereum EthManager) *StateManager {
bc: ethereum.BlockChain(),
}
sm.procState = ethereum.BlockChain().CurrentBlock.State()
-
return sm
}
@@ -134,7 +132,7 @@ func (sm *StateManager) PrepareDefault(block *Block) {
}
// Block processing and validating with a given (temporarily) state
-func (sm *StateManager) ProcessBlock(block *Block) error {
+func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
defer sm.mutex.Unlock()
@@ -143,7 +141,6 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
// nodes this won't happen because Commit would have been called
// before that.
defer sm.bc.CurrentBlock.Undo()
-
hash := block.Hash()
if sm.bc.HasBlock(hash) {
@@ -195,13 +192,15 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
}
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
+ if dontReact == false {
+ sm.Ethereum.Reactor().Post("newBlock", block)
+ }
} else {
fmt.Println("total diff failed")
}
return nil
}
-
func (sm *StateManager) CalculateTD(block *Block) bool {
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
@@ -215,6 +214,9 @@ func (sm *StateManager) CalculateTD(block *Block) bool {
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
+ fmt.Println("new block td:", td)
+ fmt.Println("cur block td:", sm.bc.TD)
+
if td.Cmp(sm.bc.TD) > 0 {
// Set the new total difficulty back to the block chain
sm.bc.SetTotalDifficulty(td)
@@ -272,15 +274,16 @@ func CalculateUncleReward(block *Block) *big.Int {
}
func (sm *StateManager) AccumelateRewards(block *Block) error {
+
// Get the coinbase rlp data
//XXX addr := processor.state.GetAccount(block.Coinbase)
addr := sm.procState.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
-
//XXX processor.state.UpdateAccount(block.Coinbase, addr)
- sm.procState.UpdateAccount(block.Coinbase, addr)
-
+ var acc []byte
+ copy(acc, block.Coinbase)
+ sm.procState.UpdateAccount(acc, addr)
for _, uncle := range block.Uncles {
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
uncleAddr.AddFee(CalculateUncleReward(uncle))
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
index fdc386303..26827c289 100644
--- a/ethchain/transaction_pool.go
+++ b/ethchain/transaction_pool.go
@@ -104,15 +104,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
if sender.Amount.Cmp(totAmount) < 0 {
- return errors.New("Insufficient amount in sender's account")
+ return errors.New("[TXPL] Insufficient amount in sender's account")
}
if sender.Nonce != tx.Nonce {
- if ethutil.Config.Debug {
- return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce)
- } else {
- return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce)
- }
+ return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce)
}
// Get the receiver
@@ -137,7 +133,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash())
- // Notify the subscribers
pool.notifySubscribers(TxPost, tx)
return
@@ -149,7 +144,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
block := pool.Ethereum.BlockChain().CurrentBlock
// Something has gone horribly wrong if this happens
if block == nil {
- return errors.New("No last block on the block chain")
+ return errors.New("[TXPL] No last block on the block chain")
}
// Get the sender
@@ -160,7 +155,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
if sender.Amount.Cmp(totAmount) < 0 {
- return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
+ return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
}
// Increment the nonce making each tx valid only once to prevent replay
@@ -174,6 +169,7 @@ out:
for {
select {
case tx := <-pool.queueChan:
+ log.Println("Received new Tx to queue")
hash := tx.Hash()
foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool {
return bytes.Compare(tx.Hash(), hash) == 0
@@ -190,9 +186,14 @@ out:
log.Println("Validating Tx failed", err)
}
} else {
+ log.Println("Transaction ok, adding")
// Call blocking version. At this point it
// doesn't matter since this is a goroutine
pool.addTransaction(tx)
+ log.Println("Added")
+
+ // Notify the subscribers
+ pool.Ethereum.Reactor().Post("newTx", tx)
// Notify the subscribers
pool.notifySubscribers(TxPre, tx)