Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
Forked from Andrew and tested different tip pool explosion methods

# IOTA Access Control Simulator
Python simulator for the IOTA Access/Congestion Control Algorithm (ICCA).

Expand All @@ -24,4 +22,4 @@ On Windows machines, it seems that you will need to create the environment from
# Running Dash app
Go to the `global_params.py` file and ensure that `DASH=True`.

Run `main.py` and a browser window should open showing the live plots from the simulation.
Run `main.py` and a browser window should open showing the live plots from the simulation.
Binary file modified core/__pycache__/global_params.cpython-39.pyc
Binary file not shown.
Binary file modified core/__pycache__/message.cpython-39.pyc
Binary file not shown.
Binary file modified core/__pycache__/node.cpython-39.pyc
Binary file not shown.
11 changes: 7 additions & 4 deletions core/global_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Simulation Parameters
MONTE_CARLOS = 1
SIM_TIME = 300
SIM_TIME = 1200
STEP = 0.01
# Network Parameters
NU = 20
Expand Down Expand Up @@ -61,8 +61,11 @@
# Tip selection
L_MAX = 300
OWN_TXS = True
MAX_TIP_AGE = 70 #30
TSC = 80
MAX_TIP_AGE = 30 #30

#TSC condition threshold
TSC_Th = 25
Last_IssuTiime = 80

# Gossip optimisation
PRUNING = False
Expand All @@ -74,7 +77,7 @@
MILESTONE_PERIOD = 10
COO = 0
## Cumulative Weight (CW)
CONF_WEIGHT = 200
CONF_WEIGHT = 10

# Attacker details
## Tip selection
Expand Down
112 changes: 110 additions & 2 deletions core/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ def __init__(self, IssueTime, Parents, Node, Network, Work=0, Index=None, Visibl
self.InScheduletime = InScheduletime
self.MessageInFlag = MessageInFlag
self.Parents = Parents
self.Children = []

self.Network = Network
self.Index = Network.MsgIndex
self.Milestone = Milestone
Expand All @@ -23,29 +25,56 @@ def __init__(self, IssueTime, Parents, Node, Network, Work=0, Index=None, Visibl
self.LastCWUpdate = self
self.Dropped = False
self.ConfirmedTime = None
self.LastConfirm = self
self.Time1 = []
self.q = []
self.k = {}
self.Pastcone = [[] for i in range(100)]
self.TXConfirmedtime = [[] for i in range(100)]
self.layer= 0
self.Parentcone = [[] for i in range(1000)]


self.Orphan = False
self.Maxconcone = 0



if Node:
self.Solid = False
self.NodeID = Node.NodeID # signature of issuing node
self.Eligible = False
self.Confirmed = False
self.EligibleTime = None
self.Pastcone[0].append(self)
self.TXConfirmedtime[0].append(self.ConfirmedTime)
Network.MsgIssuer[Network.MsgIndex] = Node.NodeID
else: # genesis
self.Solid = True
self.NodeID = 0 # Genesis is issued by Node 0
self.Pastcone[0].append(self)
self.TXConfirmedtime[0].append(self.ConfirmedTime)
self.Eligible = True
self.Confirmed = True
self.EligibleTime = 0
self.ConfirmedTime = IssueTime
Network.MsgIndex += 1


def mark_confirmed(self, Node = None, Confirtime=None):
self.Confirmed = True
self.ConfirmedTime = Confirtime
self.Network.Nodes[self.NodeID].AllTXconfirmedtime.append(self.ConfirmedTime-self.IssueTime)
# self.ConChilup()
# self.TXConupdate(Node)


assert Node.NodeID in self.Network.ScheduledNodes[self.Index]
assert not Node.NodeID in self.Network.ConfirmedNodes[self.Index]
self.Network.ConfirmedNodes[self.Index].append(Node.NodeID)
if len(self.Network.ConfirmedNodes[self.Index])==NUM_NODES:
self.Network.Nodes[self.NodeID].UnconfMsgs.pop(self.Index)
if self.Index in self.Network.Nodes[self.NodeID].UnconfMsgs:
self.Network.Nodes[self.NodeID].UnconfMsgs.pop(self.Index)
self.Network.Nodes[self.NodeID].ConfMsgs[self.Index] = self
for _,p in self.Parents.items():
if not p.Confirmed:
Expand All @@ -66,7 +95,84 @@ def updateCW(self, Node, updateMsg=None, Work=None, UPdateCWtime=None):
for _,p in self.Parents.items():
if not p.Confirmed and p.LastCWUpdate != updateMsg:
p.updateCW(Node, updateMsg, Work, UPdateCWtime)



def TXEcheck(self, Node, Time):

'''
Object to do BFS for new incoming tip
'''
layer= 0
Elenumber =[]
historycone = []
CheckedTime = []
Break_flag = False

while [True for kk in self.Pastcone[layer] if kk not in Elenumber] and self.Pastcone[layer]!=[] and not Break_flag:
if Elenumber!=[]:
for j in self.Pastcone[layer-1]:
if j in Elenumber:
Elenumber.remove(j)

for i in self.Pastcone[layer]:
if not Break_flag:
if i not in Elenumber:
Elenumber.append(i)

if i in self.Pastcone[layer]:
if self.Pastcone[layer].index(i)==0:
layer+=1

if Time-i.IssueTime<Last_IssuTiime:
if len(i.Parents)==0:
break
else:
for _,p in i.Parents.items():
self.Pastcone[layer].append(p)
# print(self, self.Pastcone[0][0], p, Node.NodeID)

# check whether there are same transactions in this layer
Dulcheck = []
for k in self.Pastcone[layer]:
if k not in Dulcheck:
Dulcheck.append(k)

# check whether there are same transactions in this layer
self.Pastcone[layer] = Dulcheck
for k in range(layer):
if len(self.Pastcone[k])!=0:
for jj in self.Pastcone[k]:
historycone.append(jj)


for k in self.Pastcone[layer]:
if k in historycone:
self.Pastcone[layer].remove(k)


for k in range(layer+1):
if len(self.Pastcone[k])!=0:
for p in self.Pastcone[k]:
if p.ConfirmedTime!=None:
self.TXConfirmedtime[k].append(p.ConfirmedTime)
if Time-p.ConfirmedTime<=TSC_Th:
Break_flag = True
break



for i in self.TXConfirmedtime:
if len(i)!=0:
for j in i:
if j!=None:
CheckedTime.append(j)

if CheckedTime:
return max(CheckedTime)
else:
return None


def copy(self, Node):
Msg = copy(self)
parentIDs = [p for p in Msg.Parents]
Expand Down Expand Up @@ -122,6 +228,8 @@ def solidify(self, Node, TxNode=None, Time=None):
assert self.IssueTime < child.IssueTime
child.solidify(Node)



class SolRequest:
'''
Object to request solidification of a transaction
Expand Down
114 changes: 93 additions & 21 deletions core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ def __init__(self, Network, NodeID, Genesis, PoWDelay = 1):
self.MissingParentIDs = {}
self.Max_buffer = 200 # W_max
self.Inboxin = 2
self.Delayconfirmedtime = []
self.ConfirmedTip = []
self.AllTXconfirmedtime = []


self.Heap = []

def issue_msgs(self, Time):
"""
Expand All @@ -76,6 +82,11 @@ def issue_msgs(self, Time):
self.LastIssueTime = max(OldestMsgTime, self.LastIssueTime+self.LastIssueWork/self.Lambda)
Msg = self.MsgPool.pop(0)
Msg.Parents = self.select_tips(Time)

for _,p in Msg.Parents.items():
p.Children.append(Msg)


Msg.IssueTime = self.LastIssueTime
self.LastIssueWork = Msg.Work
self.IssuedMsgs.append(Msg)
Expand All @@ -85,7 +96,11 @@ def issue_msgs(self, Time):
for t in times:
Parents = self.select_tips(Time)
self.IssuedMsgs.append(Message(t, Parents, self, self.Network, Work=Work))

Msg = Message(t, Parents, self, self.Network, Work=Work)

for _,p in Msg.Parents.items():
p.Children.append(Msg)

# Issue the messages
while self.IssuedMsgs:
Msg = self.IssuedMsgs.pop(0)
Expand All @@ -105,6 +120,9 @@ def add_tip(self, tip):
"""
self.TipsSet.append(tip)
self.NodeTipsSet[tip.NodeID].append(tip)




def remove_tip(self, tip):
"""
Expand All @@ -121,28 +139,42 @@ def select_tips(self, Time):
while not done:
done = True
if len(self.TipsSet)>1:
# ts = self.TipsSet
ConfirmedTip = [i for i in self.TipsSet if i.ConfirmedTime!=None]
OkTip= [i for i in ConfirmedTip if Time-i.ConfirmedTime<=TSC]
if len(OkTip)<=2:
ts= self.TipsSet
else:
ts= OkTip
ts = self.TipsSet
# if Msg.ConfirmedTime!=None:
# if Time-Msg.ConfirmedTime<=TSC:
self.ConfirmedTip = [i for i in self.TipsSet if i.Confirmed]

# # # ParentContip = [i.Parents for i in ConfirmedTip]
# # # kkk= [[] for i in range(len(ParentContip))]
# # # for j in range(len(ParentContip)):
# # # for value in ParentContip[j].values():
# # # kkk[j].append(value.ConfirmedTime)

# # # for i in range(len(ConfirmedTip)):
# # # for j in range(len(kkk[i])):
# # # if ConfirmedTip[i].ConfirmedTime - j<=TSC:
# # # OkTip.append(ConfirmedTip[i])

# OkTip= [i for i in ConfirmedTip if Time-i.ConfirmedTime<=TSC]
# if len(OkTip)<=2:
# ts= self.TipsSet
# else:
# ts= OkTip
Selection = sample(ts, k=2)
else:
eligibleLedger = [msg for _,msg in self.Ledger.items() if msg.Eligible]

ConfirmedTip = [i for i in eligibleLedger if i.ConfirmedTime!=None]
OkTip= [i for i in ConfirmedTip if Time-i.ConfirmedTime<=TSC]
if len(OkTip)<=2:
neweligibleLedger= eligibleLedger
else:
neweligibleLedger= OkTip
self.ConfirmedTip = [i for i in eligibleLedger if i.Confirmed]
# ConfirmedTip = [i for i in eligibleLedger if i.ConfirmedTime!=None]
# OkTip= [i for i in ConfirmedTip if Time-i.ConfirmedTime<=TSC]
# if len(OkTip)<=2:
# neweligibleLedger= eligibleLedger
# else:
# neweligibleLedger= OkTip

if len(neweligibleLedger)>1:
Selection = sample(neweligibleLedger, k=2)
if len(eligibleLedger)>1:
Selection = sample(eligibleLedger, k=2)
else:
Selection = neweligibleLedger # genesis
Selection = eligibleLedger # genesis
assert len(Selection)==2 or Selection[0].Index==0
return {s.Index: s for s in Selection}

Expand Down Expand Up @@ -202,16 +234,32 @@ def update_tipsset(self, Msg, Time):
If the oldest unconfirmed message in the past cone of the tip (time since confirmation) is too far in the past,
the message is discarded from the selection but temporarily kept in the tip set.

ConfirmedTip = [i for i in self.TipsSet if i.ConfirmedTime!=None]
"""

self.Inbox.update_ready()

#self.add_tip(Msg)
# Normal tip update
if OWN_TXS or Msg.NodeID!=self.NodeID or MODE[self.NodeID]>=3:
if MAX_TIP_AGE is None:
self.add_tip(Msg)
elif Time-Msg.IssueTime < MAX_TIP_AGE:

# tt=Msg.contime(self, Time)
# if tt is not None:
# self.Delayconfirmedtime.append(tt)
# # self.add_tip(Msg)
# # if MAX_TIP_AGE is None:
if Time>TSC_Th:
tt = Msg.TXEcheck(self, Time)
if tt is not None:
self.Delayconfirmedtime.append(tt)
if tt is not None and Time-tt<=TSC_Th:
self.add_tip(Msg)
else:
self.add_tip(Msg)




# if this is a malicious nodes own message and ATK_TIP_RM_PARENTS is False, then don't remove the tips it selected as parents
if MODE[self.NodeID]>=3 and Msg.NodeID==self.NodeID and not ATK_TIP_RM_PARENTS:
pass
Expand Down Expand Up @@ -258,10 +306,34 @@ def schedule(self, TxNode, Msg: Message, Time):
Msg.mark_confirmed(self)
Msg.Eligible = True
self.update_tipsset(Msg, Time)

# if len(self.UnconfMsgs)!=0:
# self.Unconsgcheck(Time)


Msg.EligibleTime = Time
# broadcast the packet
self.forward(TxNode, Msg, Time)


# def Unconsgcheck(self,Time):

# Msg = self.UnconfMsgs.copy()

# sorted(Msg, key=lambda x: self.UnconfMsgs[x].IssueTime)

# for _,i in list(Msg.items()):
# if Time-i.IssueTime>=150:
# self.UnconfMsgs.pop(_)
# else:
# break


# for _,p in list(self.UnconfMsgs.items()):
# if p.Orphan:
# self.UnconfMsgs.pop(_)


def forward(self, TxNode, Msg, Time):
"""
By default, nodes forward to all neighbours except the one they received the TX from.
Expand Down
Loading