I built a crypto currency in 2017

dollarydoo

International Drainage Commission Approved

Whenever I want to gain insights or just fulfil my curiosity about new tech, I usually try and build something with it. Blockchain technologies definitely passed me by when they first started making the news. I was not up to speed with it. I had no idea about the particular branches of mathematics that it uses, and I certainly didn’t know how it actually worked.

Digital Money! So long, banks!

It’s not worth going over how well blockchain landed as a technology. I am definitely not going to throw out an opinion there, other than to say that if nothing else, it’s incredibly interesting. Almost all arguments about when to use a blockchain can be countered with, “use a relational database”. Ahh crap that’s wading in to it I’m sorry I’m sorry.

To learn what The Blockchain is, I headed to wikipedia. I read hackernews (big mistake), I cloned repos that had Hello World versions of blockchain and I started formulating a plan. I learn by doing, I’m terrible at reading things and knowing how they work. I need to catch breakpoints in working programs to see how everything hangs together. Such is the life of a potato developer.

An overview of major moving parts of The Blockchain

  • The Blockchain

    A list of block objects, where each new block contains information about the previous block, has a proof of work attached to it, and a list of transactions between parties. I’ll talk more about transactions later. Here’s an example of a block

    {
      "index": 6,
      "proof": 845234,
      "previous_hash": "add5ec0c6edc0c24b1b314bf2761de913e3b72321c7418f73dda7d34306f5cf0",
      "timestamp": 1596269243074,
      "transactions": [
        {
          "from": "028cf7765796934c15e447e7d8eb53b06c3983e04c1b07361494e4545170385e34",
          "to": "02caf5f68b880312a7229bf24a94f4a2ba7133bb2e5c71ff36f4919cceff23d431",
          "amount": 0.01
        },
        {
          "from": "028cf7765796934c15e447e7d8eb53b06c3983e04c1b07361494e4545170385e34",
          "to": "0207cc20785e040ab344ae76e3577eb836052247396c566152fc030eff88f2c29d",
          "amount": 1
        },
        {
          "from": "Andy, drinking a Fosters in a dam.",
          "to": "028cf7765796934c15e447e7d8eb53b06c3983e04c1b07361494e4545170385e34",
          "amount": 5
        }
      ]
    }
    // 'Andy, drinking a Fosters in a dam.' is The Server, rewarding the person who submitted the `proof` value above
    
  • The Server

    In my blockchain I relied on The Server to be the creator of new Dollarydoos (coins, currency, dollarbucks, shekels, clams, what have you). New Dollarydoos were created out of thin air by this entity. When someone submits a proof of work to The Server and it’s the right proof for the next block in the chain, then The Server rewards that person with some Dollarydoos. This is the source of all wealth. All Dollarydoos exist because THIS entity handed them out.

    The Server is the only entity that writes to The Blockchain.

  • Proof of Work

    The Server can’t just hand out Dollarydoos to everyone. The Server demands that people submit an integer to a /solve endpoint and then you get a reward. The catch? That integer must be able to make a certain algorithm return true;. The proof of work is a way of knowing that someone spent computational effort to find out what was the right integer to submit - and therefore they deserve to have a reward for exerting this effort in the form of Dollarydoos!

    Yes this is the reasoning behind it all. This is the catch that is not apparent to all newcomers. You make your CPU/GPU/SomethingProcessingUnit perform cryptographic operations (SHA256 in my case), consume electricity, generate waste heat and in return you get your public key inserted into a json file that lives somewhere. It’s a bit sad, when you think about it. Never mind! It’s FUN to learn new things! Don’t let this trivial detail get you down, we have CRYPTO to build!

  • Public Keys

    Public keys can be thought of as your unique identifier. Public keys are anonymous, there is no way to determine from a public key what your private key is, and only you should own the corresponding private key in your key pair. Public keys are the TO: section of a transaction. You send Dollarydoos to a public key. It’s essentially your wallet. If you can prove that you own a particular public key, then ALL transactions TO that public key are yours. You can SPEND this money I mean Dollarydoos!

  • Private Keys

    Private keys are used in the creation of a shared secret key between you and The Server. You own a public and private Elliptic-curve Diffie–Hellman (ECDH) key pair. The Blockchain suite of technology will generate a shared secret using your private key and The Server’s public key. More on this later. I know, this is confusing as hell and I had to build something to understand it. The private key:

    • Is part of a key pair (public and private)
    • Is used along with The Server’s public key (my private key, The Server’s public key) to create a Shared Secret that is unique between you and the server. This shared secret is used in an AES (Advanced Encryption Standard) cipher. It’s a way of creating cipher text that is indecipherable unless you have the key that was used in the creation of the cipher text. The COOLEST part about all this is that with the Elliptic-curve Diffie–Hellman (ECDH) public key exchange protocol, both you and the server can create the EXACT same encryption key by only sharing your public keys.
  • Transactions

    A transaction is the movement of dollarydoos to different entities, and The Blockchain is the “public ledger” of these transactions. Transactions are one way - you may only ever give your own Dollarydoos to someone else. You need to rely on other communication methods to coordinate the transfer of Dollarydoos. You need to get someone else to start a transaction TO YOU if you ever want Dollarydoos. There is no such thing as a refund, unless of course you consider a new transaction to be one.

    A transaction is pretty basic in structure. It contains a from and a to address (both of which are public keys) and an amount of Dollarydoos to transfer, as well as some ciphertext, encryptedBlob. (Not very flattering). Because we only rely on public information to make transactions, we need to defend ourselves from fraudsters by implementing (other people’s) genius mathematics during the receipt of a transaction to The Server.

    A transaction looks like this

    {
      "from": "028cf7765796934c15e447e7d8eb53b06c3983e04c1b07361494e4545170385e34",
      "to": "0207cc20785e040ab344ae76e3577eb836052247396c566152fc030eff88f2c29d",
      "amount": 4.2,
      "encryptedBlob": "6934c15e447e7d8eb53b06344ae ... hex text ... 7361494e454517052247396c56 ..."
    }
    

    When you submit a transaction to the server the following things happen.

    • The transaction is submitted as an encrypted blob of text alongside the cleartext parts of the JSON payload. The encryptedBlob is the way that the sender guarantees that the server receives the transaction that the sender sent. E.g. make sure there was no Man In The Middle attack that mutated the transaction for nefarious purposes. We don’t want someone to impersonate your public key and make a transaction on your behalf - giving YOUR dollarydoos away to someone else! That’d be bad!

      What is encrypted? The hash of original payload, e.g. the from, to, amount parts of the transaction.

      const intendedTransaction = {
        from: this.props.publicKey,
        to: this.state.transactTo,
        amount: this.state.transactAmount
      }
      const hashedIntendedTransaction = getHash(JSON.stringify(intendedTransaction))
      
      const sharedSecret = this.props.ecdh.computeSecret(this.props.serverPublicKey, "hex")
      
      encryptData(hashedIntendedTransaction, sharedSecret)
        .then((encrypted) => {
          attemptToTransact(
            this.props.publicKey,
            this.state.transactTo,
            this.state.transactAmount,
            this.props.publicKey,
            encrypted // this is the `encryptedBlob`
          ).then((response: any) => {
            // handle the response from The Server
      

      where

      export const attemptToTransact = (from: string, to: string, amount: number, sender: string, encryptedBlob: any) => {
        const url = `${API_BASE_URL}/transact`
        return fetch(url, {
          method: "POST",
          body: JSON.stringify({
            from: from,
            to: to,
            amount: amount,
            sender: sender,
            encryptedBlob: encryptedBlob
          }),
          headers: defaultHeaders()
        })
      }
      

      The server decrypts the blob using a key that is generated between The Server’s private key and the sender’s public key. After The Server decrypts the payload, it performs a sha256 on the other elements of transaction object e.g.

    {
      "from": "028cf7765796934c15e447e7d8eb53b06c3983e04c1b07361494e4545170385e34",
      "to": "0207cc20785e040ab344ae76e3577eb836052247396c566152fc030eff88f2c29d",
      "amount": 4.2
    }
    

    If the resulting hash value for sha’ing the above object IS IDENTICAL to the decrypted payload (which is the sha256 value that you encrypted locally), then the server knows that you are the rightful owner of the private key that was used to create the encrypted blob. It also means the transaction could not have been altered in transit, since then the encryptedBlob’s cleartext value would not equal the sha256 performed on the received transaction object. Once The Server knows the public key linked/paired to the encrypted blobs creator is valid …

    • The server makes sure that the transaction’s FROM address is identical to the public key of the submitter. This means that someone is spending their own money CRAP I mean Dollarydoos
    • The server iterates over the entire blockchain, summing all of the transactions where the TO address is the senders public key (amount of credits for that public key), and deducting the sum of all transactions where the FROM address is the senders public key (amount of debits for that public key). If the remaining amount of Dollarydoos is less than or equal to the AMOUNT in the transaction, then The Server has verified that the sender has enough Dollarydoos to transfer to the TO address.
    • The server holds on to this transaction, it doesn’t add it to the blockchain immediately. It’s pending. The transaction has to be baked into the next block, and the next block can only be created when someone submits a valid proof of work.

I think we can all agree at this point, this is WAY cooler than a relational database! Let’s keep going!

Before I started on this journey I knew about RSA key pairs, I knew about SSH and a bit about signatures from SSL certificates, but I had never used Elliptic Curve cryptography (let alone studied the maths behind it), nor had I implementing an AES cipher text in real life.

I wanted to learn what Blockchain was. I wanted to build something relatively light weight, that had a small surface area for the users but was as fully featured as one would want in a digital currency website. So someone would need to be able to

  • Create “an account” (really, a public and private key pair)
  • Mine Dollarydoos (or, submit a Proof of Work and receive rewards)
  • Transact (give Dollarydoos to someone else)

No Databases

That includes for the users. There would be no user accounts. Users did not sign up, you did not create a private key and store it on any server (and you sure as hell wouldn’t give it to me either!). Your private key would need to be something that was:

  • Ephemeral (in terms of persistence). Not stored, ever, at all ever at all at all ever.
  • Reproducible (you can get this private key at any moment, but only you could)
  • I don’t store it. I don’t want it. It’s yours, don’t give it to me, don’t give it to anyone else, have you HEARD about Mt Gox?

The transactions would not be in a database, no databases allowed, not even DynamoDB or Elasticache! (Because I’m cheap, this made things very difficult for me in the future)

Up next - The Back End.