Skip to content

Instantly share code, notes, and snippets.

@fserb
Created May 31, 2021 19:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fserb/aee1beab9a0ca307ee3f6374c2e07543 to your computer and use it in GitHub Desktop.
Save fserb/aee1beab9a0ca307ee3f6374c2e07543 to your computer and use it in GitHub Desktop.
A blockchain implementation on top of git in 50 lines of Python
#!/usr/bin/env python3
import subprocess, sys, os, tempfile, re
"""
How to use this:
1. create a git repo
2. commit something to it
3. run ./chainy.py <number of zeroes>
where <number of zeroes> is how many zeroes you want the git commit hash to
have. You can try with 2 or 3 for fast results. Bigger numbers are safer, but
will take longer.
Repeat step 2, 3 as many times as you want and you will end up with a git repo
where all commits have the correct number of zeroes. This gives you the exact
same guarantee of Bitcoin: that if you someone wants to fake your history, they
would have to redo all processing work that chainy put on finding the
zero-ending hashes. I.e., the repo itself has proof of work.
It works by adding a "Chainy: <padnumber>" to the latest git commit. Where
<padnumber> is a number that makes the git commit's SHA-1 end with the correct
number of zeroes. Finding this number, i.e., "mining it", is what this script
does. In an extremely inneficient way.
"""
def git(*cmd):
with subprocess.Popen(["git", *cmd],
env=os.environ, stdout=subprocess.PIPE) as p:
p.wait()
return p.stdout.read().decode('utf-8').strip()
def main(args):
if len(args) == 1:
print("Pass number of zeroes")
return 1
zeroes = int(args[1])
print("Setting %d zeroes" % (zeroes,))
if not git("rev-parse", "--git-dir"):
print("Must be run inside a git repo")
return 2
clean_tree = len(git("diff-index", "--name-only", "HEAD", "--")) == 0
if not clean_tree:
print("Uncommmited changes")
return 3
while True:
head = git("rev-parse", "HEAD")
if head[-zeroes:] == "0" * zeroes:
print(head)
break
msg = git("log", "-1", "--pretty=%B").split('\n')
last_line = msg[-1]
c = re.findall("Chainy: (\d+)$", last_line)
if not c:
c = 0
else:
msg = msg[:-2]
c = int(c[0]) + 1
msg.append("")
msg.append("Chainy: %d" % (c,))
if c % 100 == 0: print(head, c)
with tempfile.NamedTemporaryFile('wt') as tmp:
tmp.write('\n'.join(msg))
tmp.seek(0)
git("commit", "--amend", "--file", tmp.name)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment