{"id":16040456,"url":"https://github.com/andrewaguiar/blockxain","last_synced_at":"2025-04-05T06:26:40.279Z","repository":{"id":147214893,"uuid":"110545873","full_name":"andrewaguiar/Blockxain","owner":"andrewaguiar","description":"A naive blockxain implementation for study purpose only","archived":false,"fork":false,"pushed_at":"2017-11-17T17:33:09.000Z","size":31,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-10T14:14:43.271Z","etag":null,"topics":["blockchain","elixir","merkle-tree","proof-of-work","study"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","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/andrewaguiar.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":"2017-11-13T12:32:24.000Z","updated_at":"2018-08-18T12:36:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"659fc230-7d6c-4424-9f06-7483824cbf5a","html_url":"https://github.com/andrewaguiar/Blockxain","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/andrewaguiar%2FBlockxain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewaguiar%2FBlockxain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewaguiar%2FBlockxain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewaguiar%2FBlockxain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrewaguiar","download_url":"https://codeload.github.com/andrewaguiar/Blockxain/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247297875,"owners_count":20915925,"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":["blockchain","elixir","merkle-tree","proof-of-work","study"],"created_at":"2024-10-08T23:13:01.700Z","updated_at":"2025-04-05T06:26:40.256Z","avatar_url":"https://github.com/andrewaguiar.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blockxain\n\nA naive blockchain implementation using Elixir for educational purpose only\n\n## What is a blockchain?\nBasically a blockchain is a growing list of blocks which are linked (a block points to it's prior sibling) with\neach other and contains any kind of data in it. To be able to guarantee data consistence we can get the data plus\na timestamp and generate an hash to the block\n\n```elixir\n  hash = :crypto.hash(:sha256, data) |\u003e Base.encode16\n```\n\nSo our blocks are going to be like the blocks below, and more important if somehow the data got corruped we can easily\ncheck that using the hash and the data\n\n```elixir\n  (:crypto.hash(:sha256, data_to_be_verified) |\u003e Base.encode16) == hash\n```\n\nSo this way we have our blockchain and we can trust that no data will be corruped 🎉.\n\n```elixir\n[\n  #...\n\n  # Block 2\n  %{\n    hash: \"E65ED92B129940B9D89362D83BC1DC04425AC134DBA526BDD3FD11D07AE14AD0\",\n    data: \"any kind of data can be stored here\"\n  },\n\n  # Block 3\n  %{\n    hash: \"7E51FBD75320FFEFCB5E0573C67DF823441D4C23E0829229F3F82FA35A0E0990\",\n    data: \"any kind of data can be stored here also\"\n  }\n]\n```\n\nBut we still have a problem here, what if somebody takes a block; changes its data and simply regenerate the hash 🤔?\nIn this case the block would be considered valid, but our blockchain would be corrupted.\n\nTo fix it we can simply use the previous block hash appended with the data to generate the hash, this way if somebody\ncorrupts a block he/she have to recalculate the hash of all next blocks.\n\n```elixir\n  hash = :crypto.hash(:sha256, data \u003c\u003e previows_hash) |\u003e Base.encode16\n```\n\nAs you can see in the code above the block 3 points to the block 2 using the previows_hash attribute, and its own hash\nwas created using the data plus the previows_hash.\n\n```elixir\n[\n  #...\n\n  # Block 2\n  %{\n    hash: \"E65ED92B129940B9D89362D83BC1DC04425AC134DBA526BDD3FD11D07AE14AD0\",\n    timestamp: 1510698296035,\n    previows_hash: \"ADC8AC2BF1D0E405A20EAD25E9A5BA446941FB4A79CE3BEACC765AE66C549C7C\",\n    data: \"any kind of data can be stored here\"\n  },\n\n  # Block 3\n  %{\n    hash: \"7E51FBD75320FFEFCB5E0573C67DF823441D4C23E0829229F3F82FA35A0E0990\",\n    timestamp: 1510698306319,\n    previows_hash: \"E65ED92B129940B9D89362D83BC1DC04425AC134DBA526BDD3FD11D07AE14AD0\",\n    data: \"any kind of data can be stored here also\"\n  }\n]\n```\n\nThis adds a little more complexity to malicious people who tries to corrupt our blockchains, but it is not enougth.\nGenerating a hash is very fast nowadays, using some fast hardware attackers could recreate all hashes in minutes.\nIn this case we should enforce people who generates the hash to spend a good amount of time and CPU effort to generate\nthe hash, and at the same time we should be able to verify the hash very quickly.\n\n## Proof of Work\n\nProof of work is an algorithm that can be used when you requires that a user / system proofs that he spend some effort\n(time and CPU) to execute something. A very naive implementation of this could be done using the own hash function we already\nsaw.\n\nGenerating a hash is fast of some data is very fast:\n\n```\n:crypto.hash(:sha256, \"ola\") |\u003e Base.encode16\n# =\u003e 55A9F4F8994B1BBF2058EA38C8EFB6C459000814D5F39C087002571639E6230E\n```\n\nBut we can require that the hash starts with `\"28\"` (for instance), as the hash generated is always the same given this data\nthe user needs to change the data to generate other hashes and tries. The ideia then is append a nonce (a unique number) and\ntries to find a hash that matches our challenge\n\n```\n:crypto.hash(:sha256, data \u003c\u003e \"1\") |\u003e Base.encode16 # =\u003e \"4CFC2263B5ADE5AE01ED784047E9FEC4029C0D2CB10BA79001A3ED2EF42F0D91\"\n:crypto.hash(:sha256, data \u003c\u003e \"2\") |\u003e Base.encode16 # =\u003e \"7812F001C07DE4D97485F912B33B4A57B75CBA3205F757AD888BAE92DCA42C88\"\n:crypto.hash(:sha256, data \u003c\u003e \"3\") |\u003e Base.encode16 # =\u003e \"7E2835C927A4BE25CAF6654A10FD856E661BF91457FAF0E2C5E8FD1BEC2B77DB\"\n:crypto.hash(:sha256, data \u003c\u003e \"4\") |\u003e Base.encode16 # =\u003e \"6AA5A9E5F64887B7A4C8A206A0478292BB125267690AFCDB2E19B42520C650D1\"\n:crypto.hash(:sha256, data \u003c\u003e \"5\") |\u003e Base.encode16 # =\u003e \"E9751FECB97DA01CB065A6057FC5A2B76259FBD602555122935A30A398696966\"\n:crypto.hash(:sha256, data \u003c\u003e \"6\") |\u003e Base.encode16 # =\u003e \"505D29080341DE336E977419B0D8E5FF6145FDD90880A098846290B39B3103CF\"\n:crypto.hash(:sha256, data \u003c\u003e \"7\") |\u003e Base.encode16 # =\u003e \"6932809DC4643207F47EFB483899B5CA43E5125F76827DBA6CD8505E93CFABF2\"\n:crypto.hash(:sha256, data \u003c\u003e \"8\") |\u003e Base.encode16 # =\u003e \"310C03BECF7ADDCBAC42AD387F6B4818C0C5BE954E408694AB91DB5CFE7814AB\"\n:crypto.hash(:sha256, data \u003c\u003e \"9\") |\u003e Base.encode16 # =\u003e \"EB3497EB40705CA192AA1E3347376836E68E10F08356B56AB3913651C283EEDC\"\n:crypto.hash(:sha256, data \u003c\u003e \"10\") |\u003e Base.encode16 # =\u003e \"E2DAA5A45109A218F9F510D17D34460FAC092F638907A619FEBB635224D84C37\"\n:crypto.hash(:sha256, data \u003c\u003e \"11\") |\u003e Base.encode16 # =\u003e \"40634735468E285577F9876A04C74BBDD75C542AE0F09CC926D534A8E3EF91EC\"\n:crypto.hash(:sha256, data \u003c\u003e \"12\") |\u003e Base.encode16 # =\u003e \"0FD4FF755505F2B019969EDBD9C8EC3B984AC2381E4BA0C8F18DF5ADD95883C3\"\n:crypto.hash(:sha256, data \u003c\u003e \"13\") |\u003e Base.encode16 # =\u003e \"77C897F5D86B8C39B78B12D743C19E640EBEDCD060F7EF60654DF6D0A9440AA1\"\n:crypto.hash(:sha256, data \u003c\u003e \"14\") |\u003e Base.encode16 # =\u003e \"E6E7BEF1C63D139AEBD28588CB1B031FB93392F8836646971DCFEF7ED13AC7C1\"\n:crypto.hash(:sha256, data \u003c\u003e \"15\") |\u003e Base.encode16 # =\u003e \"28D1C08992D346B301661FA7067BF767E1E9A2F83652C792DE44760F55E54A56\"\n```\n\nIn our case we were lucky, after only 15 rounds we found a winning hash. A more complete algorithm would be something like:\n\n```\ndefmodule ProofOfWork do\n  def compute_hash_with_proof_of_work(data, difficult) do\n    compute_hash_with_proof_of_work_with_nonce(data, difficult, 0)\n  end\n\n  defp compute_hash_with_proof_of_work_with_nonce(data, difficult, nonce) do\n    with hash \u003c- (:crypto.hash(:sha256, \"#{data}#{nonce}\") |\u003e Base.encode16),\n         true \u003c- String.starts_with?(hash, difficult) do\n      {nonce, hash}\n    else\n      _ -\u003e compute_hash_with_proof_of_work_with_nonce(data, difficult, nonce + 1)\n    end\n  end\nend\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewaguiar%2Fblockxain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrewaguiar%2Fblockxain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewaguiar%2Fblockxain/lists"}