added test_nodes, which simulates 3 p2pool nodes mining and exchanging shares
[p2pool.git] / p2pool / test / test_node.py
1 from __future__ import division
2
3 import random
4
5 from twisted.internet import defer, reactor
6 from twisted.trial import unittest
7 from twisted.web import resource, server
8
9 from p2pool import networks, node, work
10 from p2pool.bitcoin import worker_interface
11 from p2pool.util import deferral, jsonrpc, variable
12
13 class factory(object):
14     new_headers = variable.Event()
15     new_block = variable.Event()
16     new_tx = variable.Event()
17     conn = variable.Variable(None)
18     @classmethod
19     def getProtocol(self):
20         return defer.Deferred()
21
22 class bitcoind(object):
23     @classmethod
24     def rpc_help(self):
25         return '\ngetblock '
26     
27     @classmethod
28     def rpc_getblock(self, block_hash_hex):
29         return dict(height=42)
30     
31     @classmethod
32     def rpc_getmemorypool(self):
33         return {
34             "version" : 2,
35             "previousblockhash" : "000000000000016c169477c25421250ec5d32cf9c6d38538b5de970a2355fd89",
36             "transactions" : [
37             ],
38             "coinbaseaux" : {
39                 "flags" : "062f503253482f"
40             },
41             "coinbasevalue" : 5044450000,
42             "target" : "0000000000000513c50000000000000000000000000000000000000000000000",
43             "mintime" : 1351655621,
44             "mutable" : [
45                 "time",
46                 "transactions",
47                 "prevblock"
48             ],
49             "noncerange" : "00000000ffffffff",
50             "sigoplimit" : 20000,
51             "sizelimit" : 1000000,
52             "curtime" : 1351659940,
53             "bits" : "1a0513c5",
54             "height" : 205801
55         }
56
57 class MiniNode(object):
58     @classmethod
59     @defer.inlineCallbacks
60     def start(cls, net, factory, bitcoind, peer_ports):
61         self = cls()
62         
63         self.n = node.Node(factory, bitcoind, [], [], net)
64         yield self.n.start()
65         
66         self.n.p2p_node = node.P2PNode(self.n, 0, 1000000, {}, [('127.0.0.1', peer_port) for peer_port in peer_ports])
67         self.n.p2p_node.start()
68         
69         wb = work.WorkerBridge(node=self.n, my_pubkey_hash=random.randrange(2**160), donation_percentage=random.uniform(0, 10), merged_urls=[], worker_fee=3)
70         web_root = resource.Resource()
71         worker_interface.WorkerInterface(wb).attach_to(web_root)
72         self.web_port = reactor.listenTCP(0, server.Site(web_root))
73         
74         defer.returnValue(self)
75     
76     @defer.inlineCallbacks
77     def stop(self):
78         yield self.web_port.stopListening()
79         yield self.n.p2p_node.stop()
80         yield self.n.stop()
81         del self.web_port, self.n
82
83 class Test(unittest.TestCase):
84     @defer.inlineCallbacks
85     def test_node(self):
86         net = networks.nets['litecoin_testnet']
87         n = node.Node(factory, bitcoind, [], [], net)
88         yield n.start()
89         
90         wb = work.WorkerBridge(node=n, my_pubkey_hash=42, donation_percentage=2, merged_urls=[], worker_fee=3)
91         web_root = resource.Resource()
92         worker_interface.WorkerInterface(wb).attach_to(web_root)
93         port = reactor.listenTCP(0, server.Site(web_root))
94         
95         proxy = jsonrpc.Proxy('http://127.0.0.1:' + str(port.getHost().port))
96         
97         yield deferral.sleep(3)
98         
99         for i in xrange(100):
100             blah = yield proxy.rpc_getwork()
101             yield proxy.rpc_getwork(blah['data'])
102         
103         yield deferral.sleep(3)
104         
105         assert len(n.tracker.items) == 100
106         assert n.tracker.verified.get_height(n.best_share_var.value) == 100
107         
108         n.stop()
109         
110         yield port.stopListening()
111         del net, n, wb, web_root, port, proxy
112         import gc
113         gc.collect()
114         gc.collect()
115         gc.collect()
116         
117         yield deferral.sleep(20) # waiting for work_poller to exit
118     
119     @defer.inlineCallbacks
120     def test_nodes(self):
121         net = networks.nets['litecoin_testnet']
122         N = 3
123         
124         nodes = []
125         for i in xrange(N):
126             nodes.append((yield MiniNode.start(net, factory, bitcoind, [mn.n.p2p_node.serverfactory.listen_port.getHost().port for mn in nodes])))
127         
128         yield deferral.sleep(3)
129         
130         for i in xrange(100):
131             proxy = jsonrpc.Proxy('http://127.0.0.1:' + str(random.choice(nodes).web_port.getHost().port))
132             blah = yield proxy.rpc_getwork()
133             yield proxy.rpc_getwork(blah['data'])
134             yield deferral.sleep(random.expovariate(1/.1))
135     
136         yield deferral.sleep(3)
137         
138         for i, n in enumerate(nodes):
139             assert len(n.n.tracker.items) == 100, (i, len(n.n.tracker.items))
140             assert n.n.tracker.verified.get_height(n.n.best_share_var.value) == 100, (i, n.n.tracker.verified.get_height(n.n.best_share_var.value))
141         
142         for n in nodes:
143             yield n.stop()
144         
145         del nodes, n
146         import gc
147         gc.collect()
148         gc.collect()
149         gc.collect()
150         
151         yield deferral.sleep(20) # waiting for work_poller to exit