aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ethchain/block.go3
-rw-r--r--ethchain/block_chain.go126
-rw-r--r--ethchain/block_chain_test.go115
-rw-r--r--ethchain/dagger.go31
-rw-r--r--ethchain/state_manager.go19
-rw-r--r--ethchain/transaction_pool.go19
-rw-r--r--ethereum.go8
-rw-r--r--ethminer/miner.go149
-rw-r--r--ethutil/rlp_test.go9
-rw-r--r--peer.go125
10 files changed, 558 insertions, 46 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..8c03eec38 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"
@@ -23,7 +24,8 @@ type BlockChain struct {
func NewBlockChain(ethereum EthManager) *BlockChain {
bc := &BlockChain{}
- bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis))
+ bc.genesisBlock = NewBlockFromBytes(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,121 @@ 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
+}
+func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool {
+ var blocks []*Block
+ for i := 0; i < (msg.Data.Len() - 1); i++ {
+ block := NewBlockFromRlpValue(msg.Data.Get(i))
+ blocks = append(blocks, block)
+ }
+ return bc.FindCanonicalChain(blocks, commonBlockHash)
+}
+
+// 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(blocks []*Block, 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 _, block := range blocks {
+ if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
+ log.Println("[CHAIN] We have found the common parent block, breaking")
+ break
+ }
+ log.Println("Checking incoming blocks:")
+ chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block))
+ }
+
+ log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty)
+
+ curChainDifficulty := new(big.Int)
+ block := bc.CurrentBlock
+ for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) {
+ i++
+ if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
+ log.Println("[CHAIN] We have found the common parent block, breaking")
+ break
+ }
+ anOtherBlock := bc.GetBlock(block.PrevHash)
+ if anOtherBlock == nil {
+ // We do not want to count the genesis block for difficulty since that's not being sent
+ log.Println("[CHAIN] At genesis block, breaking")
+ break
+ }
+ log.Printf("CHECKING OUR OWN BLOCKS: %x", block.Hash())
+ log.Printf("%x", bc.GenesisBlock().Hash())
+ curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block))
+ }
+
+ log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty)
+ if chainDifficulty.Cmp(curChainDifficulty) == 1 {
+ log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash)
+ bc.ResetTillBlockHash(commonBlockHash)
+ return false
+ } else {
+ log.Println("[CHAIN] 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 +252,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,12 +297,13 @@ 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()
encodedBlock := block.RlpEncode()
+ log.Println(encodedBlock)
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
}
@@ -196,7 +314,7 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block {
return nil
}
- return NewBlockFromData(data)
+ return NewBlockFromBytes(data)
}
func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo {
diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go
new file mode 100644
index 000000000..30eb62266
--- /dev/null
+++ b/ethchain/block_chain_test.go
@@ -0,0 +1,115 @@
+package ethchain
+
+import (
+ "fmt"
+ "github.com/ethereum/eth-go/ethdb"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/ethwire"
+ "testing"
+)
+
+// Implement our EthTest Manager
+type TestManager struct {
+ stateManager *StateManager
+ reactor *ethutil.ReactorEngine
+
+ txPool *TxPool
+ blockChain *BlockChain
+ Blocks []*Block
+}
+
+func (s *TestManager) BlockChain() *BlockChain {
+ return s.blockChain
+}
+
+func (tm *TestManager) TxPool() *TxPool {
+ return tm.txPool
+}
+
+func (tm *TestManager) StateManager() *StateManager {
+ return tm.stateManager
+}
+
+func (tm *TestManager) Reactor() *ethutil.ReactorEngine {
+ return tm.reactor
+}
+func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) {
+ fmt.Println("Broadcast not implemented")
+}
+
+func NewTestManager() *TestManager {
+ ethutil.ReadConfig(".ethtest")
+
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ fmt.Println("Could not create mem-db, failing")
+ return nil
+ }
+ ethutil.Config.Db = db
+
+ testManager := &TestManager{}
+ testManager.reactor = ethutil.NewReactorEngine()
+
+ testManager.txPool = NewTxPool(testManager)
+ testManager.blockChain = NewBlockChain(testManager)
+ testManager.stateManager = NewStateManager(testManager)
+
+ // Start the tx pool
+ testManager.txPool.Start()
+
+ return testManager
+}
+func (tm *TestManager) AddFakeBlock(blk []byte) error {
+ block := NewBlockFromBytes(blk)
+ tm.Blocks = append(tm.Blocks, block)
+ tm.StateManager().PrepareDefault(block)
+ err := tm.StateManager().ProcessBlock(block, false)
+ return err
+}
+func (tm *TestManager) CreateChain1() error {
+ err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192})
+ err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192})
+ err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 68, 52, 33, 210, 160, 189, 217, 255, 78, 37, 196, 217, 94, 247, 166, 169, 224, 199, 102, 110, 85, 213, 45, 13, 173, 106, 4, 103, 151, 195, 38, 86, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 208, 12, 132, 83, 48, 38, 206, 128, 160, 65, 147, 32, 128, 177, 198, 131, 57, 57, 68, 135, 65, 198, 178, 138, 43, 25, 135, 92, 174, 208, 119, 103, 225, 26, 207, 243, 31, 225, 29, 173, 119, 192, 192})
+ return err
+}
+func (tm *TestManager) CreateChain2() error {
+ err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 40, 35, 128, 160, 162, 214, 119, 207, 212, 186, 64, 47, 14, 186, 98, 118, 203, 79, 172, 205, 33, 206, 225, 177, 225, 194, 98, 188, 63, 219, 13, 151, 47, 32, 204, 27, 192, 192})
+ err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 0, 210, 76, 6, 13, 18, 219, 190, 18, 250, 23, 178, 198, 117, 254, 85, 14, 74, 104, 116, 56, 144, 116, 172, 14, 3, 236, 99, 248, 228, 142, 91, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 255, 252, 132, 83, 48, 40, 74, 128, 160, 185, 20, 138, 2, 210, 15, 71, 144, 89, 167, 94, 155, 148, 118, 170, 157, 122, 70, 70, 114, 50, 221, 231, 8, 132, 167, 115, 239, 44, 245, 41, 226, 192, 192})
+ return err
+}
+
+func TestNegativeBlockChainReorg(t *testing.T) {
+ // We are resetting the database between creation so we need to cache our information
+ testManager2 := NewTestManager()
+ testManager2.CreateChain2()
+ tm2Blocks := testManager2.Blocks
+
+ testManager := NewTestManager()
+ testManager.CreateChain1()
+ oldState := testManager.BlockChain().CurrentBlock.State()
+
+ if testManager.BlockChain().FindCanonicalChain(tm2Blocks, testManager.BlockChain().GenesisBlock().Hash()) != true {
+ t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.")
+ }
+ if testManager.BlockChain().CurrentBlock.State() != oldState {
+ t.Error("I expected the top state to be the same as it was as before the reorg")
+ }
+
+}
+
+func TestPositiveBlockChainReorg(t *testing.T) {
+ testManager := NewTestManager()
+ testManager.CreateChain1()
+ tm1Blocks := testManager.Blocks
+
+ testManager2 := NewTestManager()
+ testManager2.CreateChain2()
+ oldState := testManager2.BlockChain().CurrentBlock.State()
+
+ if testManager2.BlockChain().FindCanonicalChain(tm1Blocks, testManager.BlockChain().GenesisBlock().Hash()) == true {
+ t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.")
+ }
+ if testManager2.BlockChain().CurrentBlock.State() == oldState {
+ t.Error("I expected the top state to have been modified but it was not")
+ }
+}
diff --git a/ethchain/dagger.go b/ethchain/dagger.go
index 5b4f8b2cd..9d2df4069 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("[POW] 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 d9831d49f..78fcb2c2f 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
}
@@ -139,7 +137,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()
@@ -148,10 +146,10 @@ 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) {
+ fmt.Println("[SM] We already have this block, ignoring")
return nil
}
@@ -166,12 +164,14 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
// Block validation
if err := sm.ValidateBlock(block); err != nil {
+ fmt.Println("[SM] Error validating block:", err)
return err
}
// I'm not sure, but I don't know if there should be thrown
// any errors at this time.
if err := sm.AccumelateRewards(block); err != nil {
+ fmt.Println("[SM] Error accumulating reward", err)
return err
}
@@ -198,13 +198,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 {
@@ -275,12 +277,15 @@ func CalculateUncleReward(block *Block) *big.Int {
}
func (sm *StateManager) AccumelateRewards(block *Block) error {
+
// Get the coinbase rlp data
addr := sm.procState.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
- 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)
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
index 4a4f2e809..9acd39e31 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)
diff --git a/ethereum.go b/ethereum.go
index fb97c34b1..c906a6954 100644
--- a/ethereum.go
+++ b/ethereum.go
@@ -60,6 +60,8 @@ type Ethereum struct {
// Specifies the desired amount of maximum peers
MaxPeers int
+
+ reactor *ethutil.ReactorEngine
}
func New(caps Caps, usePnp bool) (*Ethereum, error) {
@@ -89,6 +91,8 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
serverCaps: caps,
nat: nat,
}
+ ethereum.reactor = ethutil.NewReactorEngine()
+
ethereum.txPool = ethchain.NewTxPool(ethereum)
ethereum.blockChain = ethchain.NewBlockChain(ethereum)
ethereum.stateManager = ethchain.NewStateManager(ethereum)
@@ -99,6 +103,10 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
return ethereum, nil
}
+func (s *Ethereum) Reactor() *ethutil.ReactorEngine {
+ return s.reactor
+}
+
func (s *Ethereum) BlockChain() *ethchain.BlockChain {
return s.blockChain
}
diff --git a/ethminer/miner.go b/ethminer/miner.go
new file mode 100644
index 000000000..125eb6fb1
--- /dev/null
+++ b/ethminer/miner.go
@@ -0,0 +1,149 @@
+package ethminer
+
+import (
+ "bytes"
+ "github.com/ethereum/eth-go/ethchain"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/ethwire"
+ "log"
+)
+
+type Miner struct {
+ pow ethchain.PoW
+ ethereum ethchain.EthManager
+ coinbase []byte
+ reactChan chan ethutil.React
+ txs []*ethchain.Transaction
+ uncles []*ethchain.Block
+ block *ethchain.Block
+ powChan chan []byte
+ quitChan chan ethutil.React
+}
+
+func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
+ reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
+ powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
+ quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
+
+ ethereum.Reactor().Subscribe("newBlock", reactChan)
+ ethereum.Reactor().Subscribe("newTx", reactChan)
+
+ // We need the quit chan to be a Reactor event.
+ // The POW search method is actually blocking and if we don't
+ // listen to the reactor events inside of the pow itself
+ // The miner overseer will never get the reactor events themselves
+ // Only after the miner will find the sha
+ ethereum.Reactor().Subscribe("newBlock", quitChan)
+ ethereum.Reactor().Subscribe("newTx", quitChan)
+
+ miner := Miner{
+ pow: &ethchain.EasyPow{},
+ ethereum: ethereum,
+ coinbase: coinbase,
+ reactChan: reactChan,
+ powChan: powChan,
+ quitChan: quitChan,
+ }
+
+ // Insert initial TXs in our little miner 'pool'
+ miner.txs = ethereum.TxPool().Flush()
+ miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+
+ return miner
+}
+func (miner *Miner) Start() {
+ // Prepare inital block
+ miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
+ go func() { miner.listener() }()
+}
+func (miner *Miner) listener() {
+ for {
+ select {
+ case chanMessage := <-miner.reactChan:
+ if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
+ log.Println("[MINER] Got new block via Reactor")
+ if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
+ // TODO: Perhaps continue mining to get some uncle rewards
+ log.Println("[MINER] New top block found resetting state")
+
+ // Filter out which Transactions we have that were not in this block
+ var newtxs []*ethchain.Transaction
+ for _, tx := range miner.txs {
+ found := false
+ for _, othertx := range block.Transactions() {
+ if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
+ found = true
+ }
+ }
+ if found == false {
+ newtxs = append(newtxs, tx)
+ }
+ }
+ miner.txs = newtxs
+
+ // Setup a fresh state to mine on
+ miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+
+ } else {
+ if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
+ log.Println("[MINER] Adding uncle block")
+ miner.uncles = append(miner.uncles, block)
+ miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
+ }
+ }
+ }
+
+ if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
+ log.Println("[MINER] Got new transaction from Reactor", tx)
+ found := false
+ for _, ctx := range miner.txs {
+ if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
+ break
+ }
+
+ }
+ if found == false {
+ log.Println("[MINER] We did not know about this transaction, adding")
+ miner.txs = append(miner.txs, tx)
+ miner.block.SetTransactions(miner.txs)
+ } else {
+ log.Println("[MINER] We already had this transaction, ignoring")
+ }
+ }
+ default:
+ log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions")
+
+ // Apply uncles
+ if len(miner.uncles) > 0 {
+ miner.block.SetUncles(miner.uncles)
+ }
+
+ // Apply all transactions to the block
+ miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions())
+ miner.ethereum.StateManager().AccumelateRewards(miner.block)
+
+ // Search the nonce
+ log.Println("[MINER] Initialision complete, starting mining")
+ miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
+ if miner.block.Nonce != nil {
+ miner.ethereum.StateManager().PrepareDefault(miner.block)
+ err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
+ if err != nil {
+ log.Println("Error result from process block:", err)
+ log.Println(miner.block)
+ } else {
+
+ if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
+ log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
+ }
+ miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
+ log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash())
+ log.Println(miner.block)
+
+ miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
+ miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+ }
+ }
+ }
+ }
+}
diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go
index dc10db632..9e8127aab 100644
--- a/ethutil/rlp_test.go
+++ b/ethutil/rlp_test.go
@@ -56,6 +56,15 @@ func TestValue(t *testing.T) {
}
}
+func TestEncodeDecodeMaran(t *testing.T) {
+ b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"})
+ a := b.Encode()
+ fmt.Println("voor maran", a)
+ f, i := Decode(a, 0)
+ fmt.Println("voor maran 2", f)
+ fmt.Println(i)
+}
+
func TestEncode(t *testing.T) {
strRes := "\x83dog"
bytes := Encode("dog")
diff --git a/peer.go b/peer.go
index 279b0bc7f..f2267c29b 100644
--- a/peer.go
+++ b/peer.go
@@ -125,7 +125,8 @@ type Peer struct {
pubkey []byte
// Indicated whether the node is catching up or not
- catchingUp bool
+ catchingUp bool
+ blocksRequested int
Version string
}
@@ -135,15 +136,16 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer {
pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes()
return &Peer{
- outputQueue: make(chan *ethwire.Msg, outputBufferSize),
- quit: make(chan bool),
- ethereum: ethereum,
- conn: conn,
- inbound: inbound,
- disconnect: 0,
- connected: 1,
- port: 30303,
- pubkey: pubkey,
+ outputQueue: make(chan *ethwire.Msg, outputBufferSize),
+ quit: make(chan bool),
+ ethereum: ethereum,
+ conn: conn,
+ inbound: inbound,
+ disconnect: 0,
+ connected: 1,
+ port: 30303,
+ pubkey: pubkey,
+ blocksRequested: 10,
}
}
@@ -290,11 +292,71 @@ func (p *Peer) HandleInbound() {
// Get all blocks and process them
var block, lastBlock *ethchain.Block
var err error
+
+ // 1. Compare the first block over the wire's prev-hash with the hash of your last block
+ // 2. If these two values are the same you can just link the chains together.
+ // [1:0,2:1,3:2] <- Current blocks (format block:previous_block)
+ // [1:0,2:1,3:2,4:3,5:4] <- incoming blocks
+ // == [1,2,3,4,5]
+ // 3. If the values are not the same we will have to go back and calculate the chain with the highest total difficulty
+ // [1:0,2:1,3:2,11:3,12:11,13:12]
+ // [1:0,2:1,3:2,4:3,5:4,6:5]
+
+ // [3:2,11:3,12:11,13:12]
+ // [3:2,4:3,5:4,6:5]
+ // Heb ik dit blok?
+ // Nee: heb ik een blok met PrevHash 3?
+ // Ja: DIVERSION
+ // Nee; Adding to chain
+
+ // See if we can find a common ancestor
+ // 1. Get the earliest block in the package.
+ // 2. Do we have this block?
+ // 3. Yes: Let's continue what we are doing
+ // 4. No: Let's request more blocks back.
+
+ // Make sure we are actually receiving anything
+ if msg.Data.Len()-1 > 1 && p.catchingUp {
+ // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find
+ // common ground to start syncing from
+ lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1))
+ if p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) {
+ fmt.Println("[PEER] We found a common ancestor, let's continue.")
+ } else {
+
+ // If we can't find a common ancenstor we need to request more blocks.
+ // FIXME: At one point this won't scale anymore since we are not asking for an offset
+ // we just keep increasing the amount of blocks.
+ fmt.Println("[PEER] No common ancestor found, requesting more blocks.")
+ p.blocksRequested = p.blocksRequested * 2
+ p.catchingUp = false
+ p.SyncWithBlocks()
+ }
+
+ for i := msg.Data.Len() - 1; i >= 0; i-- {
+ block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
+ // Do we have this block on our chain? If so we can continue
+ if p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) {
+ fmt.Println("[PEER] Block found, checking next one.")
+ } else {
+ // We don't have this block, but we do have a block with the same prevHash, diversion time!
+ if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) {
+ fmt.Printf("[PEER] Local and foreign chain have diverted after %x, we are going to get freaky with it!\n", block.PrevHash)
+ if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) {
+ return
+ }
+ } else {
+ fmt.Println("[PEER] Both local and foreign chain have same parent. Continue normally")
+ }
+ }
+ }
+ }
+
for i := msg.Data.Len() - 1; i >= 0; i-- {
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
p.ethereum.StateManager().PrepareDefault(block)
- err = p.ethereum.StateManager().ProcessBlock(block)
+ err = p.ethereum.StateManager().ProcessBlock(block, false)
if err != nil {
if ethutil.Config.Debug {
@@ -313,7 +375,7 @@ func (p *Peer) HandleInbound() {
if ethchain.IsParentErr(err) {
ethutil.Config.Log.Infoln("Attempting to catch up")
p.catchingUp = false
- p.CatchupWithPeer()
+ p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
} else if ethchain.IsValidationErr(err) {
// TODO
}
@@ -326,7 +388,7 @@ func (p *Peer) HandleInbound() {
ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash)
}
p.catchingUp = false
- p.CatchupWithPeer()
+ p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
}
}
case ethwire.MsgTxTy:
@@ -374,11 +436,11 @@ func (p *Peer) HandleInbound() {
// Amount of parents in the canonical chain
//amountOfBlocks := msg.Data.Get(l).AsUint()
amountOfBlocks := uint64(100)
+
// Check each SHA block hash from the message and determine whether
// the SHA is in the database
for i := 0; i < l; i++ {
- if data :=
- msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) {
+ if data := msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) {
parent = p.ethereum.BlockChain().GetBlock(data)
break
}
@@ -386,9 +448,12 @@ func (p *Peer) HandleInbound() {
// If a parent is found send back a reply
if parent != nil {
+ ethutil.Config.Log.Infof("[PEER] Found conical block, returning chain from: %x ", parent.Hash())
chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks)
+ ethutil.Config.Log.Infof("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash())
p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain))
} else {
+ ethutil.Config.Log.Infof("[PEER] Could not find a similar block")
// If no blocks are found we send back a reply with msg not in chain
// and the last hash from get chain
lastHash := msg.Data.Get(l - 1)
@@ -537,7 +602,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
}
// Catch up with the connected peer
- p.CatchupWithPeer()
+ // p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
+ p.SyncWithBlocks()
// Set the peer's caps
p.caps = Caps(c.Get(3).Byte())
@@ -564,11 +630,34 @@ func (p *Peer) String() string {
return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps)
}
+func (p *Peer) SyncWithBlocks() {
+ if !p.catchingUp {
+ p.catchingUp = true
+ // FIXME: THIS SHOULD NOT BE NEEDED
+ if p.blocksRequested == 0 {
+ p.blocksRequested = 10
+ }
+ fmt.Printf("Currenb lock %x\n", p.ethereum.BlockChain().CurrentBlock.Hash())
+ fmt.Println("Amount:", p.blocksRequested)
+ blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested)
+
+ var hashes []interface{}
+ for _, block := range blocks {
+ hashes = append(hashes, block.Hash())
+ }
+ fmt.Printf("Requesting hashes from network: %x", hashes)
+
+ msgInfo := append(hashes, uint64(50))
+
+ msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo)
+ p.QueueMessage(msg)
+ }
+}
-func (p *Peer) CatchupWithPeer() {
+func (p *Peer) CatchupWithPeer(blockHash []byte) {
if !p.catchingUp {
p.catchingUp = true
- msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockChain().CurrentBlock.Hash(), uint64(50)})
+ msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)})
p.QueueMessage(msg)
ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4])