mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
Introducing ethash
This commit is contained in:
parent
080823bdee
commit
ef0ebde4f5
15 changed files with 105 additions and 70 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
/tmp
|
||||
*/**/*un~
|
||||
*/**/*.test
|
||||
*un~
|
||||
.DS_Store
|
||||
*/**/.DS_Store
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
@ -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,
|
||||
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) 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 {
|
||||
|
|
@ -42,9 +52,9 @@ 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)
|
||||
|
|
@ -52,6 +62,7 @@ func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
|
|||
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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -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{}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ func env(block *types.Block, eth core.Backend) *environment {
|
|||
type Work struct {
|
||||
Number uint64
|
||||
Nonce []byte
|
||||
MixDigest []byte
|
||||
SeedHash []byte
|
||||
}
|
||||
|
||||
type Agent interface {
|
||||
|
|
@ -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})
|
||||
|
|
|
|||
12
pow/block.go
12
pow/block.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
extern char *Sha3(char *, int);
|
||||
char *sha3_cgo(char *data, int l)
|
||||
{
|
||||
return Sha3(data, l);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package dash
|
||||
|
||||
/*
|
||||
char *sha3_cgo(char *, int); // Forward declaration
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
//export Sha3
|
||||
func Sha3(data []byte, l int) []byte {
|
||||
return crypto.Sha3(data)
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ func (pow *EasyPow) Turbo(on bool) {
|
|||
pow.turbo = on
|
||||
}
|
||||
|
||||
func (pow *EasyPow) Search(block pow.Block, stop <-chan struct{}) []byte {
|
||||
func (pow *EasyPow) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte, []byte) {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
hash := block.HashNoNonce()
|
||||
diff := block.Difficulty()
|
||||
|
|
@ -57,7 +57,7 @@ empty:
|
|||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
return nil, nil, nil
|
||||
default:
|
||||
i++
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ empty:
|
|||
|
||||
sha := crypto.Sha3(big.NewInt(r.Int63()).Bytes())
|
||||
if verify(hash, diff, sha) {
|
||||
return sha
|
||||
return sha, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,8 +75,6 @@ empty:
|
|||
time.Sleep(20 * time.Microsecond)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pow *EasyPow) Verify(block pow.Block) bool {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package pow
|
||||
|
||||
type PoW interface {
|
||||
Search(block Block, stop <-chan struct{}) []byte
|
||||
Search(block Block, stop <-chan struct{}) ([]byte, []byte, []byte)
|
||||
Verify(block Block) bool
|
||||
GetHashrate() int64
|
||||
Turbo(bool)
|
||||
|
|
|
|||
Loading…
Reference in a new issue