async function sha256(message) {
// encode as UTF-8
const msgBuffer = new TextEncoder("utf-8").encode(message)
// hash the message
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer)
// convert ArrayBuffer to Array
const hashArray = Array.from(new Uint8Array(hashBuffer))
// convert bytes to hex string
const hashHex = hashArray
.map((b) => ("00" + b.toString(16)).slice(-2))
.join("")
return hashHex
}
const { useState, unstable_useTransition: useTransition, useCallback, useRef, useEffect } = React
const useStateAndRef = (defaultValue) => {
const [state, setState] = useState(defaultValue)
const ref = useRef(defaultValue)
useEffect(() => {
ref.current = state
}, [state])
return [state, setState, ref]
}
const timeFormatter = new Intl.NumberFormat('en-US', { maximumSignificantDigits: 3 })
const hashRateFormatter = new Intl.NumberFormat('en-US', { maximumSignificantDigits: 4 })
const addToAverage = (currentAverage, newValue, nthValue) => {
return (currentAverage * ((nthValue - 1) / nthValue)) + (newValue * (1 / nthValue))
}
const Component = () => {
const [input, setInput] = useState("")
const [displayNonce, setDisplayNonce] = useState(0)
const [difficulty, setDifficulty] = useState(1)
const nonce = useRef(0)
const lastHash = useRef("")
const [running, setRunning, runningRef] = useStateAndRef(false)
const [output, setOutput] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
const [smallestHash, setSmallestHash] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
const [startTransition, isPending] = useTransition({ timeoutMs: 5000 })
useEffect(() => {
if (running) {
let targetHex = ""
for (let i = 0; i < 64; i++) {
targetHex += i < difficulty ? "0" : "f"
}
const target = parseInt(targetHex, 16)
const searchForNonce = () => {
sha256(input + nonce.current).then(hash => {
if (parseInt(hash, 16) <= target) {
setRunning(false)
setOutput(hash)
setDisplayNonce(nonce.current)
} else {
nonce.current++
lastHash.current = hash
if (runningRef.current) searchForNonce()
}
})
}
const renderProgress = () => {
setDisplayNonce(nonce.current)
setOutput(lastHash.current)
}
const renderTimer = setInterval(renderProgress, 32)
searchForNonce()
return () => clearInterval(renderTimer)
}
}, [running, input])
const onChange = useCallback(e => { setInput(e.target.value) })
useEffect(() => {
if (!running) {
sha256(input + displayNonce).then(result => setOutput(result))
}
}, [input, displayNonce, running])
let renderedDifficulty = ""
for (let i = 0; i < difficulty; i++) {
renderedDifficulty += "0"
}
return (
<>
<label className="font-semibold">Pretend Block Data</label>
<textarea className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 mb-4 font-mono placeholder-gray-500" value={input} onChange={onChange} placeholder="Type anything in here" disabled={running} />
<div className="flex flex-col items-center mb-4">
<label className="font-semibold">Difficulty</label>
<code className="border-gray-300 border-solid border bg-gray-200 rounded p-1 font-mono text-sm">{renderedDifficulty}</code>
<input type="range" min={1} max={6} value={difficulty} onChange={e => setDifficulty(e.target.value)} disabled={running}/>
</div>
<label className="font-semibold">Nonce</label>
<div className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 font-mono text-sm break-all mb-4">
{displayNonce}
</div>
<span className="flex rounded-md shadow-sm mb-4">
<button type="button" className="flex flex-1 items-center justify-center px-3 py-2 border border-gray-300 text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150" onClick={() => setRunning(r => !r)}>
{running ? "Running..." : "Start"}
</button>
</span>
<div className="flex justify-between">
<label className="font-semibold">SHA-256 Output</label>
</div>
<div className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 font-mono text-sm break-all">
{output}
</div>
</>
)
}
ReactDOM.unstable_createRoot(document.getElementById("root")).render(<Component />)
View Compiled