I don’t consume cannabis very often, but when I do I usually end up watching documentaries about Thomas Edison.
Which, as I write that, makes me think I should smoke weed more often.
Anyways, a historian in one documentary said something that was deceptively profound.
“Edison decided he was going to be about inventing. He was going to invent full-time.”
That was a new concept in Edison’s day? That blew my mind. Today, one of our most popular TV shows revolves around people pitching their inventions in the hopes of turning it into a successful business.
Obviously, people invented stuff in Edison’s day, but apparently he was one of the first people to do it as his main hustle, exclusively inventing and commercializing brand new technologies.
At the time, there wasn’t even really a mental model of what a “successful” inventor looked like. Edison had to figure that out.
Tragically, humans hate this sort of ambiguity.
When we think about our careers and the contributions we want to make to the world, we often lack Edison’s courage and prefer to just do the things we’ve seen work before. It’s easier to cut and paste from a few compelling role models, proven professions, or tried-and-true paths.
Sometimes, following the crowd works (the now-conventional wisdom “learn to code” probably isn’t bad advice in general). Sometimes, though, it’s tragic (are people still getting accounting majors?!).
Even if pursuing a “traditional” path works out financially, it’s not hard to accidentally sacrifice what is uniquely valuable about your perspective or personality in the process.
“The people who make Vice President at this bank are soulless, miserable creatures who frequently fill their comically-large penthouses with people they, deep down, despise. Therefore, it is imperative that I kill my personality and sense of humor as soon as possible. Because, money.”
That outcome feels as tragic as picking a dying career path. They both cost the world a unique contribution.
At some point, every compelling role model had to ignore the prevailing wisdom of their time and be the first person to do something.
They had to suck it up and deal with the uncertainty.
Their genius is only obvious in hindsight.
Our “normal” is just the world a few weirdos championed 50 years earlier.
The year is 1997. The internet is growing at a mind-blowing pace. It’s a glorious time to be alive.
But, while man rapidly builds his greatest invention, a few bad actors are quietly plotting to screw it all up.
They want to abuse the reach and accessibility of the internet by flooding it with unsolicited promotional emails – “spam,” as the youths call it.
And in 1997, inboxes everywhere agree: the spammers are winning.
Why do people send spam?
Most spam either tries to sell something (advertising) or trick a user into sharing sensitive information (phishing) that the sender can use maliciously.
Why is it so easy to send spam emails?
An individual email is a tiny file that can be reproduced and distributed near-instantaneously to millions of people at essentially no cost (relative to the next best options).
Sending email is cheap mostly because:
- The distribution channel (the internet) is essentially free and open to anybody
- It requires negligible compute resources to send an email
The first fact, at least in 1997, was impractical to change.
The second was far more negotiable.
What if our email protocols required a computer to exert some modest computational effort in order to send a message?
Sending a single email wouldn’t be overly-demanding (perhaps only taking a second or so), but sending millions upon millions would quickly become a Herculean effort requiring massive, and therefore expensive, compute resources.
This gave birth to proof-of-work systems.
In a proof-of-work system, a computer is required to solve a computational problem of a pre-determined level of difficulty before it’s allowed to take some desired action.
Once the computer solves the problem, it shares its answer as “proof” of its efforts.
Another computer is able to quickly verify the proof and allow the desired action to take place.
In the case of limiting spam, we’d want our email client to only accept an email from somebody who has provided proof they underwent an effort to get it to us.
So, how can we verify that a computer has made a particular effort?
Imagine we have a function that, for any given input, produces a fixed-size output.
When we send a simple string through our function:
our_function(“Which one of you bastards ate my pad thai?”)
It produces this output every time we send that exact string through it.
Now, take a look at what happens when we change one single character in our input:
our_function(“Which one of you bastards ate my pad thai!”)
The output is radically different!
This makes it impractical to reverse-engineer how input is transformed into output. Tiny alterations to our input do not create obvious, measurable changes to the output.
Also, remember that our output is always a string of a fixed size. In this example, our output will always be 64 characters long.
For simplicity, let’s imagine that every character in the output string can only be one of the 16 hexadecimal values (0-9, a-f). Even with these constraints, our function yields an enormous number of possible outputs.
A math refresher: a 64 character-long string where each character can be one of 16 items produces 1664 different possible outputs. 1664 is a ludicrously large number. Like, total-atoms-in-the-observable-universe huge.
Given the enormous range of possible output values, we will be able to generate a unique output string for pretty much any input.
Occasionally, two different inputs will map to the same value (a “collision”), but in our function this is extremely rare.
Put simply: our function creates a unique identifier for almost any unique input.
There’s a fancy name for the type of function we just built: a “cryptographic hash function.”
Cryptographic hash functions have a few other properties, but our example covers the most relevant. So…
How can we use this function to “prove” a computer has done some work?
Recall that our function executes quickly. It’s not hard to run some input through and produce some output.
But, imagine if we asked:
Solve for an input, n, where our_function(n) returns the following output: ‘0c756ce63af37a723cf4f8012f6817a58ba55196bf0f9dc9f962086d24f6ab7f’.
Assuming the computer had never seen the particular output string (and had known the input that produced it), it would have to start making random guesses and checking the output.
But, remember, it could take up to 16^64 guesses to get the right answer. 
That could literally take billions of years to solve, so instead we might ask a far less demanding question like:
Solve for an input, n, where our_function(n) returns an output where the first three characters are 0’s.
Assuming we hadn’t worked with our_function(n) in the past, we would start making random guesses until we received an output like:
It requires dramatically less effort to guess three correct characters than 64.
If we wanted to make things more challenging, we’d go from matching the first 3 characters to matching the first 4, then the first 5. Each step becomes 16 times more difficult than the last because, recall, there are 16 possible values for each character.
We can think of this as a work factor. We’d like the ability to make problems harder over time if needed. After all, any challenge we would have created in 1997 would be trivially easy to complete today with our faster processors.
We still have a problem though: once somebody has found an input that produces a desired output, they can just re-use the answer the next time they’re asked the same question, exerting negligible effort.
So, to prevent re-using answers, we could generate a random value each time we ask the question and require that it be appended to the input, thereby guaranteeing that they couldn’t re-use an old answer (remember: altering just one character to our input dramatically alters the output).
Our question would look more like:
Given a random string, solve for an input, n, where our_function(n + random_string) returns an output where the first three characters are 0’s.
Even if they discovered an input, n, that had previously produced an output starting with three 0’s, that same input n combined with a random string would produce a wildly different value, requiring them to start from scratch and solve for a different n.
Now, obviously, our random string generation function would need to be truly random. A half-assed random generator that produced the same challenges more frequently than pure probability would increase the likelihood of a challenger receiving the same challenge twice.
But, that’s a rabbit hole for another day.
Putting this all together, a simple function to guess the value of n might look like the following:
In the code above, “challenge” is the random string that we’ll send to a challenger.
And we might validate random guesses for n with something like this. We’re just asking if Hash(n + random_string) outputs a value that starts with a sufficient number of 0’s.
Pretty simple, huh?
There are a few more things we’ll need to build out to make this sensible, particularly for the concepts invented for combatting spam (Hashcash, in particular), but hopefully this illustrates the underlying theory behind proof-of-work.
For most of human history, knowledge was scarce.
It was often stored in people’s brains and, occasionally on stone or paper, both of which were easily lost or destroyed.
It was often transmitted orally, always one game of “telephone” away from being lost or degraded.
Knowledge was highly localized; and knowledge that did survive was often held behind closed doors and only accessible by a privileged few.
To read Confucius, to know that he even existed, you’d not only need to be in the East, but you’d need to be friendly with the dynasty guarding the library of Eastern knowledge.
Two millennia later, our relationship with knowledge has been revolutionized by the internet.
Rather than being stuck in a single library or a single human mind, most knowledge that lives on the internet is immediately available to almost any human, largely unencumbered by gatekeepers and geography.
Today, experiences are very similar to pre-internet knowledge.
Experiences are highly local. To experience a sailing trip in the Mediterranean, you must go there.
Experiences are protected by gatekeepers. You can’t experience a concert from the front row without buying the tickets.
Experiences are ephemeral. The circumstances which allowed a specific experience may never arise again.
Today, we are at the dawn of building technology which will allow us to do for experiences what the internet did for information.
Virtual reality will democratize experiences.
People will be able to experience what it’s like to sail through the Mediterranean without leaving their living room.
It’s going to be wild.
As we grew our team at MassRoots, we frequently reiterated the need to exclusively hire “A Players,” but we never actually articulated what exactly that meant.
When somebody pointed this out during an all-hands, we created the following list to help define the types of people we wanted on our team.
Hopefully it can help you frame the difference between somebody who is adequate and somebody who is exceptional.
A Players contribute 5-10x their value. B Players contribute exactly what they’re paid for, sometimes less.
A Players are pulled towards learning, growth, hard work. B Players need to be pushed.
A Players crave mentorship. B Players crave management.
A Players are gratified by hard work. B Players never miss a happy hour.
A Players are like air support. B Players are like speed bumps.
A Players sometimes complain, but always offer solutions. B Players never take responsibility.
A Players do not want to work with B Players.
A Players feel physical pain when work is subpar. B Players make no distinction between “done” and “done well.”
A Players care about the people who consume their work. B Players view them as a burden.
A Players say “we.” B Players say “you,” “they,” and “I.”
A Players hate carelessness. B Players hate the extra work that diligence requires.
A Players own. B Players blame.
A Players aspire to make everybody else’s job easier. B Players aspire for others to make their job easier.
A Players offer alternatives. B Players can only explain why it won’t work.
A Players give a shit. B Players can’t hide their apathy.
Oh, and one more: A Players will drop a comment and share what they disagree with 🙂
This is a bit embarrassing, but my Nest camera caught my reaction as I saw you subscribe (give it ~5 seconds).
I thought you might enjoy…
See you next week.