added MIN_TARGET attribute to p2pool network definitions for testing
[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 node, work
10 from p2pool.bitcoin import networks, worker_interface
11 from p2pool.util import deferral, jsonrpc, math, 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 mynet = math.Object(
58     PARENT=networks.nets['litecoin_testnet'],
59     SHARE_PERIOD=3, # seconds
60     CHAIN_LENGTH=20*60//3, # shares
61     REAL_CHAIN_LENGTH=20*60//3, # shares
62     TARGET_LOOKBEHIND=200, # shares
63     SPREAD=12, # blocks
64     IDENTIFIER='cca5e24ec6408b1e'.decode('hex'),
65     PREFIX='ad9614f6466a39cf'.decode('hex'),
66     P2P_PORT=19338,
67     MIN_TARGET=2**256 - 1,
68     MAX_TARGET=2**256 - 1,
69     PERSIST=False,
70     WORKER_PORT=19327,
71     BOOTSTRAP_ADDRS='72.14.191.28'.split(' '),
72     ANNOUNCE_CHANNEL='#p2pool-alt',
73     VERSION_CHECK=lambda v: True,
74 )
75
76 class MiniNode(object):
77     @classmethod
78     @defer.inlineCallbacks
79     def start(cls, net, factory, bitcoind, peer_ports):
80         self = cls()
81         
82         self.n = node.Node(factory, bitcoind, [], [], net)
83         yield self.n.start()
84         
85         self.n.p2p_node = node.P2PNode(self.n, 0, 1000000, {}, [('127.0.0.1', peer_port) for peer_port in peer_ports])
86         self.n.p2p_node.start()
87         
88         wb = work.WorkerBridge(node=self.n, my_pubkey_hash=random.randrange(2**160), donation_percentage=random.uniform(0, 10), merged_urls=[], worker_fee=3)
89         web_root = resource.Resource()
90         worker_interface.WorkerInterface(wb).attach_to(web_root)
91         self.web_port = reactor.listenTCP(0, server.Site(web_root))
92         
93         defer.returnValue(self)
94     
95     @defer.inlineCallbacks
96     def stop(self):
97         yield self.web_port.stopListening()
98         yield self.n.p2p_node.stop()
99         yield self.n.stop()
100         del self.web_port, self.n
101
102 class Test(unittest.TestCase):
103     @defer.inlineCallbacks
104     def test_node(self):
105         n = node.Node(factory, bitcoind, [], [], mynet)
106         yield n.start()
107         
108         wb = work.WorkerBridge(node=n, my_pubkey_hash=42, donation_percentage=2, merged_urls=[], worker_fee=3)
109         web_root = resource.Resource()
110         worker_interface.WorkerInterface(wb).attach_to(web_root)
111         port = reactor.listenTCP(0, server.Site(web_root))
112         
113         proxy = jsonrpc.Proxy('http://127.0.0.1:' + str(port.getHost().port))
114         
115         yield deferral.sleep(3)
116         
117         for i in xrange(100):
118             blah = yield proxy.rpc_getwork()
119             yield proxy.rpc_getwork(blah['data'])
120         
121         yield deferral.sleep(3)
122         
123         assert len(n.tracker.items) == 100
124         assert n.tracker.verified.get_height(n.best_share_var.value) == 100
125         
126         n.stop()
127         
128         yield port.stopListening()
129         del n, wb, web_root, port, proxy
130         import gc
131         gc.collect()
132         gc.collect()
133         gc.collect()
134         
135         yield deferral.sleep(20) # waiting for work_poller to exit
136     
137     @defer.inlineCallbacks
138     def test_nodes(self):
139         N = 3
140         
141         nodes = []
142         for i in xrange(N):
143             nodes.append((yield MiniNode.start(mynet, factory, bitcoind, [mn.n.p2p_node.serverfactory.listen_port.getHost().port for mn in nodes])))
144         
145         yield deferral.sleep(3)
146         
147         for i in xrange(100):
148             proxy = jsonrpc.Proxy('http://127.0.0.1:' + str(random.choice(nodes).web_port.getHost().port))
149             blah = yield proxy.rpc_getwork()
150             yield proxy.rpc_getwork(blah['data'])
151             yield deferral.sleep(random.expovariate(1/.1))
152     
153         yield deferral.sleep(3)
154         
155         for i, n in enumerate(nodes):
156             assert len(n.n.tracker.items) == 100, (i, len(n.n.tracker.items))
157             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))
158         
159         for n in nodes:
160             yield n.stop()
161         
162         del nodes, n
163         import gc
164         gc.collect()
165         gc.collect()
166         gc.collect()
167         
168         yield deferral.sleep(20) # waiting for work_poller to exit