From 567d41d9363706b4b13ce0903804e8acf214af49 Mon Sep 17 00:00:00 2001 From: Péter Szilágyi Date: Sun, 5 Mar 2017 20:00:01 +0200 Subject: all: swap out the C++ ethash to the pure Go one (mining todo) --- core/bench_test.go | 5 +++-- core/block_validator.go | 2 +- core/block_validator_test.go | 7 ++++--- core/blockchain.go | 3 +++ core/blockchain_test.go | 34 ++++++++++++++-------------------- core/chain_makers.go | 13 +------------ core/chain_makers_test.go | 3 ++- core/chain_pow.go | 2 +- core/chain_pow_test.go | 28 ++++++++++++++++------------ core/dao_test.go | 13 +++++++------ 10 files changed, 52 insertions(+), 58 deletions(-) (limited to 'core') diff --git a/core/bench_test.go b/core/bench_test.go index 8a1600557..42d50a7b1 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/pow" ) func BenchmarkInsertChain_empty_memdb(b *testing.B) { @@ -171,7 +172,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. evmux := new(event.TypeMux) - chainman, _ := NewBlockChain(db, ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux, vm.Config{}) + chainman, _ := NewBlockChain(db, ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, pow.FakePow{}, evmux, vm.Config{}) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -281,7 +282,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + chain, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator.go b/core/block_validator.go index ed5cc3ab6..f93a9f40b 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -244,7 +244,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade if checkPow { // Verify the nonce of the header. Return an error if it's not valid - if !pow.Verify(types.NewBlockWithHeader(header)) { + if err := pow.Verify(types.NewBlockWithHeader(header)); err != nil { return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()} } } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 01931efd2..c13aa83db 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/pow" ) func testChainConfig() *params.ChainConfig { @@ -40,7 +41,7 @@ func proc() (Validator, *BlockChain) { var mux event.TypeMux WriteTestNetGenesisBlock(db) - blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &mux, vm.Config{}) + blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &mux, vm.Config{}) if err != nil { fmt.Println(err) } @@ -54,13 +55,13 @@ func TestNumber(t *testing.T) { cfg := testChainConfig() header := makeHeader(cfg, chain.Genesis(), statedb) header.Number = big.NewInt(3) - err := ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false) + err := ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false) if err != BlockNumberErr { t.Errorf("expected block number error, got %q", err) } header = makeHeader(cfg, chain.Genesis(), statedb) - err = ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false) + err = ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false) if err == BlockNumberErr { t.Errorf("didn't expect block number error") } diff --git a/core/blockchain.go b/core/blockchain.go index 0c752b3f9..765a4b318 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -223,6 +223,9 @@ func (self *BlockChain) loadLastState() error { log.Info("Loaded most recent local full block", "number", self.currentBlock.Number(), "hash", self.currentBlock.Hash(), "td", blockTd) log.Info("Loaded most recent local fast block", "number", self.currentFastBlock.Number(), "hash", self.currentFastBlock.Hash(), "td", fastTd) + // Try to be smart and issue a pow verification for the head to pre-generate caches + go self.pow.Verify(types.NewBlockWithHeader(currentHeader)) + return nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 99b155620..2f06f0735 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -27,7 +27,6 @@ import ( "testing" "time" - "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -45,15 +44,10 @@ func init() { runtime.GOMAXPROCS(runtime.NumCPU()) } -func thePow() pow.PoW { - pow, _ := ethash.NewForTesting() - return pow -} - func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain { var eventMux event.TypeMux WriteTestNetGenesisBlock(db) - blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &eventMux, vm.Config{}) + blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &eventMux, vm.Config{}) if err != nil { t.Error("failed creating blockchain:", err) t.FailNow() @@ -476,7 +470,7 @@ func chm(genesis *types.Block, db ethdb.Database) *BlockChain { chainDb: db, genesisBlock: genesis, eventMux: &eventMux, - pow: FakePow{}, + pow: pow.FakePow{}, config: testChainConfig(), } valFn := func() HeaderValidator { return bc.Validator() } @@ -615,7 +609,7 @@ func testReorgBadHashes(t *testing.T, full bool) { defer func() { delete(BadHashes, headers[3].Hash()) }() } // Create a new chain manager and check it rolled back the state - ncm, err := NewBlockChain(db, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + ncm, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -736,7 +730,7 @@ func TestFastVsFullChains(t *testing.T) { archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) - archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) @@ -744,7 +738,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) - fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -820,7 +814,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) - archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) @@ -832,7 +826,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) - fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -851,7 +845,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds}) - light, _ := NewBlockChain(lightDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{}) + light, _ := NewBlockChain(lightDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) @@ -917,7 +911,7 @@ func TestChainTxReorgs(t *testing.T) { }) // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -991,7 +985,7 @@ func TestLogReorgs(t *testing.T) { ) evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { @@ -1028,7 +1022,7 @@ func TestReorgSideEvent(t *testing.T) { ) evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(chain); err != nil { @@ -1104,7 +1098,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { ) evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {}) @@ -1147,7 +1141,7 @@ func TestEIP155Transition(t *testing.T) { mux event.TypeMux ) - blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux, vm.Config{}) + blockchain, _ := NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{}) blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1251,7 +1245,7 @@ func TestEIP161AccountRemoval(t *testing.T) { } mux event.TypeMux - blockchain, _ = NewBlockChain(db, config, FakePow{}, &mux, vm.Config{}) + blockchain, _ = NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{}) ) blocks, _ := GenerateChain(config, genesis, db, 3, func(i int, block *BlockGen) { var ( diff --git a/core/chain_makers.go b/core/chain_makers.go index 8b3b015a8..f63496fdc 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -43,17 +43,6 @@ func MakeChainConfig() *params.ChainConfig { } } -// FakePow is a non-validating proof of work implementation. -// It returns true from Verify for any block. -type FakePow struct{} - -func (f FakePow) Search(block pow.Block, stop <-chan struct{}, index int) (uint64, []byte) { - return 0, 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 @@ -256,7 +245,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { // Initialize a fresh chain with only a genesis block genesis, _ := WriteTestNetGenesisBlock(db) - blockchain, _ := NewBlockChain(db, MakeChainConfig(), FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, MakeChainConfig(), pow.FakePow{}, evmux, vm.Config{}) // Create and inject the requested chain if n == 0 { return db, blockchain, nil diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 5c563de46..82751553f 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/pow" ) func ExampleGenerateChain() { @@ -82,7 +83,7 @@ func ExampleGenerateChain() { // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, chainConfig, FakePow{}, evmux, vm.Config{}) + blockchain, _ := NewBlockChain(db, chainConfig, pow.FakePow{}, evmux, vm.Config{}) if i, err := blockchain.InsertChain(chain); err != nil { fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) return diff --git a/core/chain_pow.go b/core/chain_pow.go index c3b5788c1..e5ccd87e2 100644 --- a/core/chain_pow.go +++ b/core/chain_pow.go @@ -65,7 +65,7 @@ func verifyNonces(checker pow.PoW, items []pow.Block) (chan<- struct{}, <-chan n for i := 0; i < workers; i++ { go func() { for index := range tasks { - results <- nonceCheckResult{index: index, valid: checker.Verify(items[index])} + results <- nonceCheckResult{index: index, valid: checker.Verify(items[index]) == nil} } }() } diff --git a/core/chain_pow_test.go b/core/chain_pow_test.go index 1400b166f..311ca128e 100644 --- a/core/chain_pow_test.go +++ b/core/chain_pow_test.go @@ -17,6 +17,7 @@ package core import ( + "errors" "math/big" "runtime" "testing" @@ -35,12 +36,16 @@ type failPow struct { failing uint64 } -func (pow failPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) { +func (pow failPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) { return 0, nil } -func (pow failPow) Verify(block pow.Block) bool { return block.NumberU64() != pow.failing } -func (pow failPow) GetHashrate() int64 { return 0 } -func (pow failPow) Turbo(bool) {} +func (pow failPow) Verify(block pow.Block) error { + if block.NumberU64() == pow.failing { + return errors.New("failed") + } + return nil +} +func (pow failPow) Hashrate() float64 { return 0 } // delayedPow is a non-validating proof of work implementation, that returns true // from Verify for all blocks, but delays them the configured amount of time. @@ -48,12 +53,11 @@ type delayedPow struct { delay time.Duration } -func (pow delayedPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) { +func (pow delayedPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) { return 0, nil } -func (pow delayedPow) Verify(block pow.Block) bool { time.Sleep(pow.delay); return true } -func (pow delayedPow) GetHashrate() int64 { return 0 } -func (pow delayedPow) Turbo(bool) {} +func (pow delayedPow) Verify(block pow.Block) error { time.Sleep(pow.delay); return nil } +func (pow delayedPow) Hashrate() float64 { return 0 } // Tests that simple POW verification works, for both good and bad blocks. func TestPowVerification(t *testing.T) { @@ -75,11 +79,11 @@ func TestPowVerification(t *testing.T) { switch { case full && valid: - _, results = verifyNoncesFromBlocks(FakePow{}, []*types.Block{blocks[i]}) + _, results = verifyNoncesFromBlocks(pow.FakePow{}, []*types.Block{blocks[i]}) case full && !valid: _, results = verifyNoncesFromBlocks(failPow{blocks[i].NumberU64()}, []*types.Block{blocks[i]}) case !full && valid: - _, results = verifyNoncesFromHeaders(FakePow{}, []*types.Header{headers[i]}) + _, results = verifyNoncesFromHeaders(pow.FakePow{}, []*types.Header{headers[i]}) case !full && !valid: _, results = verifyNoncesFromHeaders(failPow{headers[i].Number.Uint64()}, []*types.Header{headers[i]}) } @@ -134,11 +138,11 @@ func testPowConcurrentVerification(t *testing.T, threads int) { switch { case full && valid: - _, results = verifyNoncesFromBlocks(FakePow{}, blocks) + _, results = verifyNoncesFromBlocks(pow.FakePow{}, blocks) case full && !valid: _, results = verifyNoncesFromBlocks(failPow{uint64(len(blocks) - 1)}, blocks) case !full && valid: - _, results = verifyNoncesFromHeaders(FakePow{}, headers) + _, results = verifyNoncesFromHeaders(pow.FakePow{}, headers) case !full && !valid: _, results = verifyNoncesFromHeaders(failPow{uint64(len(headers) - 1)}, headers) } diff --git a/core/dao_test.go b/core/dao_test.go index b8b4c71cf..45b3235c7 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/pow" ) // Tests that DAO-fork enabled clients can properly filter out fork-commencing @@ -40,12 +41,12 @@ func TestDAOForkRangeExtradata(t *testing.T) { proDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(proDb) proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true} - proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux), vm.Config{}) + proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) conDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(conDb) conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false} - conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux), vm.Config{}) + conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) if _, err := proBc.InsertChain(prefix); err != nil { t.Fatalf("pro-fork: failed to import chain prefix: %v", err) @@ -58,7 +59,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain db, _ = ethdb.NewMemDatabase() WriteGenesisBlockForTesting(db) - bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux), vm.Config{}) + bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1)) for j := 0; j < len(blocks)/2; j++ { @@ -79,7 +80,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a no-fork block, and try to feed into the pro-fork chain db, _ = ethdb.NewMemDatabase() WriteGenesisBlockForTesting(db) - bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux), vm.Config{}) + bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1)) for j := 0; j < len(blocks)/2; j++ { @@ -101,7 +102,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db, _ = ethdb.NewMemDatabase() WriteGenesisBlockForTesting(db) - bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux), vm.Config{}) + bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1)) for j := 0; j < len(blocks)/2; j++ { @@ -117,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db, _ = ethdb.NewMemDatabase() WriteGenesisBlockForTesting(db) - bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux), vm.Config{}) + bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1)) for j := 0; j < len(blocks)/2; j++ { -- cgit