#wrapper.p-5
  h1.text-2xl.font-bold.text-center Mine Your Own Block
  
  #root
View Compiled
* {
  font-family: proxima-nova, sans-serif;
}

#wrapper {
  max-width: 350px;
  margin: auto;
}

p {
  color: #4D4D4D;
}
View Compiled
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 } = React

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 [output, setOutput] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  const [smallestHash, setSmallestHash] = useState("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  const [hashingTime, setHashingTime] = useState(0)
  const [averageHashingTime, setAverageHashingTime] = useState(0)
  const hashes = useRef(new Set(["e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"]))
  const [startTransition, isPending] = useTransition({ timeoutMs: 5000 })
  const onChange = useCallback(e => {
    const value = e.target.value
    
    setInput(value)
    
    startTransition(() => {
      const t0 = performance.now()
      sha256(value).then(result => {
        const t1 = performance.now()
        setSmallestHash(currentSmallest => parseInt(result, 16) < parseInt(currentSmallest, 16) ? result : currentSmallest)
        setOutput(result)
        setHashingTime(t1-t0)
        let countAverage = !hashes.current.has(result)
        hashes.current.add(result)
        if (countAverage) {
          setAverageHashingTime(current => addToAverage(current, t1-t0, hashes.current.size))
        }
      })
    })
  })
  
  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" />
      <div className="flex justify-between">
        <label className="font-semibold">SHA-256 Output</label>
        <p className="font-mono text-sm text-gray-500">{hashes.current.size} {hashes.current.size == 1 ? 'hash' : 'hashes'}</p>
      </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>
      <div className="flex justify-between mb-4">
        <div className="font-mono text-sm text-gray-500">
          Computed in {timeFormatter.format(hashingTime)} ms
        </div>
        <div className="font-mono text-sm text-gray-500 hidden">
          Hash Rate: {hashRateFormatter.format(1000 / averageHashingTime)} hashes / sec
        </div>
      </div>
      <p className="mb-4">Try to see how small of an output you can find. See if you can find an output that starts with <code className="border-gray-300 border-solid border bg-gray-200 rounded p-1 font-mono text-sm">00</code></p>
      
      <label className="font-semibold">Smallest Output Found</label>
      <div className="border-gray-300 border-solid border bg-gray-200 rounded w-full p-2 font-mono text-sm break-all">
        {smallestHash} 
      </div>
    </>
  )
}

ReactDOM.unstable_createRoot(document.getElementById("root")).render(<Component />)
View Compiled

External CSS

  1. https://cdn.jsdelivr.net/npm/@tailwindcss/ui@latest/dist/tailwind-ui.min.css
  2. https://use.typekit.net/tjo5maf.css

External JavaScript

  1. https://cdn.jsdelivr.net/npm/react@experimental/umd/react.development.min.js
  2. https://cdn.jsdelivr.net/npm/react-dom@experimental/umd/react-dom.development.min.js