Our Problem with Boxen

Posted 3 months back at blah blah woof woof articles

Over a year ago, we started using Boxen at Icelab to manage our team’s development environments. It’s worked as advertised, but not well enough. I’m looking for something else.

Our problem with Boxen is that it contains hundreds of different components, all of which are changing, all the time. It needs constant tending. By the time a team is big enough to need something like Boxen, it’s paradoxically too small to look after it properly: to have someone whose job it is to be “Boxenmaster,” someone who knows how these intricate parts all interact and can run the regular clean installs needed to make sure that the experience is smooth for new people (we’ve found it typical for a functional Boxen setup to stay working over repeated updates, while clean installs end up failing). We need a tool that we can set up once for a project and then have it still work reliably 6 months later when we revisit the project for further work.

Boxen can be a trojan horse. If you don’t look after it properly, you risk creating two classes of developers within your team: those who were around to get Boxen working when you first rolled it out, now enjoying their nice functional development environments, and those who get started later, whose first experience in the team is one of frustration, non-productivity and a disheartening, unapproachable web of interconnected packages. And no one is safe: as soon as you want to upgrade that version of PHP, you could slip down there too.

So while Boxen can indeed work as manager of personal development environments, and while Puppet is a serious and capable configuration manager, my recommendation is not to commit to Boxen half-heartedly. In fact, you may not even need something so rigorous and complex if your team is still small. I’m looking into such alternatives right now. I’m not settled on anything yet, but it’ll likely involve virtual machines, and perhaps use Docker as a way to keep it lightweight while working on multiple projects at a time. Fig seems like it could be a good fit. I’ll keep you posted.

Episode #465 - May 16th, 2014

Posted 3 months back at Ruby5

A rich text editor that isn't awful, over one thousand free programming books, handle email subscriptions and track emails sent, super easy email unsubscribe, and a cheatsheet for OAuth exploits.

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic


Quill is a modern rich text editor built for compatibility and extensibility. It was created by Jason Chen and Byron Milligan and open sourced by Salesforce.com.

Free Programming Books

A compilation of roughly 1,500 links to free programming-related resources.
Free Programming Books

OAuth Security Cheatsheet

This site describes common OAuth/Single Sign On/OpenID-related vulnerabilities.
OAuth Security Cheatsheet

Ahoy Email

Simple, powerful email tracking for Rails
Ahoy Email


Email subscriptions made easy

What to do when Stack Overflow is down?

Posted 3 months back at mir.aculo.us - Home

The Internet is awesome. Information at your fingertips and always-available help from people all over the world is one of humanity’s dreams come true. I’m not sure if the ancient philosophers included copy & pasting of code snippets in this dream, but it’s a fact of daily developer life.

It’s awesome, and it’s very convenient.

But this is not how you learn and become great at thinking for yourself, finding solutions for solving programming problems and most importantly how to be creative. Over-using sites like Stack Overflow will not make you a better developer, it will (probably) make you very good at clicking up-vote buttons and copy & pasting.

You owe it to your brain and future self that you try to find a solution first, and not give up just because something doesn’t work the first time you try it. Especially when you don’t feel comfortable or knowledgeable, because you’re working on a new project, with a new programming language or different development environment. Humans are built for exploration and understanding by doing. Your brain will reward you for discovering things. The rewards are higher as the problem is harder (for you) to solve.

That doesn’t mean to ban forums and answer sites from your bookmarks. You can and should share your discoveries and see how others solved similar problems. You’ll probably find that there’s (hope my cats won’t hear this) more than one way to skin a cat. Sharing will likely lead to new, better ways to tackle a specific problem, and this will benefit lots of people.

All because you spent 10 minutes thinking about a problem and not just copy & pasting the first answer that somewhat works.

Software Apprenticeship Podcast Episode 3 is Out

Posted 3 months back at Jake Scruggs

This week we start off by throwing Jonathan into the deep end of pool where he pairs with an experienced developer on a 10 year old Java project that is the core of our signature product: Backstop.  Of course the company is called Backstop Solutions and so, in order to avoid confusion, we gave the project a different name for internal use:  Fund Butter.  The mystery of how such a terrible thing came to pass is revealed in this very episode.

There’s no way we couldn’t discuss DHH’s Rails Conf declaration and blog post: “TDD is dead. Long live testing.” This, of course, leads to a discussion of our team’s test philosophy.

You can find it on iTunes (search for Software Apprenticeship Podcast), any podcast app’s search function, Google, this temp page: https://itunes.apple.com/us/podcast/software-apprenticeship-podcast/id868371146 or use the RSS feed directly if your into that sort of thing: http://softwareapprenticeship.libsyn.com/rss

Our panel (composed of Toby Tripp, Matt Pyra, Eric Johnson, Jonathan Howden, and I) meander through quite a few topics.  Here’s a breakdown by time of the various topics:

01:27 Backstop’s 2 day bug bash
02:00 The apprentice has to tackle a 10 year old Java program
06:22 “Everything needs to have an ID if you’re going to make it Hibernate-y” - Jake “super technical” Scruggs
08:21 Why we call Backstop “Fund Butter” within the company
10:50 The apprentice encounters Selenium
12:42 Troubles with regression/integration testing through the web browser.
13:43 “Unit Testing is Dead” - DHH 
20:00 Pairing all the time vs code review
21:51 Toby talks about the Hill Air Force Base pair programming study mentioned here: http://www.informit.com/articles/article.aspx?p=29410
26:40 The Wall of Awesome - Backstop’s way for employee’s to recognize and thank other employees
47:21 The anti-college movement
49:36 The “Expose your ignorance” apprenticeship pattern with examples/confessions from Jonathan, Jake, and Toby
51:14 The C3 project comes up with near 100% frequency when >= 2 die hard XP'ers are in the same room.

Episode #464 - May 13th, 2014

Posted 3 months back at Ruby5

In this episode we talk about new Ruby releases for versions 2.1.2 and 2.0.0-p48, Jekyll 2.0, Ruby core team disputing a CVE report, How Batched Queries work in Rails and FiniteMachine.

Listen to this episode on Ruby5

Sponsored by RailsLTS

With the release of Rails 4, support for Rails 2.3 and Rails 3.0 has ended. Security vulnerabilities are no longer patched for these versions. Rails LTS offers a solution for mission critical applications by providing security patches for old versions of Rails.
This episode is sponsored by RailsLTS

Ruby 2.1.2 and 2.0.0-p481

Late last week Ruby 2.1.2 was released alongside Ruby 2.0.0­-p481. Version 2.1.2 notably fixes a regression on the Hash#reject method.
Ruby 2.1.2 and 2.0.0-p481

Jekyll 2.0

Jekyll, the popular static site generator, released its 2.0 version last week. This new version is jam­-packed with highly­-requested features and bug fixes, thanks to the contribution of over 180 different developers.
Jekyll 2.0

Ruby CVE dispute

The Ruby core team is disputing an earlier CVE report. The CVE in question claimed that it was possible for an attacker to forge arbitrary root certificates by modifying the certificate’s signature. Apparently it’s simply a misunderstanding over the return value of the X509Certificate#verify method.
Ruby CVE dispute

How Batched Queries Work

Adam Sanderson wrote another article in his "Reading Rails" series titled 'How do Batched Queries Work', where he investigates Rails' find_each. The 'find_each' method is used to run queries when you don't want all the records instantiated at once.
How Batched Queries Work


FiniteMachine is a gem by Piotr Murach that provides a minimal finite state machine with a straightforward and intuitive syntax. The machine is event driven, with a focus on passing synchronous and asynchronous messages to trigger state transitions. It supports a natural DSL for declaring events, exceptions and callbacks.

Baseimage-docker 0.9.11 released

Posted 3 months back at Phusion Corporate Blog

Baseimage-docker is a special Docker image that is configured for correct use within Docker containers. It is Ubuntu, plus modifications for Docker-friendliness. You can use it as a base for your own Docker images. Learn more at the Github repository and the website, which explain in detail what the problems are with the stock Ubuntu base image, and why you should use baseimage-docker.

Changes in this release

  • Upgraded to Ubuntu 14.04 (Trusty). We will no longer release images based on 12.04.
    Thanks to contributions by mpeterson, Paul Jimenez, Santiago M. Mola and Kingdon Barrett.
  • Fixed a problem with my_init not correctly passing child processes’ exit status. Fixes GH-45.
  • When reading environment variables from /etc/container_environment, the trailing newline (if any) is ignored. This makes commands like this work, without unintentially adding a newline to the environment variable value:
    echo my_value > /etc/container_environment/FOO

    If you intended on adding a newline to the value, ensure you have two trailing newlines:

    echo -e "my_value\n" > /etc/container_environment/FOO
  • It was not possible to use docker run -e to override environment variables defined in /etc/container_environment. This has been fixed (GH-52). Thanks to Stuart Campbell for reporting this bug.

Using baseimage-docker

Please learn more at the README.

Baseimage-docker 0.9.10 released

Posted 3 months back at Phusion Corporate Blog

Baseimage-docker is a special Docker image that is configured for correct use within Docker containers. It is Ubuntu, plus modifications for Docker-friendliness. You can use it as a base for your own Docker images. Learn more at the Github repository and the website, which explain in detail what the problems are with the stock Ubuntu base image, and why you should use baseimage-docker.

Changes in this release

  • Upgraded to Ubuntu 14.04 (Trusty). We will no longer release images based on 12.04.
    Thanks to contributions by mpeterson, Paul Jimenez, Santiago M. Mola and Kingdon Barrett.
  • Fixed a problem with my_init not correctly passing child processes’ exit status. Fixes GH-45.
  • When reading environment variables from /etc/container_environment, the trailing newline (if any) is ignored. This makes commands like this work, without unintentially adding a newline to the environment variable value:
    echo my_value > /etc/container_environment/FOO

    If you intended on adding a newline to the value, ensure you have two trailing newlines:

    echo -e "my_value\n" > /etc/container_environment/FOO
  • It was not possible to use docker run -e to override environment variables defined in /etc/container_environment. This has been fixed (GH-52). Thanks to Stuart Campbell for reporting this bug.

Using baseimage-docker

Please learn more at the README.

The post Baseimage-docker 0.9.10 released appeared first on Phusion Corporate Blog.

Docker-friendly Vagrant boxes 2014-05-11 released

Posted 3 months back at Phusion Corporate Blog


We provide Vagrant base boxes that are based on Ubuntu 14.04 and 12.04, 64-bit. These boxes are specifically customized to work well with Docker. Please learn more at the website

The changes in version 2014-05-11 are:

  • The Ubuntu 12.04 boxes have been upgraded to kernel 3.13 (Trusty kernel). This is because even the updated VMWare Tools still occasionally caused kernel panics on kernel 3.8. In our tests, we’ve observed that VMWare Tools does not cause any kernel panics on kernel 3.13.
  • No changes in the Ubuntu 14.04 boxes.

Related resources: Github | Prebuilt boxes | Vagrant Cloud | Discussion forum | Twitter

Upgrade instructions for Vagrant >= 1.5 with Vagrant Cloud


vagrant box outdated

Upgrade instructions for Vagrant <= 1.4, or Vagrant >= 1.5 without Vagrant Cloud

Destroy your Vagrant VM:

vagrant destroy

Remove your existing base box:

# Vagrant >= 1.5
vagrant box remove phusion-open-ubuntu-12.04-amd64 --provider virtualbox
vagrant box remove phusion-open-ubuntu-12.04-amd64 --provider vmware_fusion

# Vagrant <= 1.4
vagrant box remove phusion-open-ubuntu-12.04-amd64 virtualbox
vagrant box remove phusion-open-ubuntu-12.04-amd64 vmware_fusion

Start your VM again. Vagrant will automatically download the latest version of the box.

vagrant up

Back to Basics: Regular Expressions


Regular expressions have been around since the early days of computer science. They gained widespread adoption with the introduction of Unix. A regular expression is a notation for describing sets of character strings. They are used to identify patterns within strings. There are many useful applications of this functionality, most notably string validations, find and replace, and pulling information out of strings.

Regular expressions are just strings themselves. Each character in a regular expression can either be part of a code that makes up a pattern to search for, or it can represent a letter, character or word itself. Let’s take a look at some examples.


First let’s look at an example of a regular expression that is made up of only actual characters and none of the special characters or patterns that generally make up regular expressions.

To get started let’s fire up irb and create our regular expression:

> regex = /back to basics/
 => /back to basics/

Notice we create a regular expression by entering a pattern between two front slashes. The pattern we’ve used here will only match strings that contain the stringi ‘back to basics’. Let’s use the match method, which gives us information about the first match it finds, to look at some examples of what matches and what doesn’t:

> regex.match('basics to back')
 => nil

We’re getting close, but nothing in this string matches our regular expression, so we get nil.

> regex.match('i enjoyback to basics')
 => <MatchData "back to basics">

After an unsuccessful attempt we have a match. Notice that our regular expression matched even though there are no spaces between the pattern and the words before it.


The object returned from the RegularExpression object’s match method is of type MatchData. This object can tell us all sorts of things about a particular match. Let’s take a look at some of the information we can get about our match.

We can use the begin method to find out the offset of the beginning of our match in the original string:

> match = regex.match('i enjoyback to basics')
 => <MatchData "back to basics">

> match.begin(0)
 => 7

> 'i enjoyback to basics'[7]
 => "b"

The argument we send the method can be used to specify a capture, a concept which is covered below, within our match. In our above example begin tells us that the beginning of our match can be found at index 7 in our string. As we can see from the code above the 8th character in the string (at the 7th index in our string) is ‘b’ the first letter of our match.

Similarly we can get the index of the character following the end of our match using the end method:

> match.end(0)
 => 21

> 'i enjoyback to basics'[21]
 => nil

In this case we get nil since the end of our match is also the end of our string.

We can also use the to_s method to print our match:

> match.to_s
 => "back to basics"


The regular expression’s real power becomes obvious when we introduce patterns. Let’s take a look at some examples.


A metacharacter is any character that has a meaning within a regular expression. Let’s start with something simple, let’s say we want to find out if our string contains a number. This will require we use our first pattern the \d, which is a metacharacter that says we’re looking for any digit:

> string_to_match = 'back 2 basics'

> regex = /\d/
 => /\d/

> regex.match(string_to_match)
 => <MatchData "2">

Our regular expression matches the number 2 in our string.

Character Classes

Let’s say we wanted to find out if any of the letters from ‘k’ to ’s' were in our string. This will require we use a character class. A character class let’s us specify a list of characters or patterns that we’re looking for:

> string_to_match = 'i enjoy making stuff'

> regex = /[klmnopqrs]/
 => /[klmnopqrs]/

> regex.match(string_to_match)
 => <MatchData "n">

In this example we can see we entered all the letters of the alphabet we were interested in between the brackets and the first instance of any of those characters results in a match. We can simplify the above regular expression by using a range. This is done by entering two character or numbers separated by a -:

> string_to_match = 'i enjoy making stuff'

> regex = /[k-s]/
 => /[k-s]/

> regex.match(string_to_match)
 => <MatchData "n">

As expected, we get the same results with our simplified regular expression.

It’s also possible to invert a character class. This is done by adding a ^ to the beginning of the pattern. If we wanted to look for the first letter not in between ‘k’ and ’s' we would use the pattern /[^k-s]/:

> string_to_match = 'i enjoy making stuff'

> regex = /[^k-s]/
 => /[^k-s]/

> regex.match(string_to_match)
 => <MatchData "i">

Since ‘i’ isn’t in our range the first letter in our string meets the criteria our regular expression specified.

Another thing worth noting is the \d character we used above is an alias for the character class [0-9].


We have the ability to set a regular expression’s matching mode via modifiers. In Ruby this is done by appending characters after the regular expression pattern is defined. A particularly useful matching modifier is the case insensitive modifier i. Let’s take a look:

> string_to_match = 'BACK to BASICS'

> regex = /back to basics/i
 => /back to basics/i

> regex.match(string_to_match)
 => <MatchData "BACK to BASICS">

The regular expression matches our string in spite of the fact that the cases are clearly not the same. We’ll look at another common modifier later on in the blog.


Repetitions give us the ability to look for repeated patterns. We are given the ability to broadly search for that are repeating an indiscriminate number of time, or we can get as granular as the exact number of repetitions we’re looking for.

Let’s try to identify all the numbers in a string again:

> string_to_match = 'The Mavericks beat the Spurs by 21 in game two.'

> regex = /\d/
 => /\d/

> regex.match(string_to_match)
 => <MatchData "2">

Because we used only a single \d we only got the first digit, in this case ‘2’. What we’re actually looking for is the entire number, not just the first digit. We can fix this by modifying our pattern. We need to specify a pattern that will say find any group of contiguous digits. For this we can use the + metacharacter. This tells the regular expression engine to find one or more of the character or characters that match the previous pattern. Let’s take a look:

> string_to_match = 'The Mavericks beat the Spurs by 21 in game two.'

> regex = /\d+/
 => /\d+/

> regex.match(string_to_match)
 => <MatchData "21">

We could also look for an exact number of repetitions. Let’s say we only wanted to look for numbers between 100 and 999. One way we could do that would be using the {n} patern, where n indicates the number of repetitions we’re looking for:

> string_to_match = 'In 30 years the San Francisco Giants have had two 100 win seasons.'

> regex = /\d{3}/
 => /\d{3}/

> regex.match(string_to_match)
 => <MatchData "100">

Our pattern doesn’t match 30, but does match 100 because we told it only three repeating digit characters constituted a match.

Let’s look for words that are only longer than five characters. This will require a new metacharacter, the \w that matches any word character. Then we’ll use the {n,} pattern, which says look for n or more of the previous pattern:

> string_to_match = 'we are only looking for long words'

> regex = /\w{5,}/
 => /\w{5,}/

> regex.match(string_to_match)
 => <MatchData "looking">

You can also specify less than using this pattern {,m} and in between with this {n,m}.


Grouping gives us the ability to combine several patterns into one single cohesive unit. This can be very useful when combined with repetitions. Earlier we looked at using repetitions with a single metacharacter \d, but rarely will that be enough to satisfy our needs. Let’s look at how we could define a more complex pattern we expect to see repeated.

Let’s look at how we might create a more complicated regular expression that matches phone numbers in several different formats. We’ll use groups and repetitions to do this:

> phone_format_one = '5125551234'
 => "5125551234"

> phone_format_two = '512.555.1234'
 => "512.555.1234"

> phone_format_three = '512-555-1234'
 => "512-555-1234"

regex = /(\d{3,4}[.-]{0,1}){3}/
 => /(\d{3,4}[\.-]{0,1}){3}/

> regex.match(phone_format_one)
 => <MatchData "5125551234" 1:"234">

> regex.match(phone_format_two)
 => <MatchData "512.555.1234" 1:"1234">

> regex.match(phone_format_three)
 => <MatchData "512-555-1234" 1:"1234">

We have successfully created our regular expression, but there is a lot going on there. Let’s break it down. First we define that our pattern will be made up of groups of three or four digits with this \d{3,4}. Next we indicate that we want to allow for ‘-’ or ‘.’ patterns (we have to escape the ‘.’ because this character is also a metacharacter that acts as a wild card), but that we don’t want to require these characters with this pattern [\.-]{0,1}. Finally we say we need three of this group of patterns by grouping the previous two patterns together and apply a repetition of three (\d{3,4}[.-]{0,1}){3}.

Lazy and Greedy

Regular expressions are by default greedy, which means they’ll find the largest possible match. Often that isn’t the behavior we’re looking for. When creating our patterns it’s possible to tell Ruby we’re looking for a lazy match, or the first possible match that satisfies our pattern.

Let’s look at an example. Let’s say we wanted to parse out the timestamp of a log entry. We’ll start out just trying to grab everything in between the square brackets that we know our log is configured to output the date in. In this pattern we’ll use a new metacharacter. The . is a wildcard in a regular expression:

> string_to_match = '[2014-05-09 10:10:14] An error occured in your application. Invalid input [foo] received.'

> regex = /\[.+\]/
 => /\[.+\]/

> regex.match(string_to_match)
 => <MatchData "[2014-05-09 10:10:14] An error occured in your application. Invalid input [foo]">

Instead of matching just the text in between the first two square brackets it grabbed everything between the first instance of an opening square bracket and the last instance of a closing square bracket. We can fix this by telling the regular expression to be lazy using the ? metacharacter. Let’s take another shot:

> string_to_match = '[2014-05-09 10:10:14] An error occured in your application. Invalid input [foo] received.'

> regex = /\[.+?\]/
 => /\[.+?\]/

> regex.match(string_to_match)
 => <MatchData "[2014-05-09 10:10:14]">

Notice that we added our ? after our repetition metacharacter. This tells the regular expression engine to keep looking for the next part of the pattern only until it finds a match; not until it finds the last match.


Assertions are part of regular expressions that do not add any characters to a match. They just assert that certain patterns are present, or that a match occurs at a certain place within a string. There are two types of assertions, let’s take a closer look.


The simplest type of assertion is an anchor. Anchors are metacharacters that let us specify positions in our patterns. The thing that makes these metacharacters different is they don’t match characters only positions.

Let’s look at how we can determine if a line starts with Back to Basics using the ^ anchor, which denotes the beginning of a line:

> multi_line_string_to_match = <<-STRING
"> I hope Back to Basics is fun to read.
"> Back to Basics is fun to write.
 => "I hope Back to Basics is fun to read.\nBack to Basics is fun to write.\n"

> regex = /^Back to Basics/
 => /^Back to Basics/

> regex.match(multi_line_string_to_match)
 => <MatchData "Back to Basics">

> match.begin(0)
 => 38

Looking at where our match begins we can see it’s the second instance of the string “Back to Basics” we’ve matched. Another thing to take note of is the ^ anchor doesn’t only match the beginning of a string, but the beginning of a line within a string.

There are many anchors available. I encourage you to review the Regex documentation and check out some of the others.


The second type of assertion is called a lookaround. Lookarounds allow us to provide a pattern that must be matched in order for a regular expression to be satisified, but that will not be included in a successful match. These are called lookahead and lookbehind patterns.

Let’s say we had a comma delimited list of companies and the year they were founded. Let’s match the year that thoughtbot was founded. In this case we only want the year, we’re not interested in including the company in the match, but we’re only interestedin thougtbot, not the other two companies. To do this we’ll use a positive lookbehind. This means we’ll provide a pattern we expect to appear before the pattern we want to match.

> string_to_match = 'Dell: 1984, Apple: 1976, thoughtbot: 2003'

> regex = /(?<=.thoughtbot: )\d{4}/
 => /(?<=.thoughtbot: )\d{4}/

> regex.match(string_to_match)
 => <MatchData "2003">

Even though the pattern we use to assert the word thoughtbot preceeds our match appears in our regular expression it isn’t included in our match data. This is exactly the behavior we were looking for.

To specify a positive lookbehind we use the ?<=. If we wanted to use a negative lookbehind, meaning the match we want isn’t preceed by some particular text we would use ?<!=.

To do a positive lookahead we use ?=. A negative look ahead is achieved using ?!=.


Another useful tool is called a capture. This gives us the ability to match on a pattern, but only captures parts of the pattern that are of interest to us. We accomplish this by surrounding the pattern data we intend to capture with parenthesis, which is also how we specify a group. Let’s look at how we might pull the quantity and price for an item off of an invoice:

> string_to_match = 'Mac Book Pro - Quantity: 1 Price: 2000.00'

> regex = /[\w\s]+ - Quantity: (\d+) Price: ([\d\.]+)/
 => /[\w\s]+ - Quantity: (\d+) Price: ([\d\.]+)/ 

> match = regex.match(string_to_match)
 => <MatchData "Mac Book Pro - Quantity: 1 Price: 2000.00" 1:"1" 2:"2000.00"> 

> match[0]
 => "Mac Book Pro - Quantity: 1 Price: 2000.00" 

> match[1]
 => "1"

> match[2]
 => "2000.00"

Notice we have all the match data in an array. The first element is the actual match and the second two are our captures. We indicate we want something to be captured by surrounding it in parentheses.

We can make working with captures simpler by using what is called a named capture. Instead of using the match data array we can provide a name for each capture and access the values out of the match data as a hash of those names after the match has occurred. Let’s take a look:

> string_to_match = 'Mac Book Pro - Quantity: 1 Price: 2000.00'

> regex = /[\w\s]+ - Quantity: (?<quantity>\d+) Price: (?<price>[\d\.]+)/
 => /[\w\s]+ - Quantity: (?<quantity>\d+) Price: (?<price>[\d\.]+)/

> match = regex.match(string_to_match)
 => <MatchData "Mac Book Pro - Quantity: 1 Price: 2000.00" quantity:"1" price:"2000.00">

> match[:quantity]
 => "1"

> match[:price]
 => "2000.00"


There are also some useful functions that take advantage of regular expressions in the String class. Let’s take a look at some of the things we can do.

sub and gsub

The sub and gsub methods both allow us to provide a pattern and a string to replace instances of that pattern with. The difference between the two methods is that gsub will replace all instances of the pattern, while sub will only replace the first instance.

The gsub method gets its name from the fact that matching mode (discussed above) is set to global, which is accomplished using the modifier code g hence the name.

Let’s take a look at some examples.

> string_to_match = "My home number is 5125551234, so please call me at 5125551234."
 => "My home number is 5125551234, so please call me at 5125551234."

> string_to_match.sub(/5125551234/, '(512) 555-1234')
 => "My home number is (512) 555-1234, so please call me at 5125551234."

When we use sub we can see we still have one instance of our phone number that isn’t formatted. Let’s use gsub to fix it.

> string_to_match.gsub(/5125551234/, '(512) 555-1234')
 => "My home number is (512) 555-1234, so please call me at (512) 555-1234."

As expected gsub replaces both instances of our phone number.

While our previous example demonstrates the way the functions work it isn’t a particularly useful regular expression. If we were trying to format all the phone numbers in a large document we obviously couldn’t make our pattern the number in each case, so let’s revisit our example and see if we can make it more useful.

> string_to_match = "My home number is 5125554321. My office number is 5125559876."
 => "My home number is 5125554321. My office number is 5125559876." 

> string_to_match.gsub(/(?<area_code>\d{3})(?<exchange>\d{3})(?<subscriber>\d{4})/, '(\k<area_code>) \k<exchange>-\k<subscriber>')
 => "My home number is (512) 555-4321. My office number is (512) 555-9876."

Now our regular expression will format any phone number in our string. Notice that we take advantage of named captures in our regular expression and use them in our replacement by using \k.


The scan method lets pull all reular expression matches out of a string. Let’s look at some examples.

> string_to_scan = "I've worked in TX and CA so far in my career."
 => "I've worked in TX and CA so far in my career." 

> string_to_scan.scan(/[A-Z]{2}/)
 => ["TX", "CA"]

Using a regular expression we pull out all the state codes in our string. One thing to keep in mind as you continue to learn is pay close attention to the assorted metacharacters available and how their meanings change depending context. Just in this introductory blog we saw multiple meaings for both the ^ and ? character and we didn’t even cover all of the possible meanings of even those two characters. Sorting out when each metacharacter means what is one of the more difficult parts of mastering regular expressions.

Regular expressions are one of the most powerful tools we have at our disposal with Ruby. Keep them in mind as you code and you’ll be surprised how often they can provide a nice clean solution to an otherwise daunting task!

What’s next?

If you found this useful, you might also enjoy:

Episode #463 - May 9th, 2014

Posted 3 months back at Ruby5

Untangline spaghetti code, opening the Atom source, better presenters with DumbDelegator, managing your OS X setup with osxc, an intro to Rails view caching, and the Eldritch async DSL all in this episode of the Ruby5!

Listen to this episode on Ruby5

Sponsored by New Relic

New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
This episode is sponsored by New Relic

Untangle Spaghetti Code

This article from Justin Weiss walks you through a refactoring that cleans up the code by reversing the caller and callee.
Untangle Spaghetti Code

Atom is OSS

The Atom editor is now open source!
Atom is OSS


The dumb_delegator gem is a delegator implementation specifically designed to work with Rails url helpers.


Tired of reinstalling things manually when you get a new machine? The osxc project will make this process a breeze for OS X machines!

Rails Caching

Want to start caching in Rails but aren't sure how to go about it? This two part blog post from Greg Molnar will tee you up!
Rails Caching


Eldritch is a DSL to make parallel programming easier in Ruby. Asynchronousness has never been easier!

Tips for Clojure Beginners


1. Learn the essentials with Clojure Koans.

Clojure Koans teaches you the basics of the language by providing a series of tests for you to turn green.

The topics and tests are chosen well, and the project’s vibe is pleasant (“calling a function is like giving it a hug with parentheses”).

Open a koan. Make it pass. Meditate. Enjoy enlightenment.

2. Move on to 4Clojure problems.

4Clojure is a great way to become familiar with Clojure’s many built-in functions.

Make sure to register an account and follow a handful of the Top Users. This will let you compare your solutions to theirs and be suitably mindblown.

A word of warning: 4Clojure tends to encourage code golf. Shorter is not always better.

For the longer problems, you may prefer to work in your editor. Check out offline-4clojure to get a local copy of the problems and tests.

3. Read a book or two.

Clojure Programming and The Joy of Clojure are both great places to start.

Clojure Programming is approachable, well-written, and no-nonsense. In particular, the examples are well-chosen and understandable.

The Joy of Clojure is also excellent, but takes more mental horsepower to get through. Its examples are perhaps more realistic, but thus more complicated and harder to follow.

4. Learn to develop interactively from your editor.

As a Rubyist, I’m used to running tests from my editor, and would never adopt a workflow that forced me to switch to the shell to run my tests. Additionally, I use the Spring pre-loader because rebooting the application every time I make a make a change and want to test it is painful. The ability to get test feedback quickly, and in the same place I’m writing them, contributes greatly to my flow and sense of happiness.

Despite this, when I want to interact with a running version of my application, it’s off to the Rails console I go. I write code “over here,” but interact with my running application “over there.”

Clojurians eschew this separation.

When writing Clojure, I can connect my editor to an instance of my running application that sticks around. When I change a function, I instruct that persistent application session to simply use the new function without restarting or reloading.

Further, when I want to see how the system behaves there’s no need to head off to some “over there” place. Instead, I can evaluate Clojure code in the context of my running application right from Vim, with results displayed wherever I might want them.

I had read descriptions of this development style and felt somewhat underwhelmed, but getting this set up and working really changed how much I enjoyed writing Clojure. Make sure you at least give this an honest shot before moving on.

  • Vim users: to get this experience, install Tim Pope’s fireplace.vim and read enough of the docs to learn how to eval code and open an in-editor REPL. Outdated resources might point you to VimClojure, but it is abandonware and should be avoided.

  • Emacs users: cider is what you’re looking for.

  • LightTable users: your editor does this out of the box! How enlightened of it. Check your docs for details, or just start on David Nolen’s interactive ClojureScript tutorial.

  • Users of other editors: you probably want to google something like [your-editor-name nrepl server].

5. Absorb Clojure’s philosophies and motivations with conference talks.

One of my favorite parts of the Clojure ecosystem is how many excellent conference talks are available. Three great examples, all from Rich Hickey, creator of Clojure:

  • Are We There Yet? - Rich asks whether OO as we practice it today is the best we can do. Spoiler: he thinks not. A great starting place to understand Clojure design motivations.

  • The Value of Values - Immutable data structures are a key element in Clojure’s design. This talk gives a great overview of their rationale and characteristics.

  • Simple Made Easy - Required viewing, if only because “complect” and “simple, in the Rich Hickey sense” are terms you’ll hear community members use often.

The above are some of my favorites, but I’ve been pleasantly surprised at the high quality of most Clojure talks I’ve watched, so don’t hestitate to dive into whatever looks interesting. For lots of options, check out the ClojureTV YouTube channel.

Bonus tip: I find I can watch most talks at 1.5x without a loss of comprehension. Enjoy that 40-minute talk in just 26!

6. Ask for help when stuck.

I’ve had good luck getting unstuck by asking for help in #clojure on freenode (IRC), reaching out to library authors directly on Twitter (thanks @swannodette, @weavejester, and @cemerick!), and the usual swearing/staring/source-diving that is sofware development.

7. Don’t panic.

Chances are, you’re coming to Clojure from an object-oriented languge with mutable data structures. Moving to a functional language with immutable data is a significant change of paradigm, and will take some getting used to. This is normal. Don’t feel bad if you struggle early on. I certainly did (and often still am)!

Episode #462 - May 6th, 2014

Posted 3 months back at Ruby5

Good news from the Ruby Core meeting, TDD debates galore, AdequateRecord, and some surprisingly uneventful code ping pong this week.

Listen to this episode on Ruby5

Sponsored by Pull Review

You want to ship it right instead of doing it again. But what could you clean while still meeting the deadline? PullReview reviews the Ruby code you just wrote and tells you what's wrong, why, and how to fix it - from style to security. Code, Spot, Fix, and Ship!
This episode is sponsored by Pull Review

Ruby Core Meeting

The Ruby Core Developer meeting took place in Japan and Terence Lee was kind enough to let us know what happened. Team Matz is considering accelerating the release schedule for Ruby patch releases. So that would be things like 2.1.1, and 2.1.2 as opposed to waiting for a 2.2 release. It would allow them to tackle bugs that cause dreaded segmentation faults much faster. To achieve this, Shibata Hiroshi & Koichi Sasada will work on a CI environment in order to make the release process easier. They also discussed removing commits that are not directly relevant to a patch release (or hotfix) before a the release goes out, probably in order to avoid potential regressions in those releases. By the way, since Ruby 2.1.0 was released, the core team announced that they would not release versions with patch­levels anymore. So no more obscure versions like 1.9.3­p545? Finally dear listeners, remember that feature suggestions for Ruby 2.2 are still being accepted so if you’ve ever wanted to give back to your favorite language, you should head over to bugs.ruby­lang.org right now.
Ruby Core Meeting

RailsConf Keynote & Videos

RailsConf was less than two weeks ago and the good people at Confreaks already have David Heinemeier Hansson’s keynote along with a handful of other talks available on their site. There’s another part of that talk that was a little less talked about: the part about David’s confession his inability to ever become a computer scientist. Although it was overshadowed by his knack for controversy, I think it was really interesting to hear such a prominent programmer — whatever you think of him — describe himself more as a software writer with affinities towards humanities instead of sciences.
RailsConf Keynote & Videos

TDD Counterpoints

So speaking of the TDD controversy, a number of prominent voices in the community have by now responded to his allegations that TDD for instance hinders design, is not necessary, etc. Robert Martin a.k.a Uncle Bob, was one of the first to respond with several blog posts actually. While deploring DHH’s rhetoric at first, he reiterated the benefits of TDD in a first post. As DHH continued aboard his TDD hate train, it was more like a blog ping pong than a code one. That’s about when it got interesting for me, right when Gary Bernhardt chimed in. On top of that yesterday, both Martin Fowler and Corey Haines joined in the merry battle of giants.
TDD Counterpoints

Duplication in Tests is Sometimes Good

Continuing down the testing path, this weekend Jakub Arnold published a short­yet­useful post entitled, “Duplication in Tests is Sometimes Good.”. I presume that you’re writing tests for your application or library. And I further presume you’re using a framework with before and after test hooks, like RSpec. People often use those hooks to clean up their test code, pulling out common setup and configuration. Is it possible that you can extract too much of that setup and configuration? Perhaps to the point of making your tests hard to understand? As Jakub shows, some duplication can be good. It’s not always bad to repeat ���yourself, especially if the repetition is easily updated with a find and replace.
Duplication in Tests is Sometimes Good


I think a much more important thing than dislike of TDD happened at RailsConf. I’m sad that not enough people have talked about Aaron Patterson’s Keynote. He spent quite a bit of time explaining the hard work that was put into speeding up ActiveRecord for the upcoming 4.2 release of Rails. He showed multiple benchmarks of the AdequateRecord branch and how in many ways it’s even faster than back in the Rails 2.3 days. So while the video for Aaron’s talk wasn’t available at the time of this recording, we highly recommend you watch it on Confreaks when it comes out. By the way, AdequateRecord has already been merged into rails/master on GitHub so you can already test it out if you like your edge really really bleedy.

Code Ping Pong with DHH - The Aftermath

And finally, to wrap up a TDDHH­filled episode, yesterday, Marcin Stecki published an article on the netguru blog describing some of the background for and aftermath from creating the Code Ping Pong with DHH site. In summation, the Rails 4 app was built on a whim, the source is available on GitHub, DHH didn’t know about it before hand, yet he did agree to respond to a handful of entries, DHH’s tweets brought several thousand eyes to the site, and ultimately Marcin was confused. As he put it, people poop on Rails all the time, but when presented with an avenue for presenting “bad code” to DHH for his thoughts, almost no one had any concrete examples. I think they got about 11 submissions ... and most of them weren’t even serious. Ultimately, only three entries were presented to David. Three submissions were presented to DHH... and David’s refactorings won the popular opinion vote for all three. Anyway, it is actually quite impressive to me that David volunteered his time for this, especially since he had nothing to do with its setup or concept. I appreciate that he gave his time and attention to what could’ve easily been seen as being silly and just ignored. So, thanks, David and Marcin!
Code Ping Pong with DHH - The Aftermath

Sponsored by Ruby5

Ruby5 is released Tuesday and Friday mornings. To stay informed about and active with this podcast, we encourage you to do one of the following:

Thank You for Listening to Ruby5

More new recruits

Posted 3 months back at RicRoberts :

Software engineer and web developer, Alex Lynham, is a Ruby enthusiast with particular expertise in front-end development but with ability throughout the stack. A speaker at NWRUG, he is also a fan of Python and JavaScript and divides his time between his love for programming and freelance music journalism.

Nicolas Terpolilli joins us from l’école Centrale de Lille for the summer. A software engineer, and devotee of Open Data, he’s a founder of rawdatahunter where he writes news and musings on Open Data.

And, on a contracting basis, we’ve been delighted to have Robin Gower with us since March. Robin has considerable software developing experience and is skilled at both front and back-end, development. And if that wasn’t enough, he’s also an economist and information analyst. Clever clogs.

You can see the rest of our team here.

Document Explicit Dependencies Through Tests


One of the purposes of writing tests is to provide living documentation of application’s code. Tests provide real examples of how a certain class or function is supposed to be used. Tests could also document the exact dependencies of the tested code.

The Problem

When Rails boots it loads most, if not all, of the application’s code, along with all of the dependencies (gems). Because of this, there is no need to require dependencies in individual files that contain application logic. When looking at the source of a specific class, it is hard to tell what external code it depends on. The test doesn’t help either.

A typical RSpec test usually looks something like this:

require 'spec_helper'

describe StyleGuide do
  # actual tests omitted

In the Rails community, it has become a de facto standard to require the default spec_helper (or an equivalent) in each test file. A typical spec/spec_helper.rb file ends up loading the whole Rails environment, requiring numerous helper files, and setting up various configuration options. All of that, en masse, is more than what any particular test file needs.

Certainly, integration and feature tests depend on the entire Rails environment. ActiveRecord model tests depend on the presence and configuration of a database. These are all good use cases for spec_helper. But what about unit tests that don’t require the database? When testing a plain old Ruby class, there might only be a few dependencies, if any.

The Solution

Being conscious about what must be required for a particular source file is a good thing. Instead of loading everything but the kitchen sink through the spec_helper, let’s specify the minimum dependencies inside of the test.

Here’s a revision of our code from above:

require 'basic_spec_helper'
require 'rubocop'
require 'app/models/style_guide'

describe StyleGuide do
  # actual tests omitted

This code states exactly what the tested class (app/models/style_guide.rb) depends on: the gem rubocop and basic_spec_helper.rb file.

The idea behind basic_spec_helper is that it’s very minimal, and that its sole purpose is to do a few convenience things. It should avoid becoming a junk drawer like spec_helper.

Here’s an example of a basic spec helper, extracted from Hound:

$LOAD_PATH << File.expand_path('../..', FILE)

require 'webmock/rspec'

RSpec.configure do |config|
  config.expect_with :rspec { |c| c.syntax = :expect }
  config.order = 'random'

This lightweight spec helper does just enough to enforce good practices and setup some configuration that should apply to all of the tests. Here’s the quick breakdown of what this spec helper is doing:

  1. Add the project root to the load path to allow requiring files starting at the project root.

    $LOAD_PATH << File.expand_path('../..', __FILE__)
  2. Requires webmock/rspec to ensure that external requests are not allowed.

    require 'webmock/rspec'
  3. Provides preferred RSpec configuration that all tests should adhere to.

    RSpec.configure do |config|
      config.expect_with :rspec { |c| c.syntax = :expect }
      config.order = 'random'

Tests which might be part of a Rails application test suite, but don’t actually depend on Rails or ActiveRecord can now require this basic spec helper along with the essential gems and files. This causes each test to explicitly document dependencies of the tested code. Loading minimal dependencies during tests removes any magical coupling, helps with refactoring, saves time during debugging, and makes tests run faster.

What’s Next?

Want to learn more techniques about decoupling code away from Rails?

Minimum Viable Block Chain

Posted 3 months back at igvita.com

Cryptocurrencies, and Bitcoin in particular, have been getting a lot of attention from just about every angle: regulation, governance, taxation, technology, product innovation, and the list goes on. The very concept of a "peer-to-peer (decentralized) electronic cash system" turns many of our previously held assumptions about money and finance on their head.

That said, putting the digital currency aspects aside, an arguably even more interesting and far-reaching innovation is the underlying block chain technology. Regardless of what you think of Bitcoin, or its altcoin derivatives, as a currency and a store of value, behind the scenes they are all operating on the same basic block chain principles outlined by Satoshi Nakamoto:

We propose a solution to the double-spending problem using a peer-to-peer network. The network timestamps transactions by hashing them into an ongoing chain of hash-based proof-of-work, forming a record that cannot be changed without redoing the proof-of-work. The longest chain not only serves as proof of the sequence of events witnessed, but proof that it came from the largest pool of CPU power... The network itself requires minimal structure.

The block chain is agnostic to any "currency". In fact, it can (and will) be adapted to power many other use cases. As a result, it pays to understand the how and the why behind the "minimum viable block chain":

  • What follows is not an analysis of the Bitcoin block chain. In fact, I intentionally omit mentioning both the currency aspects, and the many additional features that the Bitcoin block chain is using in production today.
  • What follows is an attempt to explain, from the ground up, why the particular pieces (digital signatures, proof-of-work, transaction blocks) are needed, and how they all come together to form the "minimum viable block chain" with all of its remarkable properties.
I have learned long ago that writing helps me refine my own sloppy thinking, hence this document. Primarily written for my own benefit, but hopefully helpful to someone else as well. Feedback is always welcome, leave a comment below!

Securing transactions with triple-entry bookkeeping #

Alice and Bob are stamp collectors. It's nothing serious, and they're mostly in it for the social aspects of meeting others, exchanging stories, and doing an occasional trade. If both parties see something they like, they negotiate right there and then and complete the swap. In other words, it's a simple barter system.

Then, one day Bob shows up with a stamp that Alice feels she absolutely must have in her collection. Except there is a problem, because Bob is not particularly interested in anything that Alice has to offer. Distraught, Alice continues negotiating with Bob and they arrive at a solution: they'll do a one-sided transaction where Bob will give Alice his stamp and Alice will promise to repay him in the future.

Both Bob and Alice have known each other for a while, but to ensure that both live up to their promise (well, mostly Alice), they agree to get their transaction "notarized" by their friend Chuck.

They make three copies (one for each party) of the above transaction receipt indicating that Bob gave Alice a "Red stamp". Both Bob and Alice can use their receipts to keep account of their trade(s), and Chuck stores his copy as evidence of the transaction. Simple setup but also one with a number of great properties:

  1. Chuck can authenticate both Alice and Bob to ensure that a malicious party is not attempting to fake a transaction without their knowledge.
  2. The presence of the receipt in Chuck's books is proof of the transaction. If Alice claims the transaction never took place then Bob can go to Chuck and ask for his receipt to disprove Alice's claim.
  3. The absence of the receipt in Chuck's books is proof that the transaction never took place. Neither Alice nor Bob can fake a transaction. They may be able to fake their copy of the receipt and claim that the other party is lying, but once again, they can go to Chuck and check his books.
  4. Neither Alice nor Bob can tamper with an existing transaction. If either of them does, they can go to Chuck and verify their copies against the one stored in his books.

What we have above is an implementation of "triple-entry bookkeeping", which is simple to implement and offers good protection for both participants. Except, of course you've already spotted the weakness, right? We've placed a lot of trust in an intermediary. If Chuck decides to collude with either party, than the entire system falls apart.

Moral of the story? Be (very) careful about your choice of the intermediary!

Securing transactions with PKI #

Dissatisfied with the dangers of using a "reliably intermediary", Bob decides to do some research and discovers that public key cryptography can eliminate the need for an intermediary! This warrants some explanation…

Public-key cryptography, also known as asymmetric cryptography, refers to a cryptographic algorithm which requires two separate keys, one of which is secret (or private) and one of which is public. Although different, the two parts of this key pair are mathematically linked. The public key is used to encrypt plaintext or to verify a digital signature; whereas the private key is used to decrypt ciphertext or to create a digital signature.

The original intent behind using a third party (Chuck) was to ensure three properties:

  • Authentication: a malicious party can't masquerade as someone else.
  • Non-repudiation: participants can't claim that the transaction did not happen after the fact.
  • Integrity: the transaction receipt can't be modified after the fact.

Turns out, public key cryptography can satisfy all of the above requirements. Briefly, the workflow is as follows:

  1. Both Alice and Bob generate a set public-private keypairs.
  2. Both Alice and Bob publish their public keys to the world.
  3. Alice writes a transaction receipt in plaintext.
  4. Alice encrypts the plaintext of the transaction using her private key.
  5. Alice prepends a plaintext "signed by" note to the ciphertext.
  6. Both Alice and Bob store the resulting output.
Note that step #5 is only required when many parties are involved: if you don't know who signed the message then you don't know whose public key you should be using to decrypt it. This will become relevant very soon...

This may seem like a lot of work for no particular reason, but let's examine the properties of our new receipt:

  1. Bob doesn't know Alice's private key, but that doesn't matter because he can look up her public key (which is shared with the world) and use it to decrypt the ciphertext of the transaction.
  2. Alice is not really "encrypting" the contents of the transaction. Instead, by using her private key to encode the transaction she is "signing it": anyone can decrypt the ciphertext by using her public key, and because she is the only one in possession of the private key this mechanism guarantees that only she could have generated the ciphertext of the transaction.
How does Bob, or anyone else for that matter, get Alice's public key? There are many ways to handle distribution of public keys - e.g. Alice publishes it it on her website. We'll assume that some such mechanism is in place.

As a result, the use of public key infrastructure (PKI) fulfills all of our earlier requirements:

  • Bob can use Alice's public key to authenticate signed transaction by decrypting the ciphertext.
  • Only Alice knows her private key, hence Alice can't deny that the transaction took place - she signed it.
  • Neither Bob nor anyone else can fake or modify a transaction without access to Alice's private key.

Both Alice and Bob simply store a copy of the signed transaction and the need for an intermediary is eliminated. The "magic" of public key cryptography is a perfect match for their two-party barter system.

Balance = Σ(receipts) #

With the PKI infrastructure in place, Bob and Alice complete a few additional trades: Alice acquires another stamp from Bob and Bob picks up a stamp from Alice. They each follow the same steps as before to generate signed transactions and append them to their respective ledgers.

The records are secure, but there is a small problem: it's not clear if either party has an outstanding balance. Previously, with just one transaction, it was clear who owed whom (Alice owed Bob) and how much (one red stamp), but with multiple transactions the picture gets really murky. Are all stamps of equal value? If so, then Alice has a negative balance. If not, then it's anyone's guess! To resolve this, Alice and Bob agree on the following:

  • Yellow stamp is worth twice the value of a red stamp.
  • Blue stamp is equal in value to a red stamp.

Finally, to ensure that their new agreement is secure they regenerate their ledgers by updating each transaction with its relative value. Their new ledgers now look as follows:

With that, computing the final balance is now a simple matter of iterating through all of the transactions and applying the appropriate debits and credits to each side. The net result is that Alice owes Bob 2... units of value. What's a "unit of value"? It's an arbitrary medium of exchange that Alice and Bob have agreed on. Further, since "unit of value" doesn't roll off the tongue, Alice and Bob agree to call 1 unit of value as 1 chroma (plural: chroms).

All of the above seems trivial, but the fact that the balance of each party is a function of all of the receipts in the ledger has an important consequence: anyone can compute everyone's balance. There is no need for any trusted intermediaries and the system is trivial to audit. Anyone can traverse the full ledger, verify the trades, and figure out the outstanding balances of each party.

Multi-party transfers & verification #

Next, Bob stumbles across a stamp owned by John that he really likes. He tells John about the secure ledger he is using with Alice and asks him if he would be willing to do a trade where Bob transfers his balance with Alice as a method of payment - i.e. Bob gets the stamp from John, and Alice would owe John the amount she previously owed Bob. John agrees, but now they have dilemma. How exactly does Bob "transfer" his balance to John in a secure and verifiable manner? After some deliberation, they arrive at an ingenious plan:

Bob creates a new transaction by following the same procedure as previously, except that he first computes the SHA-256 checksum (a unique fingerprint) of the encrypted transaction he wants to transfer and then inserts the checksum in the "What" field of the new receipt. In effect, he is linking the new transfer receipt to his previous transaction with Alice, and by doing so, transfers its value to John.

To keep things simple, we'll assume that all transfers "spend" full value of the transaction being transfered. It's not too hard to extend this system to allow fractional transfers, but that's unnecessary complexity at this point.

With the new transaction in place, John makes a copy of the encrypted ledger for his safekeeping (now there are three copies) and runs some checks to verify its integrity:

  1. John fetches Alice's and Bob's public keys and verifies the first three transactions.
  2. John verifies that Bob is transferring a "valid" transaction:
    • The transaction that is being transferred is addressed to Bob.
    • Bob has not previously transfered the same transaction to anyone else.

If all the checks pass, they complete the exchange and we can compute the new balances by traversing the ledger: Bob has a net zero balance, Alice has a debit of 2 chroms, and John has a credit of 2 chroms (courtesy of Alice). Further, John can now take his new ledger to Alice and ask her for payment, and even though Alice wasn't present for their transaction, that's not a problem:

  • Alice can verify the signature of the new transfer transaction using Bob's public key.
  • Alice can verify that the transfer transaction is referencing one of her own valid transactions with Bob.
The above transfer and verification process is a pretty remarkable property of the system! Note that to make it all work, we need two enabling technologies: (a) use of PKI, which enables digital signature verification, and (b) the receipt ledger, which enables us to look at the full transaction history to verify balances and to link previous transactions to enable the transfer.

Satisfied with their ingenuity John and Bob part ways: Bob goes home with a new stamp and John with a new ledger. On the surface, everything looks great, but they've just exposed themselves to a challenging security problem... Can you spot it?

Double-spending and distributed consensus #

Shortly after completing the transaction with John, Bob realizes that they have just introduced a critical flaw into their system and one that he could exploit to his advantage if he acts quickly: both Bob and John have updated their ledgers to include the new transaction, but neither Alice nor anyone else is aware that it has taken place. As a result, there is nothing stopping Bob from approaching other individuals in his network and presenting them with an old copy of the ledger that omits his transaction with John! If he convinces them to do a transaction, just as he did with John, then he can "double-spend" the same transaction as many times as he wants!

Of course, once multiple people show up with their new ledgers and ask Alice for payment, the fraud will be detected, but that is of little consolation - John has already run away with his loot!

The double-spend attack was not possible when we only had two participants since in order to complete the transaction you'd verify and update both sets of books simultaneously. As a result, all ledgers were always in sync. However, the moment we added an extra participant we introduced the possibility of incomplete and inconsistent ledgers between all the participants, which is why the double-spend is now possible.

In CS speak, a two-party ledger provides "strong consistency", and growing the ledger beyond two parties requires some form of distributed consensus to mitigate double-spend.

The simplest possible solution to this problem is to require that all parties listed in the ledger must be present at the time when each new transaction is made, such that everyone can update their books simultaneously. An effective strategy for a small-sized group, but also not a scalable one for a large number of participants.

Requirements for a distributed consensus network #

Let's imagine that we want to scale our ledger to all stamp collectors around the globe such that anyone can trade their favorite stamps in a secure manner. Obviously, requiring that every participant must be present to register each transaction would never work due to geography, timezones, and other limitations. Can we build a system where we don't need everyone's presence and approval?

  1. Geography is not really an issue: we can move communication online.
  2. Timezone problems can be solved with software: we don't need each individual to manually update their ledgers. Instead, we can build software that can run on each participant's computer and automatically receive, approve, and add transactions to the ledger on their behalf.

In effect, we could build a peer-to-peer (P2P) network that would be responsible for distributing new transactions and getting everyone's approval! Except, unfortunately that's easier said than done in practice. For example, while a P2P network can resolve our geography and timezone problems, what happens when even just one of the participants goes offline? Do we block all transactions until they're back online?

Note that the "how" of building a P2P network is a massive subject in its own right: protocols and signaling, traversing firewalls and NATs, bootstrapping, optimizing how updates are propagated, security, and so on. That said, the low-level mechanics of building such a network are out of scope of our discussion... we'll leave that as an exercise for the reader.

Turns out, distributed consensus is a well studied problem in computer science, and one that offers some promising solutions. For example, two-phase commit (2PC) and Paxos both enable a mechanism where we only need the majority quorum (50%+) of participants to be present to safely commit a new transaction: as long as the majority has accepted the transaction the remainder of the group is guaranteed to eventually converge on the same transaction history.

That said, neither 2PC nor Paxos are sufficient on their own. For example, how would either 2PC or Paxos know the total number of participants in our P2P stamp-collector network when new participants are joining on a daily basis and others are disappearing without notice? If one of the prior participants is offline, are they offline temporarily, or have they permanently left the network? Similarly, there is another and an even more challenging "Sybil attack" that we must account for: there is nothing stopping a malicious participant from creating many profiles to gain an unfair share of voting power within our P2P network.

If the number of participants in the system was fixed and their identities were authenticated and verified (i.e. a trusted network), than both 2PC and Paxos would work really well. Alas, that is simply not the case in our ever changing stamp collector P2P network. Have we arrived at a dead end? Well, not quite…

One obvious solution to solve our dilemma is to eliminate the "distributed" part from the problem statement. Instead of building a P2P distributed system we could, instead, build a global registry of all stamp collectors that would record their account information, authenticate them and (try to) ensure that nobody is cheating by creating multiple identities, and most importantly, keep one shared copy of the ledger! Concretely, we could build a website where these trades can take place, and the website would then take care of ensuring the integrity and correct ordering of all transactions by recording them in its centralized database.

The above is a practical solution but, let's admit it, an unsatisfying one since it forces us to forfeit the peer-to-peer nature of our ledger system. It places all of the trust in a single centralized system and opens up an entirely new set of questions: what is the uptime, security and redundancy of the system; who maintains the system and what are their incentives; who has administrative access, and so on. Centralization brings its own set challenges.

Let's rewind and revisit some of the problems we've encountered with our P2P design:

  • Ensuring that every participant is always up to date (strongly consistent system) imposes high coordination costs and affects availability: if a single peer is unreachable the system cannot commit new transactions.
  • In practice we don't know the global status of the P2P network: number of participants, whether individuals are temporarily offline or decided to leave the network, etc.
  • Assuming we can resolve above constraints, the system is still open to a Sybil attack where a malicious user can create many fake identities and exercise unfair voting power.

Unfortunately, resolving all of the above constraints is impossible unless we relax some of the requirements: the CAP theorem tells us that our distributed system can't have strong consistency, availability, and partition tolerance. As a result, in practice our P2P system must operate under the assumption of weak(er) consistency and deal with its implications:

  • We must accept that some ledgers will be out of sync (at least temporarily).
  • The system must eventually converge on a global ordering (linearizability) of all transactions.
  • The system must resolve ledger conflicts in a predictable manner.
  • The system must enforce global invariants - e.g. no double-spends.
  • The system should be secure against Sybil and similar attacks.

Protecting the network from Sybil attacks #

Achieving consensus in a distributed system, say by counting votes of each participant, opens up many questions about the "voting power" of each peer: who is allowed to participate, do certain peers have more voting power, is everyone equal, and how do we enforce these rules?

To keep things simple, let's say everyone's vote is equal. As a first step, we could require that each participant sign their vote with their private key, just as they would a transaction receipt, and circulate it to their peers - signing a vote ensures that someone else can't submit a vote on their behalf. Further, we could make a rule that only one vote is allowed to be submitted. If multiple votes are signed by the same key then all of them are discarded - make up your mind already! So far so good, and now the hard part…

How do we know if any particular peer is allowed to participate in the first place? If all that's needed is just a unique private key to sign a vote, then a malicious user could simply generate an unlimited number of new keys and flood the network. The root problem is that when forged identities are cheap to generate and use, any voting system is easily subverted.

To solve this problem we need to make the process of submitting the vote "expensive". Either the cost of generating a new identity must be raised, or the very process of submitting a vote must incur sufficiently high costs. To make this concrete, consider some real-world examples:

  • When you show up to vote in your local government election, you are asked to present an ID (e.g. a passport) that is (hopefully) expensive to fake. In theory, nothing stops you from generating multiple fake IDs, but if the costs are high enough (monetary costs of making a fake, risk of being caught, etc), than the cost of running a Sybil attack will outweigh its benefits.
  • Alternatively, imagine that you had to incur some other cost (e.g. pay a fee) to submit a vote. If the cost is high enough, then once again, the barrier to running a large-scale Sybil attack is increased.

Note that neither of the above examples "solves" the Sybil attack completely, but they also don't need to: as long as we raise the cost of the attack to be larger than the value gained by successfully subverting the system, then the system is secure and behaves as intended.

Note that we're using a loose definition of "secure". The system is still open for manipulation, and the exact vote count is affected, but the point is that a malicious participant doesn't affect the final outcome.

Proof-of-work as a participation requirement #

Any user can easily (and cheaply) generate a new "identity" in our P2P network by generating a new private-public keypair. Similarly, any user can sign a vote with their private key and send it into the P2P network - that's also cheap, as the abundance of spam email in our inboxes clearly illustrates. Hence, submitting new votes is cheap and a malicious user can easily flood the network with as many votes as they wish.

However, what if we made one of the steps above expensive such that you had to expend significantly more effort, time, or money? That's the core idea behind requiring a proof-of-work:

  1. The proof-of-work step should be "expensive" for the sender.
  2. The proof-of-work step should be "cheap" to verify by everyone else.

There are many possible implementations of such a method, but for our purposes we can re-use the properties provided by the cryptographic hash functions we encountered earlier:

  1. It is easy to compute the hash value for any given message.
  2. It is expensive to generate a message that has a given hash value.

We can impose a new rule in our system requiring that every signed vote must have a hash value that begins with a particular substring - i.e. require a partial hash collision of, say, two zero prefix. If this seems completely arbitrary, that's because it is - stay with me. Let's walk through the steps to see how this works:

  1. Let's say a valid vote statement is a simple string: "I vote for Bob".
  2. We can use the same SHA-256 algorithm to generate a hash value for our vote.
    • sha256("I vote for Bob") → b28bfa35bcd071a321589fb3a95cac...
  3. The resulting hash value is invalid because it does not start with our required substring of two zeros.
  4. We modify the vote statement by appending an arbitrary string and try again:
    • sha256("I vote for Bob - hash attempt #2") → 7305f4c1b1e7...
  5. The resulting hash value does not satisfy our condition either. We update the value and try again, and again, and… 155 attempts later we finally get:
    • sha256("I vote for Bob - hash attempt #155") → 008d08b8fe...

The critical property of the above workflow is that the output of the cryptographic hash function (SHA-256 in this case) is completely different every time we modify the input: the hash value of the previous attempt does not tell us anything about what the hash value of the next attempt when we increment our counter - i.e. its a non-deterministic algorithm. As a result, generating a valid vote is not just "hard problem", but also one better described as a lottery where each attempt gives you a random output. Also, we can adjust the odds of the lottery by changing the length of the required prefix:

  1. Each character of the SHA-256 checksum has 16 possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.
  2. In order to generate a hash with a valid two zero prefix the sender will need 256 (162) attempts on average.
  3. Bumping the requirement to 5 zeros will require more than 1,000,000 (165) attempts on average… Point being, we can easily increase the cost and make the sender spend more CPU cycles to find a valid hash.
How many SHA256 checksums can we compute on a modern CPU? The cost depends on the size of the message, CPU architecture, and other variables. If you're curious, open up your console and run a benchmark: $> openssl speed sha.

The net result is that generating a valid vote is "expensive" for the sender, but is still trivial to verify for the receiver: the receiver hashes the transaction (one operation) and verifies that the checksum contains the required hash collision prefix... Great, so how is this useful for our P2P system? Above proof-of-work mechanism allows us to adjust the cost of submitting a vote such that the total cost of subverting the system (i.e. spoofing enough valid votes to guarantee a certain outcome) is higher than the value gained by attacking the system.

Note that the "high cost to generate a message" is a useful property in many other contexts. For example, email spam works precisely because it is incredibly cheap to generate a message. If we could raise the cost of sending an email message - say, by requiring a proof-of-work signature - then we could break the spam business model by raising costs to be higher than profits.

Building the minimum viable block chain #

We've covered a lot of ground. Before we discuss how the block chain can help us build a secure distributed ledger, let's quickly recap the setup, the properties, and the unsolved challenges within of our network:

  1. Alice and Bob complete a transaction and record it in their respective ledgers.
    1. Once done, Bob has a PKI-protected IOU from Alice.
  2. Bob completes a transaction with John where he transfers Alice's IOU to John. Both Bob and John update their ledgers, but Alice doesn't know about the transaction… yet.
    1. Happy scenario: John asks Alice to redeem his new IOU; Alice verifies his transaction by fetching Bob's public key; if the transaction is valid she pays John the required amount.
    2. Not so happy scenario: Bob uses his old ledger that omits his transaction with John to create a double-spend transaction with Katy. Next, both Katy and John show up at Alice's doorstep and realize that only one of them will get paid.

The double-spend is possible due to the "weak consistency" of the distributed ledger: neither Alice nor Katy know about John and Bob's transaction, which allows Bob to exploit this inconsistency to his advantage. Solution? If the network is small and all participants are known, we can require that each transaction must be "accepted" by the network before it is deemed valid:

  • Unanimous consensus: whenever a transaction takes place the two parties contact all other participants, tell them about the transaction, and then wait for their "OK" before they commit the transaction. As a result, all of the ledgers are updated simultaneously and double-spend is no longer possible.
  • Quorum consensus: to improve processing speed and availability of the network (i.e. if someone is offline, we can still process the transaction) we can relax above condition of unanimous consensus to quorum consensus (50% of the network).

Either of above strategies would solve our immediate problem for a small network of known and verified participants. However, neither strategy scales to a larger, dynamic network where neither the total number of participants is known at any point in time, nor their identity:

  1. We don't know how many people to contact to get their approval.
  2. We don't know whom to contact to get their approval.
  3. We don't know whom we are calling.
Note that we can use any means of communication to satisfy above worfklow: in person, internet, avian carriers, etc!

Lacking identity and global knowledge of all the participants in the network we have to relax our constraints. While we can't guarantee that any particular transaction is valid, that doesn't stop us from making a statement about the probability of a transaction being accepted as valid:

  • Zero-confirmation transaction: we can accept a transaction without contacting any other participants. This places full trust on the integrity of the payee of the transaction - i.e. they won't double-spend.
  • N-confirmation transaction: we can contact some subset of the (known) participants in the network and get them to verify our transaction. The more peers we contact, the higher the probability that we will catch malicious parties attempting to defraud us.

What is a good value for "N"? The answer depends on the amount being transferred and your trust and relationship with the opposite party. If the amount is small, you may be willing to accept a higher level of risk, or, you may adjust your risk tolerance based on what you know about the other party. Alternatively, you will have to do some extra work to contact other participants to validate your transaction. In either case, there is a tradeoff between the speed with which the transaction is processed (zero-confirmation is instant), the extra work, and the risk of that transaction being invalid.

So far, so good. Except, there is an additional complication that we must consider: our system relies on transaction confirmations from other peers, but nothing stops a malicious user from generating as many fake identities as needed (recall that an "identity" in our system is simply a public-private keypair, which is trivial to generate) to satisfy Katy's acceptance criteria.

Whether Bob decides to execute the attack is a matter of simple economics: if the gain is higher than the cost then he should consider running the attack. Conversely, if Katy can make the cost of running the attack higher than the value of the transaction, then she should be safe (unless Bob has a personal vendetta and/or is willing to lose money on the transaction... but that's out of scope). To make it concrete, let's assume the following:

  • Bob is transferring 10 chroms to Katy.
  • The cost of generating a fake identity and transaction response is 0.001 chroms: energy costs to keep the computer running, paying for internet connectivity, etc.

If Katy asks for 1001 confirmations, then it no longer makes (economic) sense for Bob to run the attack. Alternatively, we could add a proof-of-work requirement for each confirmation and raise the cost for each valid response from 0.001 chroms to 1: finding a valid hash will take CPU time, which translates to a higher energy bill. As a result, Katy would only need to ask for 11 confirmations to get the same guarantee.

Note that Katy also incurs some costs while requesting each confirmation: she has to expend effort to send out the requests and then validate the responses. Further, if the cost of generating a confirmation and verifying it is one-to-one, then Katy will incur the same total cost to verify the transaction as its value… which, of course, makes no economic sense.

This is why the asymmetry of proof-of-work is critical. Katy incurs low cost to send out requests and validate the responses, but the party generating the confirmation needs to expend significantly more effort to generate a valid response.

Great, problem solved, right? Sort of... in the process we've created another economic dilemma. Our network now incurs a cost to validate each transaction that is of equal or higher value than the transaction itself. While this acts as an economic deterrent against malicious participants, why would any legitimate participant be willing to incur any costs for someone else? A rational participant would simply wouldn't, it doesn't make sense. Doh.

Adding "blocks" & transaction fee incentives #

If participants in the network must incur a cost to validate each other's transactions, then we must provide an economic incentive for them to do so. In fact, at a minimum we need to offset their costs, because otherwise an "idle" participant (anyone who is not submitting own transactions) would continue accruing costs on behalf of the network — that wouldn't work. Also a couple of other problems that we need address:

  1. If the cost of verifying the transaction is equal to or higher than the value of the transaction itself (to deter malicious participants), than the total transaction value is net-zero, or negative! E.g. Bob transfers 10 chroms to Katy; Katy spends 10 chroms to compensate other peers to validate the transaction; Katy is sad.

  2. How does Katy pay for confirmations? If that's its own transaction then we have a recursive problem.

Let's start with the obvious: the transaction fee can't be as high as the value of the transaction itself. Of course, Katy doesn't have to spend the exact value to confirm the transaction (e.g. she can allocate half the value for confirmations), but then it becomes a question of margins: if the remaining margin (value of transaction - verification fees) is high enough, than there is still incentive for fraud. Instead, ideally we would like to incur the lowest possible transaction fees and still provide a strong deterrent against malicious participants. Solution?

We can incentivize participants in the network to confirm transactions by allowing them to pool and confirm multiple transactions at once - i.e. confirm a "block" of transactions. Doing so would also allow them to aggregate transaction fees, thereby lowering the validation costs for each individual transaction.

A block is simply a collection (one or more) of valid transactions - think of it as the equivalent of a page in a physical ledger. In turn, each block contains a reference to a previous block (previous page) of transactions, and the full ledger is a linked sequence of blocks. Hence, block chain. Consider the example above:

  1. Alice and Bob generate new transactions and announces them to the network.
  2. Chris is listening for new transaction notifications, each of which contains a transaction fee that the sender is willing to pay to get it validated and confirmed by the network:
    1. Chris aggregates unconfirmed transactions until he has a direct financial incentive (sum of transaction fees > his cost) to perform the necessary work to validate the pending transactions.
    2. Once over the threshold, Chris first validates each pending transaction by checking that none of the inputs are double-spent.
    3. Once all transactions are validated Chris adds an extra transaction to the pending list (indicated in green in the diagram above) that transfers the sum of advertised transaction fees to himself.
    4. Chris generates a block that contains the list of pending transactions, a reference to the previous block (such that we can traverse the blocks and see the full ledger), and performs the proof-of-work challenge to generate a block hash value that conforms to accepted rules of the network - e.g. partial hash collision of N leading zeros.
    5. Finally, once Chris finds a valid block, he distributes it to all other participants.
  3. Both Alice and Bob are listening for new block announcements and look for their transaction in the list:
    1. Alice and Bob verify integrity of the block - i.e. verify proof-of-work and contained transactions.
    2. If the block is valid and their transaction is in the list, then the transaction has been confirmed!
We made a big leap here. Previously we've only had one type of record in our network - the signed transaction. Now we have signed transactions and blocks. The former is generated by the individuals engaging in trade, and the latter is generated by parties interested in collecting fees by validating and confirming transactions.

Also, note that the above scheme requires some minimum volume of transactions in the system to sustain the incentives for individuals creating the blocks: the more transactions there are, the lower the fees have to be for any single transaction.

Phew, ok, Alice has announced a new transaction and received a valid block from Chris confirming it. That's one confirmation, what about the rest? Also, Chris is (hopefully) not the only participant who is incentivized to work on generating the blocks. What if someone else generates a different block at the same time, and which of those blocks is "valid"? This is where it gets interesting...

Racing to claim the transaction fees #

The remarkable part about introducing the ability to aggregate fees by verifying a block of transactions is that it creates a role for a new participant in the network who now has a direct financial incentive to secure it. You can now make a profit by validating transactions, and where there is profit to be made, competition follows, which only strengthens the network - a virtuous cycle and a clever piece of social engineering!

That said, the incentive to compete to validate transactions creates another interesting dilemma: how do we coordinate this block generation work in our distributed network? The short answer is, as you may have already guessed, we don't. Let's add some additional rules into our system and examine how they resolve this problem:

  1. Any number of participants is allowed to participate ("race") to create a valid block. There is no coordination. Instead, each interested participant listens for new transactions and decides whether and when they want to try to generate a valid block and claim the transaction fees.
  2. When a valid block is generated, it is immediately broadcast into the network.
    1. Other peers check the validity of the block (check each transaction and validity of the block itself), and if valid, add it to their ledgers and then finally rebroadcast it to other peers in the network.
    2. Once added, the new block becomes the "topmost block" of their ledger. As a result, if that same peer was also working on generating a block, then they need to abort their previous work and start over: they now need to update their reference to the latest block and also remove any transactions from their unconfirmed list that are contained in the latest block.
    3. Once above steps are complete, they start working on a new block, with the hope that they'll be the first ones to discover the next valid block, which would allow them to claim the transaction fees.
  3. … repeat above process until the heat death of the universe.

The lack of coordination between all the participants working on generating the blocks means there will be duplicate work in the network, and that's OK! While no single participant is guaranteed to claim any particular block, as long as the expected value (probability of claiming the block times the expected payout, minus the costs) of participating in the network is positive, then the system is self-sustaining.

Note that there is also no consensus amongst the peers on which transactions should be validated next. Each participant aggregates their own list and can use different strategies to optimize their expected payoff. Also, due to the random nature of our proof-of-work function (finding a partial hash collision for a SHA-256 checksum of the block), the only way to increase the probability of claiming a block is to expend more CPU cycles.

There is one more caveat that we need to deal with: it's possible that two peers will find a valid block at about the same time and begin propagating through the network - e.g. Kent and Chris in the diagram above. As a result, some fraction of the network may end up accepting Kent's block as topmost block, while the rest will take Chris's block. Now what?

Resolving chain conflicts #

Once again, we're going to take a hands-off approach and let the random nature of the block generation process resolve the conflict, albeit with one additional rule: if multiple chains are detected, the participants should immediately switch to and build on top of the longest chain. Let's see how this work in practice:

  1. Some peers will start building new blocks on top of Kent's block, others on top of Chris's block.
  2. At some point, someone will find a new block and begin propagating it through the network.
    1. When other peers receive the new block, the part of the network that was working with a different topmost block will detect that there is now a longer alternative chain, which means that they need to switch to it - e.g. in the above example, the peers who were working with Chris's block stop their work, drop Chris's block, and switch to the longer (Amy + Kent's) chain.
    2. Any transactions that are part of the discarded block but that are not yet confirmed are placed in the pending list and the process starts over.
It's possible that the race condition can persist for multiple blocks, but eventually, due to the random nature of the proof-of-work process, one branch will race ahead of the other and the rest of the network will converge on the same longest chain.

Great, we now have a strategy to resolve conflicts between different chains in the network. Specifically, the network promises linearizability of transactions by recording them in a linked list of blocks. But, crucially, it makes no promises about an individual block "guaranteeing" the state of any transaction. Consider the example above:

  • Alice sends out her transaction into the network.
  • Chris generates a valid block that confirms her transaction.

Except, there is a fork in the chain and Chris's block is later "removed" as the network converges on Kent's branch of the chain. As a result, even when Alice receives a block with her transaction, she can't be sure that this block won't be undone in the future!

Blocks are never "final" #

No block is "final", ever. Any block can be "undone" if a longer chain is detected. In practice, forks should be detected fairly quickly, but there is still always the possibility of an alternative chain. Instead, the only claim we can make is that the "deeper" any particular block is in the chain, the less likely it is that it will undone. Consequently, no transaction can ever be treated as "final" either, we can only make statements about the probability of it being undone.

  1. 0-confirmation transaction: exchange is performed without waiting for any block to include the transaction.
  2. 1-confirmation transaction: latest valid block includes the transaction.
  3. N-confirmation transaction: there is a valid block that includes the transactions, and there are N-1 blocks that have since been built on top of that block.

If you are willing to accept the risk, you always have the option to go with a 0-confirmation transaction: no transaction fees, no need to wait for confirmations. However, you also place a lot of trust in the opposite party.

Alternatively, if you want to lower your risk, then you should wait for one or more blocks to be built on top of the block that includes your transaction. The longer you wait, the more blocks will be built on top of the block that contains your transaction, the lower the probability of an alternative chain that may undo your transaction.

By "undo" we mean any scenario where one of the participants can make the network accept an alternative transaction transferring funds to any account other than yours - e.g. you complete the transaction, hand over the widget and get a receipt, but the attacker then injects a transaction that "double-spends" those same funds to an alternative account.

Why does the length of the block chain act as a good proxy for "safety" of a transaction? If an attacker wanted to undo a particular transaction, then they will need to build a chain that begins at a block prior to the one where that transaction is listed, and then build a chain of other blocks that is longer than the one currently used by the network. As a result, the deeper the block, the higher the amount of computational effort that would be required to replace it by creating an alternative chain. The longer the chain the more expensive it is to execute an attack.

How many blocks should you wait for before accepting a transaction? There is no one number, the answer depends on the properties of the network (time to generate each block, propagation latency of the transactions and blocks, size of the network, etc), and the transaction itself: it's value, what you know about the other party, your risk profile, and so on.

Properties of the (minimum viable) block chain#

  1. Individual transactions are secured by PKI.
    • Transactions are authenticated: a malicious party can't masquerade as someone else and sign a transaction on their behalf.
      • Authentication is only with respect to the public-private keypair. There is no requirement for "strong authentication" that links the keypair to any other data about the participants. In fact, a single participant can generate and use multiple keypairs! In this sense, the network allows anonymous transactions.
    • Non-repudiation: participants can't claim that the transaction did not happen after the fact.
    • Integrity: transactions can't be modified after the fact.
  2. Once created, transactions are broadcast into the P2P network.
    • Participants form a network where transactions and blocks are relayed amongst all the participating peers. There no central authority.
  3. One or more transactions are aggregated into a "block".

    • A block validates one or more transactions and claims the transaction fees.
      • This allow the transaction fees to remain small relative to the value of each transaction.
    • A valid block must have valid proof-of-work solution.
      • Valid proof-of-work output is hard to generate and cheap to verify.
      • Proof-of-work is used to raise the cost of generating a valid block to impose a higher cost on running an attack against the network.
    • Any peer is allowed to work on generating a valid block, and once a valid block is generated, it is broadcast into the network.
      • Any number of peers can compete to generate a valid block. There is no coordination. When a fork is detected, it is resolved by automatically switching to the longest chain.
    • Each block contains a link to a previous valid block, allowing us to traverse the full history of all recorded transactions in the network.
  4. Peers listen for new block announcements and merge them into their ledgers.

    • Inclusion of the transaction in a block acts as a "confirmation" of that transaction, but that fact alone does not "finalize" any transaction. Instead, we rely on the length of the chain as a proxy for "safety" of the transaction. Each participant can choose their own level of risk tolerance, ranging from 0-confirmation transactions to waiting for any arbitrary number of blocks.

The combination of all of the above rules and infrastructure provides a decentralized, peer-to-peer block chain for achieving distributed consensus of ordering of signed transactions. That's a mouthful, I know, but it's also an ingenious solution to a very hard problem. The individual pieces of the block-chain (accounting, cryptography, networking, proof-of-work), are not new, but the emergent properties of the system when all of them are combined are pretty remarkable.