In Part 1, we'll cover how to store the blockchain data and generate a initial blocks, how a node can sync up with the Loc Al blockchain data, how to display the blockchain (which is used in the future to sync with other nodes), and then Ho W to go through and mine and create valid new blocks. For this is the there are no other nodes. There are no wallets, no peers, no important data. Information on those would come later.
A big thing to mention this is this there are differences in a basic blockchain like the one described here and a ' profess Ional ' Blockchain. This chain would not create a crypto currency. Blockchains don't require producing coins that can is traded and exchanged for physical. Blockchains are used to store and verify information. Coins help incentive nodes to participate in validation but don ' t need to exist.
Quick Summary of Blockchain
Here's a quick summary about how a blockchains work. If you are already know how they work, feel free to skip this section. If you'd like to learn about the blockchain in more detail, refer to:the Ultimate to the Guide.
At a super high level, a blockchain are a database where everyone participating in the blockchain be able to store, view, C Onfirm, and never delete the data.
On a somewhat lower level, the data in these blocks can is anything as long as that specific blockchain allows it. For example, the "data in" Bitcoin blockchain is only transactions of bitcoins between. The Ethereum blockchain allows similar transactions of Ether ' s, but also-transactions-are to run code.
Slightly more downward, before a, created and linked to the blockchain, it is validated by a majority of people Working on the blockchain and referred to as nodes. The true blockchain is the chain containing greatest number of blocks this is correctly verified by the majority of th E nodes. That is means if a node attempts to change the data in a previous block, the newer blocks won't be valid and nodes'll no T trust the data from the incorrect block.
If you are want to look in the code, check out of the Part 1 branch on Github.
Step 1-classes and Files
Step 1 for me are to write a class so handles the blocks when a node is running. I ' ll call this class block. Frankly, there isn ' t much to do with this class. In the __init__ function, we ' re going to the required information are provided in a dictionary. If We were writing a production blockchain, this wouldn ' t is smart, but it ' s fine for the example where we ' re the only one Writing all the code. We also want to write a method this spits out the important blocks information into a dict, and then have a nicer way to SH OW block Information If we print a blocks to the terminal.
Class Block (object):
def __init__ (self, Dictionary):
'''
We ' re looking for index, timestamp, data, Prev_hash, nonce
'''
For K, v. in Dictionary.items ():
SetAttr (self, k, V)
If not hasattr (self, ' hash '): #in creating the "a", needs to is removed in future
Self.hash = Self.create_self_hash ()
def __dict__ (self):
info = {}
info[' index '] = str (self.index)
info[' timestamp '] = str (self.timestamp)
info[' prev_hash '] = str (self.prev_hash)
info[' hash '] = str (self.hash)
info[' data '] = str (self.data)
return info
def __str__ (self):
Return ' block '% (Self.prev_hash, Self.hash)
When we ' re looking to create a-a, we can run the simple code.
Def create_first_block ():
# Index zero and arbitrary previous hash
Block_data = {}
block_data[' index '] = 0
block_data[' timestamp '] = Date.datetime.now ()
block_data[' data ' = ' block data '
block_data[' prev_hash ' = None
Block = Block (block_data)
return block
Nice. The final question of the "This" is where to store the data in the file system. We want this so we don ' t lose we have local block data if we turn off the node.
In a attempt to somewhat copy the Etherium Mist folder scheme, we are going to name the folder with the data ' chaindata '. Each block'll is allowed its own file for now where it's named based on its index. We need to make sure that this filename begins with plenty of leading zeros and so the blocks in are order.
With the code above, this is what we need to create the.
#check if Chaindata folder exists.
Chaindata_dir = ' Chaindata '
If not os.path.exists (Chaindata_dir):
#make Chaindata dir
Os.mkdir (Chaindata_dir)
#check if dir is empty from just creation, or empty before
If Os.listdir (chaindata_dir) = = []:
#create the
First_block = Create_first_block ()
First_block.self_save ()
Step 2-syncing the Blockchain, locally
When you start a node, before your ' re able to start mining, interpreting the data, or send/create new data for the chain, You are need to sync the node. Since There are no other nodes, we are only talking about reading the blocks of the local files. In the future, reading from files would be part of syncing, but also talking to peers to gather the blocks that were Ted while you weren ' t running your own node.
def sync ():
Node_blocks = []
#We ' re assuming that's the folder and at least initial block exists
Chaindata_dir = ' Chaindata '
If Os.path.exists (chaindata_dir):
for filename in Os.listdir (chaindata_dir):
If Filename.endswith ('. JSON '): #. Ds_store sometimes screws things up
filepath = '%s/%s '% (chaindata_dir, filename)
With open (filepath, ' R ') as Block_file:
Block_info = Json.load (block_file)
Block_object = Block (block_info) #since we can init a blocks object with just a dict
Node_blocks.append (Block_object)
Return node_blocks
Nice and simple. Reading strings from a folder and loading them into data structures doesn ' t require super complicated code. For now, works. But in future posts if we allow different nodes to communicate, this sync function is going to get a lot more complicate D.
Step 3-displaying The Blockchain
Now so we have the blockchain in memory, we want to start being able to show the chain in a browser. Two reasons for doing. The validate in a browser that things have changed. Second, we want to use the browser in the future to view and act on the blockchain. Like sending transactions or managing wallets.
We use flask here since it's super easy to start.
Here's the code to show the blockchain JSON. We'll ignore the import requirements to save spaces here.
node = Flask (__name__)
Node_blocks = Sync.sync () #inital blocks that are synced
@node. Route ('/blockchain.json ', methods=[' get ')]
def blockchain ():
'''
Shoots back the blockchain, which in our case, is a JSON list of hashes
With the block information which is:
Index
Timestamp
Data
Hash
Prev_hash
'''
Node_blocks = Sync.sync () #regrab the nodes if they ' ve changed
# Convert our blocks into dictionaries
# so we can send them as JSON objects later
Python_blocks = []
For blocks in Node_blocks:
Python_blocks.append (block.__dict__ ())
Json_blocks = Json.dumps (python_blocks)
Return json_blocks
if __name__ = = ' __main__ ':
Node.run ()
Run This code, visit Localhost:3000/blockchain.json, and you'll be the blocks spit out.
Step 4-"Mining", also known as block creation
We only have that one genesis blocks, and if we have more data we want to the store and distribute, we need a way to include th At to a new block. The question is how to create a new blocks while linking back to a previous one.
In the Bitcoin whitepaper, Satoshi describes it as the following. The ' timestamp server ' is referred to as a ' node ':
The solution we propose begins with a timestamp server. A timestamp server works by taking a hash of a blocks of items to is timestamped and widely publishing the hash ... The timestamp proves that the "data must have existed at the" time, obviously, "in" to "get" into the hash. Each timestamp includes the previous timestamp in it hash, forming a chain, with each additional timestamp reinforcing th e ones before it.
Here's a screenshot of the picture below the description.
A quick summary of the above:in order to link the blocks together, we create a hash of the information of a new block tha T includes the time of the "Block creation," the hash of the previous block, and the information in the block. We ' ll refer to this group of information as the ' header '. In this way, we ' re able to verify a blocks ' s truthfulness by running through all the hashes before a blocks and validating t He sequence.
For our case, the header we ' re creating are adding the string values together into a giant string. The data we ' re including is:
Index, meaning which number of block this would be
Previous block ' s hash
The data is just random strings. For bitcoin that is referred to as the Merkle root and which is info about the transactions
The timestamp of when we ' re mining the Block
def generate_header (index, Prev_hash, data, timestamp):
Return str (index) + prev_hash + data + str (timestamp)
Before getting confused, adding the strings of information together ' t isn to create a header. The requirement is this everyone knows how to generate a block's header, and within the header is the previous block ' s has H. This are so everyone can confirm the correct hash for the new block, and validate the link between the two blocks.
The Bitcoin header is much more complex than combining strings. It uses hashes of data, times, and deals with the bytes are stored in computer memory. But for now, adding strings suffices.
Once we have the header, we want to go through and calculate the validated hash, and by calculating the hash. In our hash calculation, we ' re going to be doing something slightly different than ' s method, Bitcoin we ' re but still NG The block header through the SHA256 function.
def calculate_hash (index, Prev_hash, data, timestamp, nonce):
header_string = Generate_header (index, Prev_hash, data, timestamp, nonce)
sha = hashlib.sha256 ()
Sha.update (header_string)
Return Sha.hexdigest ()
Finally, to mine the "block" we use the "functions above to" a hash for the "new block," store the hash in the "new block," an D then save that blocks to the Chaindata directory.
Node_blocks = Sync.sync ()
Def mine (Last_block):
index = Int (last_block.index) + 1
timestamp = Date.datetime.now ()
data = ' I block #%s '% (int (last_block.index) + 1) #random string for now, not transactions
Prev_hash = Last_block.hash
Block_hash = Calculate_hash (index, Prev_hash, data, timestamp)
Block_data = {}
block_data[' index '] = Int (last_block.index) + 1
block_data[' timestamp '] = Date.datetime.now ()
block_data[' data '] = "I block #%s"% Last_block.index
block_data[' prev_hash '] = Last_block.hash
block_data[' hash '] = Block_hash
return Block (Block_data)
def save_block (block):
Chaindata_dir = ' Chaindata '
filename = '%s/%s.json '% (Chaindata_dir, Block.index)
with open (filename, ' W ') as Block_file:
Print new_block.__dict__ ()
Json.dump (block.__dict__ (), Block_file)
if __name__ = = ' __main__ ':
Last_block = Node_blocks[-1]
New_block = Mine (last_block)
Save_block (New_block)
tada! Though with this type of block creation, whoever has the fastest CPU are able to create a chain that ' s the longest which OT Her nodes would conceive as true. We need some way to slow down blocks creation and confirm each other before moving the "next block."
Step 5-proof-of-work
In slowdown, we are ' re throwing in Proof-of-work as Bitcoin does. Proof of Stake are another way you'll have a blockchains use to get consensus and but for this we'll go with POW.
The way to adjust the requirement, a block ' s hash has certain properties. Like Bitcoin, we ' re going to make sure that hash begins with a certain number of zeros before you can move on to the N Ext one. The way to I to throw in one more piece of information into the header-a nonce.
def generate_header (index, Prev_hash, data, timestamp, nonce):
Return str (index) + prev_hash + data + str (timestamp) + str (nonce)
Now the mining function are adjusted to create the hash, but if the block ' s hash doesn ' t leads with enough zeros, we increme NT The nonce value, create the new header, calculate the new hash and check to the IF-leads with enough zeros.
Num_zeros = 4
Def mine (Last_block):
index = Int (last_block.index) + 1
timestamp = Date.datetime.now ()
data = ' I block #%s '% (int (last_block.index) + 1) #random string for now, not transactions
Prev_hash = Last_block.hash
nonce = 0
Block_hash = Calculate_hash (index, Prev_hash, data, timestamp, nonce)
While STR (Block_hash[0:num_zeros])!= ' 0 ' * Num_zeros:
Nonce + 1
Block_hash = Calculate_hash (index, Prev_hash, data, timestamp, nonce)
Block_data = {}
block_data[' index '] = Int (last_block.index) + 1
block_data[' timestamp '] = Date.datetime.now ()
block_data[' data '] = "I block #%s"% Last_block.index
block_data[' prev_hash '] = Last_block.hash
block_data[' hash '] = Block_hash
block_data[' nonce '] = nonce
return Block (Block_data)
Excellent. This new blocks contains the valid nonce value so other nodes can validate the hash. We can generate, save, and distribute this new blocks to the rest.
Summary
And that ' s it! For now. There are tons of questions and features for this blockchain, we haven ' t included.
For example, how does other nodes become involved? How would nodes transfer data this they want included in a block? How does we store the information in the blocks other than just a giant string are there a better type of header that doesn ' t Include that giant data string?
https://www.commonlounge.com/discussion/43febd4c34ca4e958c8210ab8a9df319