Skip to content

Commit

Permalink
Introducing ethash
Browse files Browse the repository at this point in the history
  • Loading branch information
xcthulhu committed Mar 2, 2015
1 parent 080823b commit ef0ebde
Show file tree
Hide file tree
Showing 15 changed files with 105 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

/tmp
*/**/*un~
*/**/*.test
*un~
.DS_Store
*/**/.DS_Store
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ before_install:
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
- go get github.com/ethereum/ethash/go-ethash
install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint
Expand Down
5 changes: 3 additions & 2 deletions core/block_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"sync"
"time"

"github.com/ethereum/ethash/go-ethash"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/pow/ezp"
"github.com/ethereum/go-ethereum/state"
"gopkg.in/fatih/set.v0"
)
Expand Down Expand Up @@ -50,7 +50,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
sm := &BlockProcessor{
db: db,
mem: make(map[string]*big.Int),
Pow: ezp.New(),
Pow: ethash.New(chainManager),
bc: chainManager,
eventMux: eventMux,
txpool: txpool,
Expand Down Expand Up @@ -255,6 +255,7 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
}

// There can be at most one uncle
if len(block.Uncles()) > 1 {
return ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles()))
}
Expand Down
47 changes: 29 additions & 18 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,31 @@ import (
// So we can generate blocks easily
type FakePow struct{}

func (f FakePow) Search(block pow.Block, stop <-chan struct{}) []byte { return nil }
func (f FakePow) Verify(block pow.Block) bool { return true }
func (f FakePow) GetHashrate() int64 { return 0 }
func (f FakePow) Turbo(bool) {}
func (f FakePow) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte, []byte) {
return nil, nil, nil
}
func (f FakePow) Verify(block pow.Block) bool { return true }
func (f FakePow) GetHashrate() int64 { return 0 }
func (f FakePow) Turbo(bool) {}

// So we can deterministically seed different blockchains
var (
CanonicalSeed = 1
ForkSeed = 2
)

// Utility functions for making chains on the fly
// Exposed for sake of testing from other packages (eg. go-ethash)
func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block {
return newBlockFromParent(addr, parent)
}

func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block {
return makeBlock(bman, parent, i, db)
func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block {
return makeBlock(bman, parent, i, db, seed)
}

func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks {
return makeChain(bman, parent, max, db)
func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks {
return makeChain(bman, parent, max, db, seed)
}

func NewChainMan(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
Expand All @@ -42,16 +52,17 @@ func NewCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
return newCanonical(n, db)
}

// block time is fixed at 10 seconds
func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "")

block.SetUncles(nil)
block.SetTransactions(nil)
block.SetReceipts(nil)

header := block.Header()
header.Difficulty = CalcDifficulty(block, parent)
header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
header.Time = parent.Header().Time + 10
header.GasLimit = CalcGasLimit(parent, block)

block.Td = parent.Td
Expand All @@ -60,8 +71,10 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
}

// Actually make a block by simulating what miner would do
func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block {
// we seed chains by the first byte of the coinbase
func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database, seed int) *types.Block {
addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
addr[0] = byte(seed)
block := newBlockFromParent(addr, parent)
state := state.New(block.Root(), db)
cbase := state.GetOrNewStateObject(addr)
Expand All @@ -74,11 +87,11 @@ func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Data

// Make a chain with real blocks
// Runs ProcessWithParent to get proper state roots
func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks {
func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database, seed int) types.Blocks {
bman.bc.currentBlock = parent
blocks := make(types.Blocks, max)
for i := 0; i < max; i++ {
block := makeBlock(bman, parent, i, db)
block := makeBlock(bman, parent, i, db, seed)
td, err := bman.processWithParent(block, parent)
if err != nil {
fmt.Println("process with parent failed", err)
Expand All @@ -87,9 +100,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Da
block.Td = td
blocks[i] = block
parent = block
fmt.Printf("New Block: %x\n", block.Hash())
}
fmt.Println("Done making chain")
return blocks
}

Expand All @@ -113,7 +124,7 @@ func newBlockProcessor(db ethutil.Database, txpool *TxPool, cman *ChainManager,
return bman
}

// Make a new canonical chain by running InsertChain
// Make a new, deterministic canonical chain by running InsertChain
// on result of makeChain
func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
eventMux := &event.TypeMux{}
Expand All @@ -125,7 +136,7 @@ func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
if n == 0 {
return bman, nil
}
lchain := makeChain(bman, parent, n, db)
bman.bc.InsertChain(lchain)
return bman, nil
lchain := makeChain(bman, parent, n, db, CanonicalSeed)
err := bman.bc.InsertChain(lchain)
return bman, err
}
46 changes: 31 additions & 15 deletions core/chain_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ func init() {

// Test fork of length N starting from block i
func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
fmt.Println("Testing Fork!")
var b *types.Block = nil
if i > 0 {
b = bman.bc.GetBlockByNumber(uint64(i))
}
_ = b
// switch databases to process the new chain
db, err := ethdb.NewMemDatabase()
if err != nil {
Expand All @@ -40,13 +34,25 @@ func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big
if err != nil {
t.Fatal("could not make new canonical in testFork", err)
}
// asert the bmans have the same block at i
bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash()
bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash()
if bytes.Compare(bi1, bi2) != 0 {
t.Fatal("chains do not have the same hash at height", i)
}

bman2.bc.SetProcessor(bman2)

// extend the fork
parent := bman2.bc.CurrentBlock()
chainB := makeChain(bman2, parent, N, db)
bman2.bc.InsertChain(chainB)
chainB := makeChain(bman2, parent, N, db, ForkSeed)
err = bman2.bc.InsertChain(chainB)
if err != nil {
t.Fatal("Insert chain error for fork:", err)
}

tdpre := bman.bc.Td()
// Test the fork's blocks on the original chain
td, err := testChain(chainB, bman)
if err != nil {
t.Fatal("expected chainB not to give errors:", err)
Expand All @@ -55,6 +61,14 @@ func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big
f(tdpre, td)
}

func printChain(bc *ChainManager) {
for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- {
b := bc.GetBlockByNumber(uint64(i))
fmt.Printf("\t%x\n", b.Hash())
}
}

// process blocks against a chain
func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
td := new(big.Int)
for _, block := range chainB {
Expand Down Expand Up @@ -102,12 +116,13 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
}

func TestExtendCanonical(t *testing.T) {
CanonicalLength := 5
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
// make first chain starting from genesis
bman, err := newCanonical(5, db)
bman, err := newCanonical(CanonicalLength, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
Expand All @@ -116,11 +131,11 @@ func TestExtendCanonical(t *testing.T) {
t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
}
}
// Start fork from current height (5)
testFork(t, bman, 5, 1, f)
testFork(t, bman, 5, 2, f)
testFork(t, bman, 5, 5, f)
testFork(t, bman, 5, 10, f)
// Start fork from current height (CanonicalLength)
testFork(t, bman, CanonicalLength, 1, f)
testFork(t, bman, CanonicalLength, 2, f)
testFork(t, bman, CanonicalLength, 5, f)
testFork(t, bman, CanonicalLength, 10, f)
}

func TestShorterFork(t *testing.T) {
Expand Down Expand Up @@ -189,6 +204,7 @@ func TestEqualFork(t *testing.T) {
}
// Sum of numbers must be equal to 10
// for this to be an equal fork
testFork(t, bman, 0, 10, f)
testFork(t, bman, 1, 9, f)
testFork(t, bman, 2, 8, f)
testFork(t, bman, 5, 5, f)
Expand All @@ -215,7 +231,7 @@ func TestBrokenChain(t *testing.T) {
}
bman2.bc.SetProcessor(bman2)
parent := bman2.bc.CurrentBlock()
chainB := makeChain(bman2, parent, 5, db2)
chainB := makeChain(bman2, parent, 5, db2, ForkSeed)
chainB = chainB[1:]
_, err = testChain(chainB, bman)
if err == nil {
Expand Down
2 changes: 1 addition & 1 deletion core/transaction_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (self *TxPool) add(tx *types.Transaction) error {
if len(tx.From()) > 0 {
from = ethutil.Bytes2Hex(tx.From()[:4])
} else {
from = "INVALID"
return errors.New(fmt.Sprintf("FROM ADDRESS MUST BE POSITIVE (was %v)", tx.From()))
}
txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash())

Expand Down
15 changes: 14 additions & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,20 @@ type Header struct {
}

func (self *Header) rlpData(withNonce bool) []interface{} {
fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra}
fields := []interface{}{
self.ParentHash,
self.UncleHash,
self.Coinbase,
self.Root,
self.TxHash,
self.ReceiptHash,
self.Bloom,
self.Difficulty,
self.Number,
self.GasLimit,
self.GasUsed,
self.Time,
self.Extra}
if withNonce {
fields = append(fields, self.Nonce, self.MixDigest, self.SeedHash)
}
Expand Down
4 changes: 2 additions & 2 deletions miner/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ done:

func (self *CpuMiner) mine(block *types.Block) {
minerlogger.Infof("(re)started agent[%d]. mining...\n", self.index)
nonce := self.pow.Search(block, self.quitCurrentOp)
nonce, mixDigest, seedHash := self.pow.Search(block, self.quitCurrentOp)
if nonce != nil {
self.returnCh <- Work{block.Number().Uint64(), nonce}
self.returnCh <- Work{block.Number().Uint64(), nonce, mixDigest, seedHash}
}
}
9 changes: 7 additions & 2 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ func env(block *types.Block, eth core.Backend) *environment {
}

type Work struct {
Number uint64
Nonce []byte
Number uint64
Nonce []byte
MixDigest []byte
SeedHash []byte
}

type Agent interface {
Expand Down Expand Up @@ -138,9 +140,12 @@ out:
func (self *worker) wait() {
for {
for work := range self.recv {
// Someone Successfully Mined!
block := self.current.block
if block.Number().Uint64() == work.Number && block.Nonce() == nil {
self.current.block.Header().Nonce = work.Nonce
self.current.block.Header().MixDigest = work.MixDigest
self.current.block.Header().SeedHash = work.SeedHash

if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
self.mux.Post(core.NewMinedBlockEvent{self.current.block})
Expand Down
12 changes: 10 additions & 2 deletions pow/block.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package pow

import "math/big"
import (
"github.com/ethereum/go-ethereum/core/types"
"math/big"
)

type Block interface {
Difficulty() *big.Int
HashNoNonce() []byte
Nonce() []byte
Number() *big.Int
MixDigest() []byte
SeedHash() []byte
NumberU64() uint64
}

type ChainManager interface {
GetBlockByNumber(uint64) *types.Block
CurrentBlock() *types.Block
}
4 changes: 2 additions & 2 deletions pow/dagger/dagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
resChan <- 0
}

func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
func (dag *Dagger) Search(hash, diff *big.Int) ([]byte, []byte, []byte) {
// TODO fix multi threading. Somehow it results in the wrong nonce
amountOfRoutines := 1

Expand All @@ -69,7 +69,7 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
}
}

return big.NewInt(res)
return big.NewInt(res).Bytes(), nil, nil
}

func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool {
Expand Down
5 changes: 0 additions & 5 deletions pow/dash/crypto.c

This file was deleted.

14 changes: 0 additions & 14 deletions pow/dash/crypto.go

This file was deleted.

Loading

0 comments on commit ef0ebde

Please sign in to comment.