How To Make Your Own Cryptocurrency From Scratch

Today we’re going to make our own basic, decentralized cryptocurrency implementation using blockchain technology and Python.

We can use any Object-Oriented Programming Language, and I’m going to use Python.

The most important thing most cryptocurrencies rely on is blockchain. A blockchain is simply a chain a blocks. And a block is a data structure that contains information, such as transactions. Each block also a its own hash, and the hash of the previous block in the chain. A hash is a unique identifier, kind of like someone’s name (if no one has the same name). This is like if we have a line of people and each person knows their own name and the name of the person behind them in line, then the line is stored and can always be recreated. This is how we’ll create and store the blockchain.

So, to make a blockchain, we’re going to make a class for each of these:

class Blockchain (object): 
    def __init__(self):
class Block (object):
    def __init__(self):
class Transaction (object):
    def __init__(self):

Then, we’re going to add some essential data, as well as a hashing function.
Again, a hash is a unique identifier, and each block and transaction needs one so that we can identify it. We calculate the hash by using a cryptographic hash algorithm called SHA256, which is the same encoder used by Bitcoin. The hash is determined by all the data in each block or transaction, so if anything is tampered with or changed, such as the amount in a transaction, its hash will change too, and we’ll know something’s not right.

class Blockchain (object): 
    def __init__(self):
        self.chain = []; #Blockchain is an array of Blocks
class Block (object):
    def __init__(self, transactions, time, index):
        self.index = index; #Block Number
        self.transactions = transactions; #Transaction Data
        self.time = time; #Time block was created
        self.prev = ''; #Hash of Previous Block
        self.hash = self.calculateHash(); #Hash of Block
    def calculateHash(self):
        hashTransactions = "";
        for transaction in self.transactions:
            hashTransactions += transaction.hash;
        hashString = str(self.time) + hashTransactions + self.prev + str(self.index) + str(self.nonse);
        hashEncoded = json.dumps(hashString, sort_keys=True).encode();
        return hashlib.sha256(hashEncoded).hexdigest();
class Transaction (object):
    def __init__(self, sender, reciever, amt):
        self.sender = sender;
        self.reciever = reciever;
        self.amt = amt;
        self.time = time();
        self.hash = self.calculateHash();
    def calculateHash(self):
        hashString = self.sender + self.reciever + str(self.amt) + str(self.time);
        hashEncoded = json.dumps(hashString, sort_keys=True).encode();
        return hashlib.sha256(hashEncoded).hexdigest();

Then, we have to make a function to add blocks to the Blockchain:

class Blockchain (object):
    ...
    def getLastBlock(self):
        return self.chain[-1];
    def addBlock(self, block):
        if(len(self.chain) > 0):
            block.prev = self.getLastBlock().hash;
        else:
            block.prev = "none";
        self.chain.append(block);

When we test this by creating an instance of a Blockchain and adding 3 empty blocks to it in a test script, we get:

As we can see, a blockchain was made successfully, and we have 3 blocks with its own hash and the hash of the previous block in the chain.

Remember that if someone were to change some data in the blockchain, the hash of the tampered block would change too, breaking the chain. So, if someone changes, say, the value of a transaction to give them more money, this would break the chain. However, if this person were to recalculate the hashes of every block in the chain, then they could make it a valid blockchain again, one that includes their tampered data. This is very possible with a computer that can recalculate the hash values of the block and the previous block in seconds.

So, to ensure this doesn’t happen, blockchain technology relies on something called a proof-of-work algorithm.

The easiest way for me to understand this was to imagine we have 3 variables: x, y, and z. We’re ‘given’ z, don’t know y, and have to find a value x such that x * y = z. To solve this, we should start by guessing any value for x, say, 1. We multiply 1* y and the feedback we get is if this value equals z. If it doesn’t, then we should try another value for x, say, 2. We multiply 2 * x and see if it equals z. We do this for every possible value of x until we get that x * y = z. This process is called brute force, in which we compute every attempt until we happen to compute the correct answer. Once we get this value for x, we store it in our block, which affects its hash (making it the correct one).

Keep in mind that this is a very basic example and wouldn’t be implemented because it’s too fast to solve. An example of one that actually would be used is coming up :slight_smile: But yeah, a proof-of-work algorithm makes sure that rewriting the entire blockchain isn’t worthwhile because we would have to solve a new ‘x’ (which is actually called ‘nonce’ in this context) for every block and it’d take a very long time.

The process of solving this proof-of-work to make a new block for our crypocurrency is called mining. For our cryptocurrency, I’ve implemented a proof-of-work algorithm that solves for a variable nonse such that it makes the hash of the block start with ‘1234’.

class Blockchain (object):
    def __init__(self):
        self.chain = [self.addGenesisBlock()];
        self.pendingTransactions = [];
        self.difficulty = 4;
        self.minerRewards = 50;
        self.blockSize = 10;
    def addTransaction(self, sender, reciever, amt, keyString, senderKey):
        keyByte = keyString.encode("ASCII");
        senderKeyByte = senderKey.encode("ASCII");
    #print(type(keyByte), keyByte);
    key = RSA.import_key(keyByte);
        senderKey = RSA.import_key(senderKeyByte);
    if not sender or not reciever or not amt:
            print("transaction error 1");
            return False;
    transaction = Transaction(sender, reciever, amt);
    transaction.signTransaction(key, senderKey);
    if not transaction.isValidTransaction():
            print("transaction error 2");
            return False;
        self.pendingTransactions.append(transaction);
        return len(self.chain) + 1;
class Block (object):
        ...
   def mineBlock(self, difficulty):
        arr = [];
        for i in range(0, difficulty):
            arr.append(i+1);
        
        #compute until the beginning of the hash = 0123..difficulty
        arrStr = map(str, arr);  
        hashPuzzle = ''.join(arrStr);
        #print(len(hashPuzzle));
        while self.hash[0:difficulty] != hashPuzzle:
            self.nonse += 1;
            self.hash = self.calculateHash();
            '''
            print("Nonse:", self.nonse);
            print("Hash Attempt:", self.hash);
            print("Hash We Want:", hashPuzzle,"...");
            print("");
            #sleep(0.8);
            '''
        print("");
        print("Block Mined! Nonse to Solve Proof Of Work:", self.nonse);
        return True;

When we test this by mining a new block with its own transactions, we get:

So it works! When we mined the block, the solution to nonce turned out to be 61601, which would make the hash of the block start with 1234.

Now, we need to be able to verify that each of the transactions we make is valid. We’re going to do this in the same way that people sign their checks in real life to make them valid.
To do this, crypocurrencies give each “wallet” or user their own set of unique keys: a private key and a public key. With these keys, users will be able sign their transactions in order to make them valid. To implement this, we’re going to use a Python library called PyCryptoDome. The encryption algorithm we’re going to use in order to generate these keys is called RSA (Rivest–Shamir–Adleman).

class Blockchain (object):
    ...
    def addTransaction(self, sender, reciever, amt, keyString, senderKey):
        keyByte = keyString.encode("ASCII");
        senderKeyByte = senderKey.encode("ASCII");
        key = RSA.import_key(keyByte);
        senderKey = RSA.import_key(senderKeyByte);
        if not sender or not reciever or not amt:
            print("transaction error 1");
            return False;
        transaction = Transaction(sender, reciever, amt);
        transaction.signTransaction(key, senderKey);
        if not transaction.isValidTransaction():
            print("transaction error 2");
            return False;
        self.pendingTransactions.append(transaction);
        return len(self.chain) + 1;
    def generateKeys(self):
        key = RSA.generate(2048)
        private_key = key.export_key()
        file_out = open("private.pem", "wb")
        file_out.write(private_key)
        public_key = key.publickey().export_key()
        file_out = open("receiver.pem", "wb")
        file_out.write(public_key)
        
        #print(key.export_key());
        return key.publickey().export_key().decode('ASCII');
class Transaction (object):
    ...
    def signTransaction(self, key, senderKey):
        if(self.hash != self.calculateHash()):
            print("transaction tampered error");
            return False;
        if(str(key.publickey().export_key()) != str(senderKey.publickey().export_key())):
            print("Transaction attempt to be signed from another wallet");
            return False;
        self.signature = "made";
        #print(key.sign(self.hash, ""));
        print("Made Signature!");
        return True;
    def isValidTransaction(self):
        if(self.hash != self.calculateHash()):
            return False;
        if(self.sender == self.reciever):
            return False;
        if(self.sender == "Miner Rewards"):
            return True;
        if not self.signature or len(self.signature) == 0:
            print("No Signature!")
            return False;
        return True;

When we make a new wallet and generate keys, we get:

Now, when we make transactions, we will verify that it is valid with these keys, as seen in the code.

Lastly, most important thing about cryptocurrency and blockchain technology is that is relies is decentralization. This means that it does not rely on any central point of control, but instead relies on a peer-to-peer network.

An example of a centralized system is a bank. It’s centralized because it stores all your money as well as all the data about transactions in its own database, which they verify independently . You trust the bank with your money.

But with a decentralized system, like a peer-to-peer network (P2P), responsibilities of storing and verifying data is distributed among the people. Regarding blockchain, anyone in this P2P network, which is open to anyone, has a copy of the full blockchain. This is what makes it a distributed ledger, where data is open and stored by multiple nodes.

When a new block needs to be added to the blockchain, each person verifies that it is okay to add it to the chain, and adds it to their own version of the blockchain. If everything checks out and we have over 50% of the network that agrees on this new version of the blockchain, then we have consensus, or majority agreement. When we have consensus regarding a new version of the blockchain, then this new version becomes the accepted blockchain.

If someone were to change data in the blockchain, then their version would be different than what’s accepted by the majority of the network, and he/she would not be able to get this change onto the real, accepted blockchain.

To implement this, we’re going to register each user of our cryptocurrency as a node:

class Blockchain (object):
...
def register_node(self, address):
parsedUrl = urlparse(address);
self.nodes.add(parsedUrl.netloc);

And for the consensus verification, we’re just going to keep it simple for testing purposes and say that the longest blockchain in the peer-to-peer network is the correct version.

class Blockchain (object):
    ...
    def resolveConflicts(self):
        neighbors = self.nodes;
        newChain = None;
        maxLength = len(self.chain);
        for node in neighbors:
            response = requests.get(f'http://{node}/chain');
            if response.status_code == 200:
                length = response.json()['length'];
                chain = response.json()['chain'];
            if length > maxLength and self.isValidChain():
                    maxLength = length;
                    newChain = chain;
        if newChain:
            self.chain = self.chainJSONdecode(newChain);
            print(self.chain);
            return True;
        return False;

Now, when we run our crypocurrency on two separate servers, which replicates how it would be if it was running on two different computers, we can see that our blockchain is now decentralized:

We just created our own basic cryptocurrency from scratch! I did make my own user-friendly interface to use and interact with the cryptocurrency easily, so maybe I’ll write about that in a Part 2.

As some next steps, I was trying to make this public and tie it to some kind of gym membership credit, but it turns out this is already a real thing in development! I think this is super cool and can’t wait to see (and contribute) to what decentralization and cryptocurrency brings to us in the future.

But yeah, that’s pretty much it. As always, you can check out all the code on my Github, and don’t hesitate hit me up if you have any questions or concerns!

Source: Medium

Happy learning!

10 Likes