dataset.generate¶
| Source (upstream pre-purge) | Current | |
|---|---|---|
| File | consensus/ethash/ethash.go |
ethash.go |
| Symbol | dataset.generate |
dataset.generate |
| Ref | dde2da0ef~1 |
etc/v1.17.3-full-node |
Identical to core-geth v1.12.20. Differences vs upstream are ECIP-1099 adaptations (variable epochLength, new file naming scheme with epoch, legacy file cleanup).
3-way merge — purge → getc ← upstream¶
pre-purgecore-geth
↗// generate ensures that the dataset content is generated before use.
func (d *dataset) generate(dir string, limit int, lock bool, test bool) {
d.once.Do(func() {
// Mark the dataset generated after we're done. This is needed for remote
defer d.done.Store(true)
↗ csize := cacheSize(d.epoch)
dsize := datasetSize(d.epoch)
seed := seedHash(d.epoch, d.epochLength)
↗ if test {
csize = 1024
dsize = 32 * 1024
}
// If we don't store anything on disk, generate and return
if dir == "" {
cache := make([]uint32, csize/4)
↗ generateCache(cache, d.epoch, d.epochLength, seed)
↗ d.dataset = make([]uint32, dsize/4)
↗ generateDataset(d.dataset, d.epoch, d.epochLength, cache)
↗ return
}
// Disk storage is needed, this will get fancy
var endian string
if !isLittleEndian() {
endian = ".be"
}
↗ path := filepath.Join(dir, fmt.Sprintf("full-R%d-%d-%x%s", algorithmRevision, d.epoch, seed[:8], endian))
↗ logger := log.New("epoch", d.epoch)
↗ // We're about to mmap the file, ensure that the mapping is cleaned up when the
// cache becomes unused.
runtime.SetFinalizer(d, (*dataset).finalizer)
↗ // Try to load the file from disk and memory map it
var err error
d.dump, d.mmap, d.dataset, err = memoryMap(path, lock)
if err == nil {
↗ logger.Debug("Loaded old ethash dataset from disk", "path", path)
↗ return
}
logger.Debug("Failed to load old ethash dataset", "err", err)
↗ // No usable previous dataset available, create a new dataset file to fill
↗ cache := make([]uint32, csize/4)
↗ generateCache(cache, d.epoch, d.epochLength, seed)
↗ d.dump, d.mmap, d.dataset, err = memoryMapAndGenerate(path, dsize, lock, func(buffer []uint32) { generateDataset(buffer, d.epoch, d.epochLength, cache) })
↗ if err != nil {
logger.Error("Failed to generate mapped ethash dataset", "err", err)
↗ d.dataset = make([]uint32, dsize/4)
↗ generateDataset(d.dataset, d.epoch, d.epochLength, cache)
↗ }
↗ // Iterate over all full file instances, deleting any out of bounds (where epoch is below lower limit, or above upper limit).
matches, _ := filepath.Glob(filepath.Join(dir, fmt.Sprintf("full-R%d*", algorithmRevision)))
for _, file := range matches {
var ar int // algorithm revision
var e uint64 // epoch
var s string // seed
if _, err := fmt.Sscanf(filepath.Base(file), "full-R%d-%d-%s"+endian, &ar, &e, &s); err != nil {
// There is an unrecognized file in this directory.
// See if the name matches the expected pattern of the legacy naming scheme.
if _, err := fmt.Sscanf(filepath.Base(file), "full-R%d-%s"+endian, &ar, &s); err == nil {
// This file matches the previous generation naming pattern (sans epoch).
if err := os.Remove(file); err != nil {
logger.Error("Failed to remove legacy ethash full file", "file", file, "err", err)
} else {
logger.Warn("Deleted legacy ethash full file", "path", file)
}
}
// Else the file is unrecognized (unknown name format), leave it alone.
continue
}
if e <= d.epoch-uint64(limit) || e > d.epoch+1 {
if err := os.Remove(file); err == nil {
logger.Debug("Deleted ethash full file", "target.epoch", e, "file", file)
} else {
logger.Error("Failed to delete ethash full file", "target.epoch", e, "file", file, "err", err)
}
}
↗ }
})
}