docs(blog): add post about the odd CPU core count bug (#1058)

* docs(blog): add post about the odd CPU core count bug

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
Xe Iaso 2025-08-28 10:32:04 -03:00 committed by GitHub
parent 9ddc1eb840
commit 21c3e0c469
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 667 additions and 0 deletions

View file

@ -0,0 +1,214 @@
import React, { useState, useEffect, useMemo } from 'react';
import styles from './styles.module.css';
// A helper function to perform SHA-256 hashing.
// It takes a string, encodes it, hashes it, and returns a hex string.
async function sha256(message) {
try {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex;
} catch (error) {
console.error("Hashing failed:", error);
return "Error hashing data";
}
}
// Generates a random hex string of a given byte length
const generateRandomHex = (bytes = 16) => {
const buffer = new Uint8Array(bytes);
crypto.getRandomValues(buffer);
return Array.from(buffer)
.map(byte => byte.toString(16).padStart(2, '0'))
.join('');
};
// Icon components for better visual feedback
const CheckIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconGreen} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
);
const XCircleIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconRed} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
);
// Main Application Component
export default function App() {
// State for the challenge, initialized with a random 16-byte hex string.
const [challenge, setChallenge] = useState(() => generateRandomHex(16));
// State for the nonce, which is the variable we can change
const [nonce, setNonce] = useState(0);
// State to store the resulting hash
const [hash, setHash] = useState('');
// A flag to indicate if the current hash is the "winning" one
const [isMining, setIsMining] = useState(false);
const [isFound, setIsFound] = useState(false);
// The mining difficulty, i.e., the required number of leading zeros
const difficulty = "00";
// Memoize the combined data to avoid recalculating on every render
const combinedData = useMemo(() => `${challenge}${nonce}`, [challenge, nonce]);
// This effect hook recalculates the hash whenever the combinedData changes.
useEffect(() => {
let isMounted = true;
const calculateHash = async () => {
const calculatedHash = await sha256(combinedData);
if (isMounted) {
setHash(calculatedHash);
setIsFound(calculatedHash.startsWith(difficulty));
}
};
calculateHash();
return () => { isMounted = false; };
}, [combinedData, difficulty]);
// This effect handles the automatic mining process
useEffect(() => {
if (!isMining) return;
let miningNonce = nonce;
let continueMining = true;
const mine = async () => {
while (continueMining) {
const currentData = `${challenge}${miningNonce}`;
const currentHash = await sha256(currentData);
if (currentHash.startsWith(difficulty)) {
setNonce(miningNonce);
setIsMining(false);
break;
}
miningNonce++;
// Update the UI periodically to avoid freezing the browser
if (miningNonce % 100 === 0) {
setNonce(miningNonce);
await new Promise(resolve => setTimeout(resolve, 0)); // Yield to the browser
}
}
};
mine();
return () => {
continueMining = false;
}
}, [isMining, challenge, nonce, difficulty]);
const handleMineClick = () => {
setIsMining(true);
}
const handleStopClick = () => {
setIsMining(false);
}
const handleResetClick = () => {
setIsMining(false);
setNonce(0);
}
const handleNewChallengeClick = () => {
setIsMining(false);
setChallenge(generateRandomHex(16));
setNonce(0);
}
// Helper to render the hash with colored leading characters
const renderHash = () => {
if (!hash) return <span>...</span>;
const prefix = hash.substring(0, difficulty.length);
const suffix = hash.substring(difficulty.length);
const prefixColor = isFound ? styles.hashPrefixGreen : styles.hashPrefixRed;
return (
<>
<span className={`${prefixColor} ${styles.hashPrefix}`}>{prefix}</span>
<span className={styles.hashSuffix}>{suffix}</span>
</>
);
};
return (
<div className={styles.container}>
<div className={styles.innerContainer}>
<div className={styles.grid}>
{/* Challenge Block */}
<div className={styles.block}>
<h2 className={styles.blockTitle}>1. Challenge</h2>
<p className={styles.challengeText}>{challenge}</p>
</div>
{/* Nonce Control Block */}
<div className={styles.block}>
<h2 className={styles.blockTitle}>2. Nonce</h2>
<div className={styles.nonceControls}>
<button onClick={() => setNonce(n => n - 1)} disabled={isMining} className={styles.nonceButton}>
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconSmall} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 12H4" /></svg>
</button>
<span className={styles.nonceValue}>{nonce}</span>
<button onClick={() => setNonce(n => n + 1)} disabled={isMining} className={styles.nonceButton}>
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconSmall} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" /></svg>
</button>
</div>
</div>
{/* Combined Data Block */}
<div className={styles.block}>
<h2 className={styles.blockTitle}>3. Combined Data</h2>
<p className={styles.combinedDataText}>{combinedData}</p>
</div>
</div>
{/* Arrow pointing down */}
<div className={styles.arrowContainer}>
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconGray} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
</div>
{/* Hash Output Block */}
<div className={`${styles.hashContainer} ${isFound ? styles.hashContainerSuccess : styles.hashContainerError}`}>
<div className={styles.hashContent}>
<div className={styles.hashText}>
<h2 className={styles.blockTitle}>4. Resulting Hash (SHA-256)</h2>
<p className={styles.hashValue}>{renderHash()}</p>
</div>
<div className={styles.hashIcon}>
{isFound ? <CheckIcon /> : <XCircleIcon />}
</div>
</div>
</div>
{/* Mining Controls */}
<div className={styles.buttonContainer}>
{!isMining ? (
<button onClick={handleMineClick} className={`${styles.button} ${styles.buttonCyan}`}>
Auto-Mine
</button>
) : (
<button onClick={handleStopClick} className={`${styles.button} ${styles.buttonYellow}`}>
Stop Mining
</button>
)}
<button onClick={handleNewChallengeClick} className={`${styles.button} ${styles.buttonIndigo}`}>
New Challenge
</button>
<button onClick={handleResetClick} className={`${styles.button} ${styles.buttonGray}`}>
Reset Nonce
</button>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,317 @@
/* Main container styles */
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
font-family: ui-sans-serif, system-ui, sans-serif;
margin-top: 2rem;
margin-bottom: 2rem;
}
.innerContainer {
width: 100%;
max-width: 56rem;
margin: 0 auto;
}
/* Header styles */
.header {
text-align: center;
margin-bottom: 2.5rem;
}
.title {
font-size: 2.25rem;
font-weight: 700;
color: rgb(34 211 238);
}
.subtitle {
font-size: 1.125rem;
color: rgb(156 163 175);
margin-top: 0.5rem;
}
/* Grid layout styles */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
align-items: center;
text-align: center;
}
/* Block styles */
.block {
background-color: rgb(31 41 55);
padding: 1.5rem;
border-radius: 0.5rem;
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}
.blockTitle {
font-size: 1.125rem;
font-weight: 600;
color: rgb(34 211 238);
margin-bottom: 0.5rem;
}
.challengeText {
font-size: 0.875rem;
color: rgb(209 213 219);
word-break: break-all;
font-family: ui-monospace, SFMono-Regular, monospace;
}
.combinedDataText {
font-size: 0.875rem;
color: rgb(156 163 175);
word-break: break-all;
font-family: ui-monospace, SFMono-Regular, monospace;
}
/* Nonce control styles */
.nonceControls {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
}
.nonceButton {
background-color: rgb(55 65 81);
border-radius: 9999px;
padding: 0.5rem;
transition: background-color 200ms;
}
.nonceButton:hover:not(:disabled) {
background-color: rgb(34 211 238);
}
.nonceButton:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.nonceValue {
font-size: 1.5rem;
font-family: ui-monospace, SFMono-Regular, monospace;
width: 6rem;
text-align: center;
}
/* Icon styles */
.icon {
height: 2rem;
width: 2rem;
}
.iconGreen {
height: 2rem;
width: 2rem;
color: rgb(74 222 128);
}
.iconRed {
height: 2rem;
width: 2rem;
color: rgb(248 113 113);
}
.iconSmall {
height: 1.5rem;
width: 1.5rem;
}
.iconGray {
height: 2.5rem;
width: 2.5rem;
color: rgb(75 85 99);
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* Arrow animation */
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.arrowContainer {
display: flex;
justify-content: center;
margin: 1.5rem 0;
}
/* Hash output styles */
.hashContainer {
padding: 1.5rem;
border-radius: 0.5rem;
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
transition: all 300ms;
border: 2px solid;
}
.hashContainerSuccess {
background-color: rgb(20 83 45 / 0.5);
border-color: rgb(74 222 128);
}
.hashContainerError {
background-color: rgb(127 29 29 / 0.5);
border-color: rgb(248 113 113);
}
.hashContent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.hashText {
text-align: center;
}
.hashTextLg {
text-align: left;
}
.hashValue {
font-size: 0.875rem;
word-break: break-all;
}
.hashValueLg {
font-size: 1rem;
word-break: break-all;
}
.hashIcon {
margin-top: 1rem;
}
.hashIconLg {
margin-top: 0;
}
/* Hash highlighting */
.hashPrefix {
font-family: ui-monospace, SFMono-Regular, monospace;
}
.hashPrefixGreen {
color: rgb(74 222 128);
}
.hashPrefixRed {
color: rgb(248 113 113);
}
.hashSuffix {
font-family: ui-monospace, SFMono-Regular, monospace;
color: rgb(156 163 175);
}
/* Button styles */
.buttonContainer {
margin-top: 2rem;
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
}
.button {
font-weight: 700;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
transition: transform 150ms;
}
.button:hover {
transform: scale(1.05);
}
.buttonCyan {
background-color: rgb(8 145 178);
color: white;
}
.buttonCyan:hover {
background-color: rgb(6 182 212);
}
.buttonYellow {
background-color: rgb(202 138 4);
color: white;
}
.buttonYellow:hover {
background-color: rgb(245 158 11);
}
.buttonIndigo {
background-color: rgb(79 70 229);
color: white;
}
.buttonIndigo:hover {
background-color: rgb(99 102 241);
}
.buttonGray {
background-color: rgb(55 65 81);
color: white;
}
.buttonGray:hover {
background-color: rgb(75 85 99);
}
/* Responsive styles */
@media (min-width: 768px) {
.title {
font-size: 3rem;
}
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.hashContent {
flex-direction: row;
}
.hashText {
text-align: left;
}
.hashValue {
font-size: 1rem;
}
.hashIcon {
margin-top: 0;
}
}
@media (max-width: 767px) {
.grid {
display: flex;
flex-direction: column;
gap: 1rem;
}
}