Commit d366f99d authored by Abhishek Kumar's avatar Abhishek Kumar

Completed txns code

parent fb9756fb
from utils import *
from simulate import Event
class Block:
def __init__(self, peer, ID, transactions, previous_block_ID):
def __init__(self, nodeID, ID, transactions, previous_block_ID):
# Initialize block attributes
self.blk_Id = ID
self.transactions = transactions
self.prev_blk_Id = previous_block_ID
self.pow_user_id = peer
self.pow_user_id = nodeID
return
class Blockchain:
def __init__(self):
# Initialize blockchain attributes
# TODO: Should broadcast the genesis block
self.chain = {}
self.genensis_block = Block(0, [], -1)
self.chain[self.genensis_block.blk_Id] = self.genensis_block
self.head = 0
self.genensis_block = Block(-1, gen_hash(GENESIS_SECRET), [], -1)
self.chain[self.genensis_block.blk_Id] = (self.genensis_block, 0) #
self.head = self.genensis_block.blk_Id
self.len_longest_chain = 1
self.seen_transactions = set()
self.pending_transactions = set()
self.next_pow_completion_time = 0
pass
def get_chain_length(self, blk_Id = None):
def get_chain_length(self, blk_Id=None):
# Return the length of the longest chain
if blk_Id is None:
curr = self.len_longest_chain
curr = self.head
curr = blk_Id
cnt = 0
while(curr != -1):
while curr != self.genensis_block.blk_Id:
if curr not in self.chain:
print("ERROR: Block not found in the chain")
break
......@@ -63,4 +64,19 @@ class Blockchain:
"""
return
def
def print_chain(self):
pass
def already_exist(self, blk):
print(blk, self.chain.get(blk.blk_Id))
exit()
if blk.blk_Id in self.chain:
return True
return False
def received_txn(self, txn):
if txn in self.pending_transactions or txn in self.seen_transactions:
return False
self.pending_transactions.add(txn)
return True
......@@ -3,23 +3,39 @@ from simulate import EventSimulator
import random
from network import Network
def parse_cmd():
"""
Parse command line arguments
"""
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--num_nodes', type = int, default = 50, help="Number of nodes in the network")
parser.add_argument('--z0', type = int, default = 10, help="percentage of node with slow bandwidth")
parser.add_argument('--z1', type = int, default = 10, help="percentage of node with low CPU")
parser.add_argument('--T_tx', type = int, default = 10, help="Interarrival time between transactions")
parser.add_argument('--I', type = int, default = 100, help="Interarrival time between blocks")
parser.add_argument('--T_dij', type = int, default = 10, help="Mean of queuing delay")
#parser.add_argument('--pij', type = int, default = 10, help="speed of light propagation delay")
parser.add_argument('--sim_time', type = int, default = 100, help="Simulation time in seconds")
parser.add_argument('--seed', type = int, default = 0, help="Seed for random number generator")
parser.add_argument(
"-n", "--num_nodes", type=int, default=50, help="Number of nodes in the network"
)
parser.add_argument(
"--z0", type=int, default=10, help="percentage of node with slow bandwidth"
)
parser.add_argument(
"--z1", type=int, default=10, help="percentage of node with low CPU"
)
parser.add_argument(
"--T_tx", type=int, default=10, help="Interarrival time between transactions"
)
parser.add_argument(
"--I", type=int, default=100, help="Interarrival time between blocks"
)
parser.add_argument("--T_dij", type=int, default=10, help="Mean of queuing delay")
# parser.add_argument('--pij', type = int, default = 10, help="speed of light propagation delay")
parser.add_argument(
"--sim_time", type=int, default=100, help="Simulation time in seconds"
)
parser.add_argument(
"--seed", type=int, default=0, help="Seed for random number generator"
)
return parser.parse_args()
if __name__ == '__main__':
if __name__ == "__main__":
args = parse_cmd()
random.seed(args.seed)
......
......@@ -3,15 +3,22 @@ import random
from simulate import Event
from utils import sample_exponential
class Network:
def __init__(self, sim, args):
self.args = args
self.sim = sim
self.pij = float(random.randrange(10, 500)) * 0.001# speed of light propagation delay in ms
# speed of light propagation delay in ms
self.pij = float(random.randrange(10, 500)) * 0.001
self.I = 600
self.create_nodes()
self.create_connections()
self.sim.push_event(Event(0, self.init_simulation,))
self.sim.push_event(
Event(
0,
self.init_simulation,
)
)
return
def init_simulation(self, args):
......@@ -28,13 +35,13 @@ class Network:
# Create a list of badwidth and cpu type based on z0 and z1
# 0 is slow and 1 is fast
bandwidth_type = [1] * self.args.num_nodes
num_slow_bandwidth = int((self.args.z0*self.args.num_nodes)/100)
num_slow_bandwidth = int((self.args.z0 * self.args.num_nodes) / 100)
rand_idx = random.sample(range(self.args.num_nodes), num_slow_bandwidth)
for idx in rand_idx:
bandwidth_type[idx] = 0
cpu_type = [1] * self.args.num_nodes
num_slow_cpu = int((self.args.z1*self.args.num_nodes)/100)
num_slow_cpu = int((self.args.z1 * self.args.num_nodes) / 100)
rand_idx = random.sample(range(self.args.num_nodes), num_slow_cpu)
for idx in rand_idx:
cpu_type[idx] = 0
......@@ -43,7 +50,7 @@ class Network:
# 10 * h_k * (n - num_slow) + h_k * num_slow = 1
# => h_k = 1 / (10 * n - 9 * num_slow)
h_k_slow = 1 / float(10*self.args.num_nodes - 9*num_slow_cpu)
h_k_slow = 1 / float(10 * self.args.num_nodes - 9 * num_slow_cpu)
Tk = []
for i in range(self.args.num_nodes):
if cpu_type[i] == 0:
......@@ -52,9 +59,18 @@ class Network:
Tk.append(10 * (1 - h_k_slow))
for i in range(self.args.num_nodes):
self.nodes.append(Node(self.sim, i, bandwidth_type[i],\
cpu_type[i], float(self.I)/Tk[i], self.args.T_tx,\
self.args.num_nodes, self.pij))
self.nodes.append(
Node(
self.sim,
i,
bandwidth_type[i],
cpu_type[i],
float(self.I) / Tk[i],
self.args.T_tx,
self.args.num_nodes,
self.pij,
)
)
return
def create_connections(self):
......@@ -66,12 +82,20 @@ class Network:
valid_graph = False
cnt = 0
while valid_graph == False:
#print("tyring to create a valid graph",cnt)
# print("tyring to create a valid graph",cnt)
adjacency_list = [[] for _ in range(num_nodes)]
for i in range(num_nodes):
num_connections = random.randint(3, 6)
potential_neighbors = [x for x in range(num_nodes) if x != i and len(adjacency_list[x]) < 6 and x not in adjacency_list[i]]
neighbors = random.sample(potential_neighbors, min(num_connections, len(potential_neighbors)))
potential_neighbors = [
x
for x in range(num_nodes)
if x != i
and len(adjacency_list[x]) < 6
and x not in adjacency_list[i]
]
neighbors = random.sample(
potential_neighbors, min(num_connections, len(potential_neighbors))
)
for j in neighbors:
adjacency_list[i].append(j)
adjacency_list[j].append(i)
......
......@@ -2,8 +2,9 @@ from blockchain import Blockchain
from simulate import Event
from utils import sample_exponential, gen_txn_id, get_txn_id
import random
from utils import *
#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
class Node:
......@@ -11,6 +12,7 @@ class Node:
# Initialize node attributes
self.sim = sim
self.balance = 0
# self.nodeId = gen_hash(str(ID))
self.nodeId = ID
self.cpuType = cpu_type
self.bandwidth_type = bandwidth_type
......@@ -30,11 +32,20 @@ class Node:
"""
# Initialize simulation
# schedule the first transaction
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\
self._event_generate_transaction))
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.sim.push_event(
Event(
self.sim.curr_time + sample_exponential(self.T_tx),
self._event_generate_transaction,
)
)
# 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):
"""
......@@ -42,22 +53,22 @@ class Node:
"""
# check if the bandwidth type is slow for either of the nodes
if(self.bandwidth_type == 1 and node.bandwidth_type == 1):
if self.bandwidth_type == 1 and node.bandwidth_type == 1:
cij = 100
else:
cij = 5
cij *= 1e6
dij = sample_exponential((96*1e3)/cij)
dij = sample_exponential((96 * 1e3) / cij)
latency = dij + self.pij
if(type(data) == str): # transaction
if type(data) == str: # transaction
m = 1024
else:
# TODO(AG): latency for block
m = 1024
return latency + (float(m)/cij)
return latency + (float(m) / cij)
def _event_generate_transaction(self, args):
"""
......@@ -72,15 +83,19 @@ class Node:
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"
txn_str = str(self.nodeId) + " pays " + str(dest) + " " + str(amount) + " coins"
txn = str(gen_hash(txn_str)) + ": " + txn_str
print(self.sim.curr_time, self.nodeId, "Generated a txn:", txn)
self.pending_transactions.append(txn)
self.blockchain.pending_transactions.add(txn)
# schedule the next transaction
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.T_tx),\
self._event_generate_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)
......@@ -91,15 +106,21 @@ class Node:
Event to receive a transaction from a neighbor
"""
txn = txn[0]
print(self.sim.curr_time, self.nodeId, "Received transaction", get_txn_id(txn))
# Receive the transaction and add it to the pending transactions
# If the transaction is new, add it and broadcast to the neighbors
if self.blockchain.receive_txn(txn) == 1:
if self.blockchain.received_txn(txn) == 1:
# Broadcast the received transaction to the neighbors immediately
print(
self.sim.curr_time, self.nodeId, "Received transaction", get_txn_id(txn)
)
self.broadcast_transaction(txn)
else:
print(self.sim.curr_time, self.nodeId, "Already exist, discarding ", get_txn_id(txn))
return
print(
self.sim.curr_time,
self.nodeId,
"TXN exist, discarding ",
get_txn_id(txn),
)
def broadcast_transaction(self, txn):
"""
......@@ -107,16 +128,25 @@ class Node:
"""
print(self.sim.curr_time, self.nodeId, "Broadcasting txn", get_txn_id(txn))
for neighbor in self.neighbors:
print(self.sim.curr_time, self.nodeId, "Sending txn", get_txn_id(txn),\
"to", neighbor.nodeId, self.sim.curr_time\
+ self.get_latency(neighbor, txn))
self.sim.push_event(Event(self.sim.curr_time + self.get_latency(neighbor, txn),\
neighbor._event_receive_transaction, txn))
print(
self.sim.curr_time,
self.nodeId,
"Sending txn",
get_txn_id(txn),
"to",
neighbor.nodeId,
self.sim.curr_time + self.get_latency(neighbor, txn),
)
self.sim.push_event(
Event(
self.sim.curr_time + self.get_latency(neighbor, txn),
neighbor._event_receive_transaction,
txn,
)
)
return
def _event_generate_block(self, blk):
"""
Event to perform create a block and perform PoW and broadcast it
......@@ -132,8 +162,13 @@ class Node:
# Schedule the next block creation event
new_blk = self.blockchain.create_new_block_for_pow()
self.sim.push_event(Event(self.sim.curr_time + sample_exponential(self.Tk),\
self._event_generate_block, new_blk))
self.sim.push_event(
Event(
self.sim.curr_time + sample_exponential(self.Tk),
self._event_generate_block,
new_blk,
)
)
return
def _event_receive_block(self, blk):
......@@ -146,7 +181,7 @@ class Node:
If not valid ignore
"""
if self.blockchain.alread_exist(blk) or self.blockchain.verify_blk(blk) == 0:
if self.blockchain.already_exist(blk) or self.blockchain.verify_blk(blk) == 0:
return
self.blockchain.add_new_mined_block(blk)
......@@ -155,8 +190,13 @@ class Node:
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.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)
......@@ -165,6 +205,14 @@ class Node:
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))
self.sim.push_event(
Event(
self.sim.curr_time + self.get_latency(neighbor, blk),
neighbor._event_receive_blk,
blk,
)
)
return
# def __str__(self): # Hashed node Id
# return str(self.nodeId)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -7,6 +7,7 @@ class Event:
self.time = time
self.operation = operation
self.args = args
def process(self):
#print("Processing event at time", self.time)
return self.operation(self.args)
......@@ -30,7 +31,7 @@ class EventSimulator:
Start the simulation.
Run till the simulation time is reached or the queue is empty
"""
print("Starting the simulation")
print("Starting the simulation...")
while len(self.queue) > 0 and self.queue[0].time < self.sim_time:
event = self.queue.pop(0)
self.curr_time = event.time
......
import random
import hashlib
GENESIS_SECRET = "afa25t#$e09ad&1q0-9quQ8q2_aE8Q^"
def gen_hash(value):
return hashlib.sha256(value.encode("utf-8")).hexdigest()
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