-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtaint_analysis.py
102 lines (91 loc) · 3.1 KB
/
taint_analysis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import sys, heapq
import numpy as np
import pymysql as mdb
NULL_HASH = 64*'0'
class PriorityDict():
def __init__(self):
self.heap = [] # for keys of self.elements
self.elements = {}
def add(self,element):
priority = element.blockNumber
key = (element.transactionHash,element.outputIndex)
if key not in self.elements:
heapq.heappush(self.heap,(priority,key))
self.elements[key] = element
def pop(self):
priority,key = heapq.heappop(self.heap)
return self.elements[key]
def __len__(self):
return len(self.heap)
def __getitem__(self,output):
return self.elements[(output.transactionHash,output.outputIndex)]
class Output:
def __init__(self,parameters,taint=0):
self.amount = 0.0
self.taint = 0.0
self.blockNumber = parameters[0]
self.outputIndex = parameters[1]
self.spendHash = parameters[2]
self.transactionHash = parameters[3]
self.value = parameters[4]
def __hash__(self):
return hash((self.outputIndex,self.transactionHash))
def __eq__(self,other):
return hash(self) == hash(other)
con = mdb.connect('localhost','root','','bitcoin')
cur = con.cursor()
def getTxInputValue(transaction_hash):
command = 'SELECT SUM(value) FROM outputs WHERE spendHash = "%s"'
command = command % (transaction_hash)
cur.execute(command)
return cur.fetchone()[0]
def getTxOutputValue(transaction_hash):
command = 'SELECT SUM(value) FROM outputs WHERE transactionHash = "%s"'
command = command % (transaction_hash)
cur.execute(command)
return cur.fetchone()[0]
def getSourceOutputs(source_address):
command = 'SELECT blockNumber, outputIndex, spendHash, transactionHash, value '
command += 'FROM outputs WHERE address = "%s"' %source_address
cur.execute(command)
sources = PriorityDict()
for entry in cur.fetchall():
output = Output(entry)
output.amount = output.value
output.taint = 1.0
sources.add(output)
return sources
def getLinkedOutputs(output):
command = 'SELECT blockNumber,outputIndex,spendHash,transactionHash,value '
command += 'FROM outputs WHERE transactionHash = "%s"'
command = command % output.spendHash
cur.execute(command)
return [Output(entry) for entry in cur.fetchall()]
tainteds = getSourceOutputs(sys.argv[1])
popped = 0
for tainted in tainteds.elements.values():
tainteds[tainted].amount = tainted.value
unspent_outputs = []
while len(tainteds) > 0:
output = tainteds.pop()
if output.amount < 1e12 or output.amount / output.value < .4:
print output.transactionHash,output.spendHash,
print '%e' %output.amount,
print '%.3f' %(output.amount / output.value)
continue
elif output.spendHash == NULL_HASH:
unspent_outputs.append(output)
else:
print output.transactionHash,output.spendHash,
print '%e' %output.amount,
print '%.3f' %(output.amount / output.value)
txOutputValue = float(getTxOutputValue(output.spendHash))
for linked_output in getLinkedOutputs(output):
tainteds.add(linked_output)
for linked_output in getLinkedOutputs(output):
weight = linked_output.value / txOutputValue
increment = weight * tainteds[output].amount
tainteds[linked_output].amount += increment
popped += 1
if popped % 1000 == 0:
print len(tainteds), popped