{"id":19345958,"url":"https://github.com/tolitius/miner","last_synced_at":"2026-05-13T13:42:29.198Z","repository":{"id":136548479,"uuid":"128663383","full_name":"tolitius/miner","owner":"tolitius","description":"tracing steps of an evil bitcoin miner","archived":false,"fork":false,"pushed_at":"2018-04-19T17:20:59.000Z","size":23,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-06T13:49:53.203Z","etag":null,"topics":["bitcoin","blockchain","clojure","proof-of-work"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tolitius.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-08T17:03:54.000Z","updated_at":"2024-07-24T17:24:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"c19c88fa-41d3-442a-899e-3682a0989e53","html_url":"https://github.com/tolitius/miner","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fminer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fminer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fminer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tolitius%2Fminer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tolitius","download_url":"https://codeload.github.com/tolitius/miner/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240457944,"owners_count":19804489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","blockchain","clojure","proof-of-work"],"created_at":"2024-11-10T04:08:32.421Z","updated_at":"2026-05-13T13:42:24.152Z","avatar_url":"https://github.com/tolitius.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# miner\n\n- [\"I Me Mine\"](#i-me-mine)\n  - [Prove vs. Verify Moral](#prove-vs-verify-moral)\n- [Current Difficulty](#current-difficulty)\n- [License](#license)\n\n\nBitcoin relies on [Hashcash](https://en.wikipedia.org/wiki/Hashcash) to find (mine) the next block in a chain. The overall flow is fairly simple:\n\n* create a `block header` that includes:\n\n  - block version\n  - transaction merkle tree hash (i.e. a hash of all transactions in a block)\n  - hash of the previous block (i.e. a potential parent)\n  - current timestamp in seconds\n  - difficulty (roughly how many leading zero bits there should be in a new block hash)\n  - nonce (starts with 0 and increments until the hash is found)\n\n* run a `sha256( sha256( block_header ) )`\n\n  - if the hash _does not_ have a \"`difficulty`\" number of leading zero bits, increment `nonce` try again\n  - if the hash _does_ have a \"`difficulty`\" number of leading zero bits, stop and celebrate\n\nA couple of omitted details / real world corrections from the above flow:\n\n* the first transaction in the block has a miner's address which makes a unique seed for hashing\n* in reality difficulty is a ratio of the highest target to the current target. \"[Current Difficulty](#current-difficulty)\" talks more about a \"proper\" difficulty. `miner` will use a number of leading zeros since it better illustrates the point plus bits are more fun to look at.\n* whenever `nonce` overflows, an `extraNonce` field of the very first transaction in the block is changed (which changes the merkle root hash), and the `nonce` is then reset back to `0`.\n\n## \"I Me Mine\"\n\n\u003e _Coming on strong all the time\u003cbr/\u003e\nAll through' the day I me mine\u003cbr/\u003e\nthe Beatles / \"Let It Be\" / 8 May 1970_\n\nWe'll work with a slightly different version of a block header that explicitly includes miner's addess and does _not_ include the difficulty, since we'll use it as a function argument to have a more dynamic feel to it:\n\n```clojure\n;; \"miner address\" would be in the first transacaction in this block\n;; hence the merkle root is unique\n;; \"mine address\" here is for demo purposes to show presence of \"x\" in \"H(s,x,c) \u003c 2^(n-k)\"\n\n{:version 42\n :hash-prev-block \"00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d\"\n :hash-merkle-root \"51d37bdd871c9e1f4d5541be67a6ab625e32028744d7d4609d0c37747b40cd2\"\n :time (/ (System/currentTimeMillis) 1000)\n :miner-adddress \"1c1tAaz5x1HUXrCNLbtMDqc46o5GNn4xqX\"}\n```\n\n`:time` will be different every time this header is created / compiled to have some lively mining properties.\n\nLet's mine a proper hash for this block with a difficulty of 9 leading zero bits:\n\n```bash\n$ boot dev\n```\n```clojure\n=\u003e (mine {:block m/block-header :difficulty 9})\n\n{:block-hash \"0000C4881FB571CB7FDEEC94FB07968B3822E28F48B86CF76B5D619F5C59741E\", :nonce 48833}\n```\n\nwe can visually verify it:\n\n```clojure\n=\u003e (verify {:block m/block-header :nonce 48833})\n\n{:block-hash \"0000C4881FB571CB7FDEEC94FB07968B3822E28F48B86CF76B5D619F5C59741E\",\n :bits       \"0000000000000000111111111111111111111111110001001111111111111111111111111000100000011111111111111111111111111111101101010111000111111111111111111111111111001011011111111111111111111111111111111101111011111111111111111111111111101100111111111111111111111111100101001111111111111111111111111111101100000111111111111111111111111111100101101111111111111111111111111000101100111000001000101111111111111111111111111110001011111111111111111111111110001111010010001111111111111111111111111011100001101100111111111111111111111111111101110110101101011101011000011111111111111111111111111001111101011100010110010111010000011110\"}\n```\n\nLet's see how long mining vs. verification takes:\n\n```clojure\n=\u003e (time (mine {:block m/block-header :difficulty 9}))\n\n\"Elapsed time: 203.523561 msecs\"\n{:block-hash \"0000C4881FB571CB7FDEEC94FB07968B3822E28F48B86CF76B5D619F5C59741E\", :nonce 48833}\n\n=\u003e (time (verify {:block m/block-header :nonce 48833}))\n\n\"Elapsed time: 0.265915 msecs\"\n{:block-hash \"0000C4881FB571CB7FDEEC94FB07968B3822E28F48B86CF76B5D619F5C59741E\",\n :bits       \"0000000000000000111111111111111111111111110001001111111111111111111111111000100000011111111111111111111111111111101101010111000111111111111111111111111111001011011111111111111111111111111111111101111011111111111111111111111111101100111111111111111111111111100101001111111111111111111111111111101100000111111111111111111111111111100101101111111111111111111111111000101100111000001000101111111111111111111111111110001011111111111111111111111110001111010010001111111111111111111111111011100001101100111111111111111111111111111101110110101101011101011000011111111111111111111111111001111101011100010110010111010000011110\"}\n```\n\nNow let's up our game by increasing the difficulty to 24 leading zero bits:\n\n```clojure\n=\u003e (time (mine {:block m/block-header :difficulty 24}))\n\n\"Elapsed time: 28347.474171 msecs\"\n{:block-hash \"000000D3AF97325446B46CA64B0640BFC79031B734180F4A7B61571A3D247832\", :nonce 8125108}\n\n=\u003e (time (verify {:block m/block-header :nonce 8125108}))\n\n\"Elapsed time: 0.28443 msecs\"\n{:block-hash \"000000D3AF97325446B46CA64B0640BFC79031B734180F4A7B61571A3D247832\",\n :bits       \"0000000000000000000000001111111111111111111111111101001111111111111111111111111110101111111111111111111111111111100101110011001001010100010001101111111111111111111111111011010001101100111111111111111111111111101001100100101100000110010000001111111111111111111111111011111111111111111111111111111111000111111111111111111111111111100100000011000111111111111111111111111110110111001101000001100000001111010010100111101101100001010101110001101000111101001001000111100000110010\"}\n```\n\n### Prove vs. Verify Moral\n\nto _prove_ you did the work:      is **exponentially hard** depending on the current algorithm's difficulty\n\nto _verify_ someone did the work: is **constant time** (i.e. inexpensive)\n\n## Current Difficulty\n\nReal difficulty shows the ratio between the highest target (the lowest difficulty) which is `0x00000000FFFF0000000000000000000000000000000000000000000000000000` and the current target. In other words: \"how more difficult it became to find the correct hash/block\".\n\n`miner` fetches the current difficulty from [blockexplorer](https://blockexplorer.com/api/status?q=getDifficulty) and calculates the current target and the number of leading zero bits the hash should have:\n\n```clojure\n=\u003e (m/show-current-difficulty)\n\n{:difficulty 3.839316899029672E12,\n :target \"00000000000000000049500cffffffff27fa820ec18bb1999d9f4f0e1fd9e679\",\n :leading-zero-bits 72}\n```\n\nthis really means that any hash **less than a `target`** is correct. So leading zero bits used by `miner` is a \"ceiling approxomation\".\n\n## License\n\nCopyright © 2018 tolitius\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftolitius%2Fminer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftolitius%2Fminer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftolitius%2Fminer/lists"}