cmd, consensus, eth: split ethash related config to it own (#15520)

* cmd, consensus, eth: split ethash related config to it own

* eth, consensus: minor polish

* eth, consenus, console: compress pow testing config field to single one

* consensus, eth: document pow mode
This commit is contained in:
gary rong
2017-11-24 22:10:27 +08:00
committed by Péter Szilágyi
parent b0056f5bd0
commit f14047dae5
10 changed files with 154 additions and 129 deletions

View File

@ -703,8 +703,7 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
go func(idx int) {
defer pend.Done()
ethash := New(cachedir, 0, 1, "", 0, 0)
ethash := New(Config{cachedir, 0, 1, "", 0, 0, ModeNormal})
if err := ethash.VerifySeal(nil, block.Header()); err != nil {
t.Errorf("proc %d: block verification failed: %v", idx, err)
}

View File

@ -68,7 +68,7 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) {
// stock Ethereum ethash engine.
func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
// If we're running a full engine faking, accept any input as valid
if ethash.fakeFull {
if ethash.config.PowMode == ModeFullFake {
return nil
}
// Short circuit if the header is known, or it's parent not
@ -89,7 +89,7 @@ func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.He
// a results channel to retrieve the async verifications.
func (ethash *Ethash) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
// If we're running a full engine faking, accept any input as valid
if ethash.fakeFull || len(headers) == 0 {
if ethash.config.PowMode == ModeFullFake || len(headers) == 0 {
abort, results := make(chan struct{}), make(chan error, len(headers))
for i := 0; i < len(headers); i++ {
results <- nil
@ -169,7 +169,7 @@ func (ethash *Ethash) verifyHeaderWorker(chain consensus.ChainReader, headers []
// rules of the stock Ethereum ethash engine.
func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
// If we're running a full engine faking, accept any input as valid
if ethash.fakeFull {
if ethash.config.PowMode == ModeFullFake {
return nil
}
// Verify that there are at most 2 uncles included in this block
@ -455,7 +455,7 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
// the PoW difficulty requirements.
func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
// If we're running a fake PoW, accept any seal as valid
if ethash.fakeMode {
if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake {
time.Sleep(ethash.fakeDelay)
if ethash.fakeFail == header.Number.Uint64() {
return errInvalidPoW
@ -480,7 +480,7 @@ func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Head
cache := ethash.cache(number)
size := datasetSize(number)
if ethash.tester {
if ethash.config.PowMode == ModeTest {
size = 32 * 1024
}
digest, result := hashimotoLight(size, cache, header.HashNoNonce().Bytes(), header.Nonce.Uint64())

View File

@ -45,7 +45,7 @@ var (
maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
// sharedEthash is a full instance that can be shared between multiple users.
sharedEthash = New("", 3, 0, "", 1, 0)
sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal})
// algorithmRevision is the data structure version used for file naming.
algorithmRevision = 23
@ -320,15 +320,32 @@ func MakeDataset(block uint64, dir string) {
d.release()
}
// Mode defines the type and amount of PoW verification an ethash engine makes.
type Mode uint
const (
ModeNormal Mode = iota
ModeShared
ModeTest
ModeFake
ModeFullFake
)
// Config are the configuration parameters of the ethash.
type Config struct {
CacheDir string
CachesInMem int
CachesOnDisk int
DatasetDir string
DatasetsInMem int
DatasetsOnDisk int
PowMode Mode
}
// Ethash is a consensus engine based on proot-of-work implementing the ethash
// algorithm.
type Ethash struct {
cachedir string // Data directory to store the verification caches
cachesinmem int // Number of caches to keep in memory
cachesondisk int // Number of caches to keep on disk
dagdir string // Data directory to store full mining datasets
dagsinmem int // Number of mining datasets to keep in memory
dagsondisk int // Number of mining datasets to keep on disk
config Config
caches map[uint64]*cache // In memory caches to avoid regenerating too often
fcache *cache // Pre-generated cache for the estimated future epoch
@ -342,10 +359,7 @@ type Ethash struct {
hashrate metrics.Meter // Meter tracking the average hashrate
// The fields below are hooks for testing
tester bool // Flag whether to use a smaller test dataset
shared *Ethash // Shared PoW verifier to avoid cache regeneration
fakeMode bool // Flag whether to disable PoW checking
fakeFull bool // Flag whether to disable all consensus rules
fakeFail uint64 // Block number which fails PoW check even in fake mode
fakeDelay time.Duration // Time delay to sleep for before returning from verify
@ -353,28 +367,23 @@ type Ethash struct {
}
// New creates a full sized ethash PoW scheme.
func New(cachedir string, cachesinmem, cachesondisk int, dagdir string, dagsinmem, dagsondisk int) *Ethash {
if cachesinmem <= 0 {
log.Warn("One ethash cache must always be in memory", "requested", cachesinmem)
cachesinmem = 1
func New(config Config) *Ethash {
if config.CachesInMem <= 0 {
log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem)
config.CachesInMem = 1
}
if cachedir != "" && cachesondisk > 0 {
log.Info("Disk storage enabled for ethash caches", "dir", cachedir, "count", cachesondisk)
if config.CacheDir != "" && config.CachesOnDisk > 0 {
log.Info("Disk storage enabled for ethash caches", "dir", config.CacheDir, "count", config.CachesOnDisk)
}
if dagdir != "" && dagsondisk > 0 {
log.Info("Disk storage enabled for ethash DAGs", "dir", dagdir, "count", dagsondisk)
if config.DatasetDir != "" && config.DatasetsOnDisk > 0 {
log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk)
}
return &Ethash{
cachedir: cachedir,
cachesinmem: cachesinmem,
cachesondisk: cachesondisk,
dagdir: dagdir,
dagsinmem: dagsinmem,
dagsondisk: dagsondisk,
caches: make(map[uint64]*cache),
datasets: make(map[uint64]*dataset),
update: make(chan struct{}),
hashrate: metrics.NewMeter(),
config: config,
caches: make(map[uint64]*cache),
datasets: make(map[uint64]*dataset),
update: make(chan struct{}),
hashrate: metrics.NewMeter(),
}
}
@ -382,12 +391,14 @@ func New(cachedir string, cachesinmem, cachesondisk int, dagdir string, dagsinme
// purposes.
func NewTester() *Ethash {
return &Ethash{
cachesinmem: 1,
caches: make(map[uint64]*cache),
datasets: make(map[uint64]*dataset),
tester: true,
update: make(chan struct{}),
hashrate: metrics.NewMeter(),
config: Config{
CachesInMem: 1,
PowMode: ModeTest,
},
caches: make(map[uint64]*cache),
datasets: make(map[uint64]*dataset),
update: make(chan struct{}),
hashrate: metrics.NewMeter(),
}
}
@ -395,27 +406,45 @@ func NewTester() *Ethash {
// all blocks' seal as valid, though they still have to conform to the Ethereum
// consensus rules.
func NewFaker() *Ethash {
return &Ethash{fakeMode: true}
return &Ethash{
config: Config{
PowMode: ModeFake,
},
}
}
// NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that
// accepts all blocks as valid apart from the single one specified, though they
// still have to conform to the Ethereum consensus rules.
func NewFakeFailer(fail uint64) *Ethash {
return &Ethash{fakeMode: true, fakeFail: fail}
return &Ethash{
config: Config{
PowMode: ModeFake,
},
fakeFail: fail,
}
}
// NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that
// accepts all blocks as valid, but delays verifications by some time, though
// they still have to conform to the Ethereum consensus rules.
func NewFakeDelayer(delay time.Duration) *Ethash {
return &Ethash{fakeMode: true, fakeDelay: delay}
return &Ethash{
config: Config{
PowMode: ModeFake,
},
fakeDelay: delay,
}
}
// NewFullFaker creates an ethash consensus engine with a full fake scheme that
// accepts all blocks as valid, without checking any consensus rules whatsoever.
func NewFullFaker() *Ethash {
return &Ethash{fakeMode: true, fakeFull: true}
return &Ethash{
config: Config{
PowMode: ModeFullFake,
},
}
}
// NewShared creates a full sized ethash PoW shared between all requesters running
@ -436,7 +465,7 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
current, future := ethash.caches[epoch], (*cache)(nil)
if current == nil {
// No in-memory cache, evict the oldest if the cache limit was reached
for len(ethash.caches) > 0 && len(ethash.caches) >= ethash.cachesinmem {
for len(ethash.caches) > 0 && len(ethash.caches) >= ethash.config.CachesInMem {
var evict *cache
for _, cache := range ethash.caches {
if evict == nil || evict.used.After(cache.used) {
@ -473,7 +502,7 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
ethash.lock.Unlock()
// Wait for generation finish, bump the timestamp and finalize the cache
current.generate(ethash.cachedir, ethash.cachesondisk, ethash.tester)
current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest)
current.lock.Lock()
current.used = time.Now()
@ -481,7 +510,7 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
// If we exhausted the future cache, now's a good time to regenerate it
if future != nil {
go future.generate(ethash.cachedir, ethash.cachesondisk, ethash.tester)
go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest)
}
return current.cache
}
@ -498,7 +527,7 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
current, future := ethash.datasets[epoch], (*dataset)(nil)
if current == nil {
// No in-memory dataset, evict the oldest if the dataset limit was reached
for len(ethash.datasets) > 0 && len(ethash.datasets) >= ethash.dagsinmem {
for len(ethash.datasets) > 0 && len(ethash.datasets) >= ethash.config.DatasetsInMem {
var evict *dataset
for _, dataset := range ethash.datasets {
if evict == nil || evict.used.After(dataset.used) {
@ -536,7 +565,7 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
ethash.lock.Unlock()
// Wait for generation finish, bump the timestamp and finalize the cache
current.generate(ethash.dagdir, ethash.dagsondisk, ethash.tester)
current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
current.lock.Lock()
current.used = time.Now()
@ -544,7 +573,7 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
// If we exhausted the future dataset, now's a good time to regenerate it
if future != nil {
go future.generate(ethash.dagdir, ethash.dagsondisk, ethash.tester)
go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
}
return current.dataset
}

View File

@ -34,7 +34,7 @@ import (
// the block's difficulty requirements.
func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
// If we're running a fake PoW, simply return a 0 nonce immediately
if ethash.fakeMode {
if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake {
header := block.Header()
header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
return block.WithSeal(header), nil