generateDataset¶
| Source (upstream pre-purge) | Current | |
|---|---|---|
| File | consensus/ethash/algorithm.go |
algorithm.go |
| Symbol | generateDataset |
generateDataset |
| Ref | dde2da0ef~1 |
etc/v1.17.3-full-node |
ECIP-1099 epoch params + ADAPT:
reflect.SliceHeader→unsafe.Slice(#29067) — see generateCache
3-way merge — purge → getc ← upstream¶
pre-purgecore-geth
↗// generateDataset generates the entire ethash dataset for mining.
// This method places the result into dest in machine byte order.
↗func generateDataset(dest []uint32, epoch uint64, epochLength uint64, cache []uint32) {
↗ // Print some debug logs to allow analysis on low end devices
logger := log.New("epoch", epoch)
↗ start := time.Now()
defer func() {
elapsed := time.Since(start)
↗ logFn := logger.Debug
if elapsed > 3*time.Second {
logFn = logger.Info
}
↗ logFn("Generated ethash verification dataset", "epochLength", epochLength, "elapsed", common.PrettyDuration(elapsed))
↗ }()
↗ // Figure out whether the bytes need to be swapped for the machine
swapped := !isLittleEndian()
↗ // Convert our destination slice to a byte buffer
↗ dataset := unsafe.Slice((*byte)(unsafe.Pointer(&dest[0])), len(dest)*4)
↗ // Generate the dataset on many goroutines since it takes a while
threads := runtime.NumCPU()
size := uint64(len(dataset))
↗ var pend sync.WaitGroup
pend.Add(threads)
↗ var progress atomic.Uint64
for i := 0; i < threads; i++ {
go func(id int) {
defer pend.Done()
↗ // Create a hasher to reuse between invocations
keccak512 := makeHasher(sha3.NewLegacyKeccak512())
↗ // Calculate the data segment this thread should generate
batch := (size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads))
first := uint64(id) * batch
limit := first + batch
if limit > size/hashBytes {
limit = size / hashBytes
}
// Calculate the dataset segment
percent := size / hashBytes / 100
for index := first; index < limit; index++ {
item := generateDatasetItem(cache, uint32(index), keccak512)
if swapped {
swap(item)
}
copy(dataset[index*hashBytes:], item)
↗ if status := progress.Add(1); status%percent == 0 {
↗ logger.Info("Generating DAG in progress", "epochLength", epochLength, "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
↗ }
}
}(i)
}
// Wait for all the generators to finish and return
pend.Wait()
}