
Show HN: Legion, an as-simple-as-possible blockchain server written in Haskell - aviaviavi
https://github.com/aviaviavi/legion
======
KirinDave
I'm tempted to just make a youtube video going over this code line by line.

It's a really great introduction to a non-trivial bit of Haskell.

~~~
seanparsons
Would it make sense to make the code Literate Haskell?

~~~
aviaviavi
I'm not familiar with Literate Haskell, what would that involve?

~~~
KirinDave
It's just where the majority of the file is a comment instead of a minority.

~~~
piaste
Thank you. Thank you so much.

It's an old pet peeve of mine. I cringe inside every time someone starts
waxing about "writing your thoughts first, and your code only incidentally" or
"it's a completely different paradigm of programming" and other such pieces of
useless, discouraging new age fluff.

------
shadytrees
Great use of distributed-process and distributed-process-p2p! Being able to
access service discovery and peer-to-peer communication as simple Haskell
packages is kind of amazing.

* [https://hackage.haskell.org/package/distributed-process-p2p](https://hackage.haskell.org/package/distributed-process-p2p)

* [https://hackage.haskell.org/package/distributed-process](https://hackage.haskell.org/package/distributed-process)

~~~
aviaviavi
Those libraries were essential for this project! High quality. Are you a
contributor to them?

I actually had a slightly tough time finding good examples to work off of for
p2p, (the cloud haskell website had the best ones), so hopefully this code can
also work as another good example for those packages. To be fair, that's
really a complaint of the ecosystem as a whole, not distributed-process-*
specifically.

------
jstanley
I had a brief look through, and it looks like there's no proof-of-work in the
mining?

What stops somebody from rewriting history and passing it off as legitimate?

~~~
empath75
Nothing. It's a minimal blockchain.

~~~
aviaviavi
Correct, the goal for this was as minimal as possible.

However, if I (or anyone wanting to contribute) can come up with a very
compact way to implement that, we could definitely add it!

~~~
terhechte
A very simple proof of work is adding a token to the data before hashing:

sha256(token + data + previous hash)

i.e. (for simplicity, previous hash = "")

sha256("1" \+ "example" \+ PreviousHash) ->
ee73735c2355bc4d63319a6638e356ef42d0d56746317c99f52d3e7ac71cbf52

sha256("2" \+ "example" \+ PreviousHash) ->
6236cd42286c74a1683eaf394b3b2f40a3a52479e1a3d7e732175fcdfa49b931

...

sha256("10" \+ "example" \+ PreviousHash) ->
346fea90403e733fd6e925920eb10be06171b4f77f7cc8c4ef214a12f04d79c1

And only accepting hashes as valid where the first two characters form "34".
So the last example (token 10) would be valid. This requires then to do
multiple hashing operations until a valid hash emerges, thus the proof of
work.

~~~
vog
Note that "the first X characters" is kind of misleading, because it is
usually more fine grained.

It is better (and IMHO even simpler!) to think of the hash as a large integer,
not a string. Then you want that integer to be smaller than a certain value.

With strings, you can only say: "00123" shall start with "00", while wih
integers, you would say: 00123 shall be smaller than 300.

(To be that fine grained with strings, you would either need multiple prefixes
("000", "001", "002") regexes ("00[012]"), both more hassle than a simple
less-than operation.)

~~~
jstanley
I agree with the gist, but note that even with strings, "00122" is less than
"00200" :)

~~~
vog
Oh, you are right! However, my point still stands that this is not about
prefixes, but about a less-than comparison.

------
eemax
Neat. Just browsing through the source, is there a reason that:

    
    
       calculateBlockHash (Block i p t b _)  = concatMap hashString [show i, p, show t, b]
    

is not

    
    
       calculateBlockHash (Block i p t b _)  =  hashString $ concat [show i, p, show t, b]
    

i.e. why is a block hash a concatenation of 4 SHA-256 hashes instead of just
1? Is there some security benefit of doing it one way vs. the other?

edit: thinking about it a little more, option 2 seems better because in option
1 you can calculate 3/4 of a block hash without knowing the previous block's
hash. Maybe that's not a problem in this context though?

~~~
aviaviavi
You're correct, it really should be the 2nd way. The current form isn't really
a problem per se, mostly just that the generated hashes are really long and
make the output harder to read. I'll get that updated, great catch.

EDIT: code updated.

------
greglindahl
Of course there are name collisions everywhere, but, there's a
metacomputing/grid computing/distributed OS thingie named "Legion" from the
University of Virginia that has a bunch of papers about it in the CS
literature.

Oh, and we saw off the American Legion threatening to sue us by saying "We're
the State of Virginia, go right ahead..."; what's your strategy? :-)

~~~
jboynyc
You mean this project might be summoning daemons that will claim, "Our name is
Legion"?

[http://bible.oremus.org/?ql=363093142](http://bible.oremus.org/?ql=363093142)

~~~
greglindahl
Humorously, the professor who named it thought the quote was from Heinlein.
Not much of a Bible-reader.

Edit: Apparently I'm not very good at remembering my SciFi, maybe it's this?
[https://en.wikipedia.org/wiki/My_Name_Is_Legion_(short_story...](https://en.wikipedia.org/wiki/My_Name_Is_Legion_\(short_story_collection\))

------
m-j-fox
Nicely done. It reads like Ikea instructions. I didn't really know how
blockchain worked until I read this code. If this was written as a teaching
tool or a portfolio piece or even an art project, then I say its a big
success.

One question:

    
    
        getBlockChain :: (SpockState m ~ BlockChainState, MonadIO m, HasSpock m) => m [Block]
    

What does the squiggle mean?

~~~
aviaviavi
If you learned a thing about blockchains from this project, I'd call it a big
success too! :D So happy to hear it was helpful

~~~
m-j-fox
Thanks for making this. It reminds me of the day I fell in love with Haskell.
I wanted to learn how a Verilog simulator works. There's a couple good open-
source ones but I found the code impenetrable, so I went looking for something
like an introductory course and found this obscure, disused code called Hydra
which is hard to find. Let me see ... here it is:

[https://github.com/garry-
sharp/x/tree/master/CA4/HydraLib-0....](https://github.com/garry-
sharp/x/tree/master/CA4/HydraLib-0.8.1)

After reading for just an hour, the lightbulb came on and I not-only felt I
had learned how a digital simulator works but also what a mighty hammer
Haskell can be for teaching.

Since then I've read (and unfortunately written) a lot of Haskell that is far
less elucidating. It's great to come across something that reminds me how I
got turned on in the first place and that I should aspire to produce code that
not-only barely gets the job done but also explains itself and embodies a
modicum of beauty. Thanks again.

------
bernardlunn
My takeaway from this was to learn more about Literate Haskell. As somebody
points out a Blockchain without a consensus mechanism is simply a linked list
ie this is not really about pushing the envelope of Blockchain tech.

------
SkyMarshal
In case you're not aware of it, also check out Haskoin, a Bitcoin
implementation in Haskell.

[https://github.com/haskoin/haskoin](https://github.com/haskoin/haskoin)

------
erikb
Can someone explain to me in short summary why blockchain without crypto
currency suddenly is a thing and why anybody would want it?

~~~
quchen
ELI5: A blockchain is an »I told you so« store. Future statements/promises are
linked to past ones so you can’t mess one without having to mess with _all_
the others. It’s like a black board you can’t wipe clean again, adding more
text (and space to write to) is the only thing possible.

For example, you could promise to paint your house red in a blockchain. You
later regret that promise and tell your friends you never said that, but since
they all have access to all promises made, they have good evidence that what
you say is not true.

~~~
erikb
Thanks, very good explanation. So blockchain enables us to move from "our data
warehouse is the single source of truth" to "our data warehouse is the single
History of truth".

~~~
kaoD
I'd say more like "this tiny [latest] block is a strong proof of history".

------
cocktailpeanuts
Thanks for sharing, the code looks very elegant. This alone makes me want to
sit down and learn Haskell.

~~~
aviaviavi
Thanks, you definitely should! It's very fun to write code in.

------
hestefisk
... had this been written in a language less esoteric than Haskell, it
would've been even better for the rest of us :)

~~~
aviaviavi
I suggest you take a look at
[https://github.com/lhartikk/naivechain](https://github.com/lhartikk/naivechain),
the original version of this work, written in JS

~~~
flavio81
I second the recommendation for Naivechain. It is really easy to understand.

For me, reading the Javascript code of Naivechain made me understand
Blockchains in an easier-to-understand way than all the tutorials that try to
explain how to implement a blockchain!!

