pow: make data dumps backwards compatible, fix DAG end

This commit is contained in:
Péter Szilágyi 2017-03-09 16:09:43 +02:00 committed by Felix Lange
parent 5c8fa6ae1a
commit f3579f6460
2 changed files with 32 additions and 21 deletions

@ -32,12 +32,12 @@ import (
"unsafe"
mmap "github.com/edsrzf/mmap-go"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
metrics "github.com/rcrowley/go-metrics"
)
var (
ErrInvalidDumpMagic = errors.New("invalid dump magic")
ErrNonceOutOfRange = errors.New("nonce out of range")
ErrInvalidDifficulty = errors.New("non-positive difficulty")
ErrInvalidMixDigest = errors.New("invalid mix digest")
@ -55,7 +55,7 @@ var (
algorithmRevision = 23
// dumpMagic is a dataset dump header to sanity check a data dump.
dumpMagic = hexutil.MustDecode("0xfee1deadbaddcafe")
dumpMagic = []uint32{0xbaddcafe, 0xfee1dead}
)
// isLittleEndian returns whether the local system is running in little or big
@ -76,7 +76,14 @@ func memoryMap(path string) (*os.File, mmap.MMap, []uint32, error) {
file.Close()
return nil, nil, nil, err
}
return file, mem, buffer, err
for i, magic := range dumpMagic {
if buffer[i] != magic {
mem.Unmap()
file.Close()
return nil, nil, nil, ErrInvalidDumpMagic
}
}
return file, mem, buffer[len(dumpMagic):], err
}
// memoryMapFile tries to memory map an already opened file descriptor.
@ -113,7 +120,7 @@ func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint
if err != nil {
return nil, nil, nil, err
}
if err = dump.Truncate(int64(size)); err != nil {
if err = dump.Truncate(int64(len(dumpMagic))*4 + int64(size)); err != nil {
return nil, nil, nil, err
}
// Memory map the file for writing and fill it with the generator
@ -122,7 +129,10 @@ func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint
dump.Close()
return nil, nil, nil, err
}
generator(buffer)
copy(buffer, dumpMagic)
data := buffer[len(dumpMagic):]
generator(data)
if err := mem.Flush(); err != nil {
mem.Unmap()
@ -130,7 +140,7 @@ func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint
return nil, nil, nil, err
}
os.Rename(temp, path)
return dump, mem, buffer, nil
return dump, mem, data, nil
}
// cache wraps an ethash cache with some metadata to allow easier concurrent use.
@ -165,11 +175,11 @@ func (c *cache) generate(dir string, limit int, test bool) {
return
}
// Disk storage is needed, this will get fancy
endian := "le"
var endian string
if !isLittleEndian() {
endian = "be"
endian = ".be"
}
path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x.%s", algorithmRevision, seed, endian))
path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
logger := log.New("epoch", c.epoch)
// Try to load the file from disk and memory map it
@ -192,7 +202,7 @@ func (c *cache) generate(dir string, limit int, test bool) {
// Iterate over all previous instances and delete old ones
for ep := int(c.epoch) - limit; ep >= 0; ep-- {
seed := seedHash(uint64(ep)*epochLength + 1)
path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x.%s", algorithmRevision, seed, endian))
path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
os.Remove(path)
}
})
@ -249,11 +259,11 @@ func (d *dataset) generate(dir string, limit int, test bool) {
generateDataset(d.dataset, d.epoch, cache)
}
// Disk storage is needed, this will get fancy
endian := "le"
var endian string
if !isLittleEndian() {
endian = "be"
endian = ".be"
}
path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x.%s", algorithmRevision, seed, endian))
path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
logger := log.New("epoch", d.epoch)
// Try to load the file from disk and memory map it
@ -279,7 +289,7 @@ func (d *dataset) generate(dir string, limit int, test bool) {
// Iterate over all previous instances and delete old ones
for ep := int(d.epoch) - limit; ep >= 0; ep-- {
seed := seedHash(uint64(ep)*epochLength + 1)
path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x.%s", algorithmRevision, seed, endian))
path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
os.Remove(path)
}
})

@ -225,7 +225,8 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
// Print some debug logs to allow analysis on low end devices
logger := log.New("epoch", epoch)
defer func(start time.Time) {
start := time.Now()
defer func() {
elapsed := time.Since(start)
logFn := logger.Debug
@ -233,7 +234,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
logFn = logger.Info
}
logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed))
}(time.Now())
}()
// Figure out whether the bytes need to be swapped for the machine
swapped := !isLittleEndian()
@ -260,15 +261,15 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
keccak512 := makeHasher(sha3.NewKeccak512())
// Calculate the data segment this thread should generate
batch := uint32(size / hashBytes / uint64(threads))
start := uint32(id) * batch
limit := start + batch
batch := uint32((size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads)))
first := uint32(id) * batch
limit := first + batch
if limit > uint32(size/hashBytes) {
limit = uint32(size / hashBytes)
}
// Calculate the dataset segment
percent := uint32(size / hashBytes / 100)
for index := start; index < limit; index++ {
for index := first; index < limit; index++ {
item := generateDatasetItem(cache, index, keccak512)
if swapped {
swap(item)
@ -276,7 +277,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
copy(dataset[index*hashBytes:], item)
if status := atomic.AddUint32(&progress, 1); status%percent == 0 {
logger.Info("Generating DAG in progress", "percentage", uint64(status*100)/(size/hashBytes))
logger.Info("Generating DAG in progress", "percentage", uint64(status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
}
}
}(i)