Commit fb9756fb authored by Saswat's avatar Saswat

node implementation of blockchain handling

parent 1406a81e
from utils import *
from simulate import Event
class Block: class Block:
def __init__(self, ID, transactions, previous_block_ID): def __init__(self, peer, ID, transactions, previous_block_ID):
# Initialize block attributes # Initialize block attributes
self.blk_Id = ID
self.transactions = transactions
self.prev_blk_Id = previous_block_ID
self.pow_user_id = peer
return return
class Blockchain: class Blockchain:
def __init__(self): def __init__(self):
# Initialize blockchain attributes # Initialize blockchain attributes
self.chain = {}
self.genensis_block = Block(0, [], -1)
self.chain[self.genensis_block.blk_Id] = self.genensis_block
self.head = 0
self.len_longest_chain = 1
self.seen_transactions = set()
self.pending_transactions = set()
self.next_pow_completion_time = 0
pass pass
def mine_block(peer, blockchain, longest_chain):
# Simulate PoW mining and block creation def get_chain_length(self, blk_Id = None):
pass # Return the length of the longest chain
def validate_block(peer, block): if blk_Id is None:
# Validate transactions in the block curr = self.len_longest_chain
pass curr = blk_Id
def resolve_forks(peer, blockchain, longest_chain): cnt = 0
# Resolve forks and update the longest chain while(curr != -1):
pass if curr not in self.chain:
def update_tree_file(peer, blockchain): print("ERROR: Block not found in the chain")
# Update tree file with block information for each node break
pass curr = self.chain[curr].prev_blk_Id
\ No newline at end of file cnt += 1
return cnt
def receive_txn(self, txn):
"""
Receive transaction from a neighbor
if already seen, return 0 else return 1
"""
if txn in self.seen_transactions:
return 0
else:
self.seen_transactions.add(txn_id)
self.pending_transactions.add(txn)
return 1
def verify_blk(self, blk):
"""
Verify the block
if valid, return 1 else 0
"""
return 1
def add_mined_block(self, blk):
"""
Add the mined block to the blockchain
"""
return
def
from node import Node from node import Node
import random import random
from simulate import Event from simulate import Event
from utils import * from utils import sample_exponential
class Network: class Network:
def __init__(self, sim, args): def __init__(self, sim, args):
self.args = args self.args = args
self.sim = sim self.sim = sim
self.pij = float(random.randrange(10, 500)) * 0.001# speed of light propagation delay in ms self.pij = float(random.randrange(10, 500)) * 0.001# speed of light propagation delay in ms
self.I = 600
self.create_nodes() self.create_nodes()
self.create_connections() self.create_connections()
self.sim.push_event(Event(0, self.init_simulation,)) self.sim.push_event(Event(0, self.init_simulation,))
...@@ -52,7 +53,7 @@ class Network: ...@@ -52,7 +53,7 @@ class Network:
for i in range(self.args.num_nodes): for i in range(self.args.num_nodes):
self.nodes.append(Node(self.sim, i, bandwidth_type[i],\ self.nodes.append(Node(self.sim, i, bandwidth_type[i],\
cpu_type[i], Tk[i], self.args.T_tx,\ cpu_type[i], float(self.I)/Tk[i], self.args.T_tx,\
self.args.num_nodes, self.pij)) self.args.num_nodes, self.pij))
return return
......
from blockchain import Blockchain from blockchain import Blockchain
from simulate import Event from simulate import Event
from utils import * from utils import sample_exponential, gen_txn_id, get_txn_id
import random
#TODO(SM): Need to bind each transaction with a time of arrival at a node #TODO(SM): Need to bind each transaction with a time of arrival at a node
txn_id = 0
def gen_txn_id():
global txn_id
txn_id += 1
return txn_id
def get_txn_id(txn):
return txn.split(":")[0]
class Node: class Node:
def __init__(self, sim, ID, bandwidth_type, cpu_type, Tk, T_tx, num_nodes, pij): def __init__(self, sim, ID, bandwidth_type, cpu_type, Tk, T_tx, num_nodes, pij):
...@@ -22,14 +15,13 @@ class Node: ...@@ -22,14 +15,13 @@ class Node:
self.cpuType = cpu_type self.cpuType = cpu_type
self.bandwidth_type = bandwidth_type self.bandwidth_type = bandwidth_type
self.Tk = Tk self.Tk = Tk
self.I = 600
self.T_tx = T_tx self.T_tx = T_tx
self.num_nodes = num_nodes self.num_nodes = num_nodes
self.pij = pij self.pij = pij
self.neighbors = [] self.neighbors = []
self.blockchain = Blockchain() self.blockchain = Blockchain()
self.pending_transactions = []
def init_simulation(self): def init_simulation(self):
""" """
...@@ -40,7 +32,9 @@ class Node: ...@@ -40,7 +32,9 @@ class Node:
# schedule the first transaction # schedule the first transaction
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\ self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\
self._event_generate_transaction)) self._event_generate_transaction))
pass
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.Tk),\
self._event_generate_block, self.blockchain.create_new_block_for_pow()))
def get_latency(self, node, data): def get_latency(self, node, data):
""" """
...@@ -65,14 +59,42 @@ class Node: ...@@ -65,14 +59,42 @@ class Node:
return latency + (float(m)/cij) return latency + (float(m)/cij)
def _event_generate_transaction(self, args):
"""
Generate a transaction for the given peer
Format: "TxnID: IDx pays IDy C coins"
"""
# Select a random destination node and amount
dest = self.nodeId
while dest == self.nodeId:
dest = random.randint(0, self.num_nodes)
amount = random.randint(1, self.balance + 10)
# Create a transaction and it to current nodes pending transactions
txn = str(gen_txn_id()) + ": " + str(self.nodeId) + " pays "\
+ str(dest) + " " + str(amount) + " coins"
print(self.sim.curr_time, self.nodeId, "Generated a txn:", txn)
self.pending_transactions.append(txn)
# schedule the next transaction
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\
self._event_generate_transaction))
# broadcast the transaction to the neighbors
self.broadcast_transaction(txn)
pass
def _event_receive_transaction(self, txn): def _event_receive_transaction(self, txn):
""" """
Event to receive a transaction from a neighbor Event to receive a transaction from a neighbor
""" """
txn = txn[0] txn = txn[0]
print(self.sim.curr_time, self.nodeId, "Received transaction", get_txn_id(txn)) print(self.sim.curr_time, self.nodeId, "Received transaction", get_txn_id(txn))
if txn not in self.pending_transactions: # Receive the transaction and add it to the pending transactions
self.pending_transactions.append(txn) # If the transaction is new, add it and broadcast to the neighbors
if self.blockchain.receive_txn(txn) == 1:
# Broadcast the received transaction to the neighbors immediately # Broadcast the received transaction to the neighbors immediately
self.broadcast_transaction(txn) self.broadcast_transaction(txn)
else: else:
...@@ -93,29 +115,56 @@ class Node: ...@@ -93,29 +115,56 @@ class Node:
neighbor._event_receive_transaction, txn)) neighbor._event_receive_transaction, txn))
return return
def _event_generate_transaction(self, args):
def _event_generate_block(self, blk):
""" """
Generate a transaction for the given peer Event to perform create a block and perform PoW and broadcast it
Format: "TxnID: IDx pays IDy C coins"
""" """
# discard the event if the time is not right
# this means this event has been overriden
if self.sim.curr_time != self.blockchain.next_pow_completion_time:
return
# Select a random destination node and amount # Add the block it to the blockchain and broadcast it to the neighbors
dest = self.nodeId self.blockchain.add_new_mined_block(blk)
while dest == self.nodeId: self.broadcast_block(blk)
dest = random.randint(0, self.num_nodes)
amount = random.randint(1, self.balance + 10)
# Create a transaction and it to current nodes pending transactions # Schedule the next block creation event
txn = str(gen_txn_id()) + ": " + str(self.nodeId) + " pays "\ new_blk = self.blockchain.create_new_block_for_pow()
+ str(dest) + " " + str(amount) + " coins" self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.Tk),\
print(self.sim.curr_time, self.nodeId, "Generated a txn:", txn) self._event_generate_block, new_blk))
return
self.pending_transactions.append(txn) def _event_receive_block(self, blk):
"""
Event to receive a block from a neighbor
Receive the block and validate it's transactions / hash
If valid, check if it is the longest chain
If it is the longest chain, add this block to the blockchain
Schedule the next block creation event
If not valid ignore
"""
# schedule the next transaction if self.blockchain.alread_exist(blk) or self.blockchain.verify_blk(blk) == 0:
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\ return
self._event_generate_transaction))
# broadcast the transaction to the neighbors self.blockchain.add_new_mined_block(blk)
self.broadcast_transaction(txn) print(self.sim.curr_time, self.nodeId, "Received block", blk.blkId)
pass chain_length = self.blockchain.get_chain_length(blk)
if chain_length > self.blockchain.len_longest_chain:
self.blockchain.len_longest_chain = self.blockchain.get_chain_length(blk)
self.blockchain.head = blk.blkId
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.Tk),\
self._event_generate_block, self.blockchain.create_new_block_for_pow()))
self.broadcast_block(blk)
def broadcast_block(self, blk):
"""
Broadcast the block to the neighbors
"""
for neighbor in self.neighbors:
self.sim.push_event(Event(self.sim.curr_time + self.get_latency(neighbor, blk),\
neighbor._event_receive_blk, blk))
return
\ No newline at end of file
...@@ -2,3 +2,20 @@ import random ...@@ -2,3 +2,20 @@ import random
def sample_exponential(mean): def sample_exponential(mean):
return random.expovariate(1/mean) return random.expovariate(1/mean)
txn_id = 0
def gen_txn_id():
global txn_id
txn_id += 1
return txn_id
def get_txn_id(txn):
return txn.split(":")[0]
blk_id = 0
def gen_blk_id():
global blk_id
blk_id += 1
return blk_id
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment