Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
blockchain_CS765_HW1
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Saswat
blockchain_CS765_HW1
Commits
d366f99d
Commit
d366f99d
authored
Feb 06, 2024
by
Abhishek Kumar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Completed txns code
parent
fb9756fb
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1223 additions
and
120 deletions
+1223
-120
blockchain.py
blockchain.py
+37
-21
main.py
main.py
+29
-13
network.py
network.py
+43
-19
node.py
node.py
+110
-62
sim.log
sim.log
+985
-0
simulate.py
simulate.py
+2
-1
utils.py
utils.py
+17
-4
No files found.
blockchain.py
View file @
d366f99d
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
main.py
View file @
d366f99d
...
...
@@ -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
)
...
...
network.py
View file @
d366f99d
...
...
@@ -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
)
...
...
node.py
View file @
d366f99d
...
...
@@ -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
.
appen
d
(
txn
)
self
.
blockchain
.
pending_transactions
.
ad
d
(
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
.
receive
d
_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
.
alread
y
_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)
sim.log
0 → 100644
View file @
d366f99d
This source diff could not be displayed because it is too large. You can
view the blob
instead.
simulate.py
View file @
d366f99d
...
...
@@ -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
...
...
utils.py
View file @
d366f99d
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment