Skip to content

generateCache

Source (upstream pre-purge) Current
File consensus/ethash/algorithm.go algorithm.go
Symbol generateCache generateCache
Ref dde2da0ef~1 etc/v1.17.3-full-node

ECIP-1099 epoch params + ADAPT: reflect.SliceHeaderunsafe.Slice (#29067)

3-way merge — purge → getc ← upstream

pre-purgecore-geth
// generateCache creates a verification cache of a given size for an input seed.
// The cache production process involves first sequentially filling up 32 MB of
// memory, then performing two passes of Sergio Demian Lerner's RandMemoHash
// algorithm from Strict Memory Hard Hashing Functions (2014). The output is a
// set of 524288 64-byte values.
// This method places the result into dest in machine byte order.
func generateCache(dest []uint32, epoch uint64, epochLength uint64, seed []byte) {
// 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 cache", "epochLength", epochLength, "elapsed", common.PrettyDuration(elapsed))
}()
// Convert our destination slice to a byte buffer
cache := unsafe.Slice((*byte)(unsafe.Pointer(&dest[0])), len(dest)*4)
// Calculate the number of theoretical rows (we'll store in one buffer nonetheless)
size := uint64(len(cache))
rows := int(size) / hashBytes
// Start a monitoring goroutine to report progress on low end devices
var progress atomic.Uint32
done := make(chan struct{})
defer close(done)
go func() {
for {
select {
case <-done:
return
case <-time.After(3 * time.Second):
logger.Info("Generating ethash verification cache", "epochLength", epochLength, "percentage", progress.Load()*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start)))
}
}
}()
// Create a hasher to reuse between invocations
keccak512 := makeHasher(sha3.NewLegacyKeccak512())
// Sequentially produce the initial dataset
keccak512(cache, seed)
for offset := uint64(hashBytes); offset < size; offset += hashBytes {
keccak512(cache[offset:], cache[offset-hashBytes:offset])
progress.Add(1)
}
// Use a low-round version of randmemohash
temp := make([]byte, hashBytes)
for i := 0; i < cacheRounds; i++ {
for j := 0; j < rows; j++ {
var (
srcOff = ((j - 1 + rows) % rows) * hashBytes
dstOff = j * hashBytes
xorOff = (binary.LittleEndian.Uint32(cache[dstOff:]) % uint32(rows)) * hashBytes
)
bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes])
keccak512(cache[dstOff:], temp)
progress.Add(1)
}
}
// Swap the byte order on big endian systems and return
if !isLittleEndian() {
swap(cache)
}
}
core-geth validation — **Identical** ✅ | | | |---|---| | File | [`algorithm.go`](https://github.com/etclabscore/core-geth/blob/v1.12.20/consensus/ethash/algorithm.go) | | Symbol | `generateCache` | | Ref | `v1.12.20` |

← Consensus & Ethash