Skip to content

Commit 4ce513c

Browse files
committed
Bootstrap infrastucture code
- new config file options for bootstrap nodes - new config file option for testnet - update docker and docker compose to for easier running of boostrap nodes and testnet nodes
1 parent 15ecf31 commit 4ce513c

File tree

10 files changed

+162
-11
lines changed

10 files changed

+162
-11
lines changed

buildscripts/bootstrap/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This directory is for deploying bootstrap and test infrastructure for
2+
PyBitmessage.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
version: "3"
3+
name: pybitmessage
4+
services:
5+
bootstrap:
6+
image: pybitmessage/bootstrap:latest
7+
build: ..
8+
env_file:
9+
- /etc/pybitmessage.conf
10+
ports:
11+
- 127.0.0.1::8444
12+
deploy:
13+
replicas: $THREADS
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/bash
2+
3+
apt -y install curl jq ipvsadm libyajl2
4+
5+
EXTIP=$(curl -s telnetmyip.com|jq -r .ip)
6+
if [ ! -e .env ]; then
7+
THREADS=$(nproc --all)
8+
PASSWORD=$(tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo)
9+
cat > .env << EOF
10+
THREADS=$THREADS
11+
PASSWORD=$PASSWORD
12+
EOF
13+
else
14+
. .env
15+
fi
16+
17+
ipvsadm -C
18+
ipvsadm -A -t ${EXTIP}:8444 -s rr
19+
ipvsadm -A -t ${EXTIP}:8080 -s rr
20+
21+
docker compose up -d
22+
23+
CF=/etc/collectd/collectd.conf.d/curl_json.conf.new
24+
CF_LIVE=/etc/collectd/collectd.conf.d/curl_json.conf
25+
26+
echo "LoadPlugin curl_json" > $CF
27+
echo "<Plugin curl_json>" >> $CF
28+
29+
for i in `seq 1 $THREADS`; do
30+
cont="pybitmessage-bootstrap-${i}"
31+
IP=$(docker inspect -f
32+
'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
33+
$cont 2>/dev/null)
34+
[ -z "$IP" ] && continue
35+
echo "Adding $IP"
36+
ipvsadm -a -t ${EXTIP}:8444 -r ${IP}:8444 -m
37+
ipvsadm -a -t ${EXTIP}:8080 -r ${IP}:8444 -m
38+
INSTANCE=$(echo $cont|tr - _)
39+
cat >> $CF << EOF
40+
<URL "http://$IP:8442/">
41+
Plugin "pybitmessagestatus"
42+
Instance "$INSTANCE"
43+
User "api"
44+
Password "$PASSWORD"
45+
Post "{\"jsonrpc\":\"2.0\",\"id\":\"id\",\"method\":\"clientStatus\",\"params\":[]}"
46+
<Key "result/networkConnections">
47+
Type "gauge"
48+
Instance "networkconnections"
49+
</Key>
50+
<Key "result/numberOfPubkeysProcessed">
51+
Type "counter"
52+
Instance "numberofpubkeysprocessed"
53+
</Key>
54+
<Key "result/numberOfMessagesProcessed">
55+
Type "counter"
56+
Instance "numberofmessagesprocessed"
57+
</Key>
58+
<Key "result/numberOfBroadcastsProcessed">
59+
Type "counter"
60+
Instance "numberofbroadcastsprocessed"
61+
</Key>
62+
</URL>
63+
EOF
64+
done
65+
66+
echo "</Plugin>" >> $CF
67+
68+
if ! cmp -s $CF $CF_LIVE; then
69+
mv $CF $CF_LIVE
70+
systemctl restart collectd
71+
fi
72+
73+
ipvsadm -l -n

packages/docker/launcher.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,33 @@ sed -i -e "s|\(apiinterface = \).*|\10\.0\.0\.0|g" \
1212
-e "s|\(apipassword = \).*|\1$APIPASS|g" \
1313
-e "s|apinotifypath = .*||g" ${BITMESSAGE_HOME}/keys.dat
1414

15+
if [ -n "$PYBITMESAGE_BOOTSTRAP" -o -n "$PYBITMESSAGE_TESTNET" ]; then
16+
echo "[bootstrap]" >> ${BITMESSAGE_HOME}/keys.dat
17+
fi
18+
19+
if [ -n "$PYBITMESSAGE_BOOTSTRAP" ]; then
20+
IP=$(hostname -i)
21+
sed -i -e "s|\(apiinterface = \).*|\1$IP|g" \
22+
-e "s|\(bind = \).*|\1$IP|g" \
23+
${BITMESSAGE_HOME}/keys.dat
24+
echo <<(EOF) >> ${BITMESSAGE_HOME}/keys.dat
25+
idle_timeout = 60
26+
commands = True
27+
threads = True
28+
inv = True
29+
dup_ip = True
30+
(EOF)
31+
fi
32+
33+
if [ -n "$PYBITMESSAGE_TESTNET" ]; then
34+
IP=$(hostname -i)
35+
sed -i -e "s|\(apiinterface = \).*|\1$IP|g" \
36+
-e "s|\(bind = \).*|\1$IP|g" \
37+
${BITMESSAGE_HOME}/keys.dat
38+
echo <<(EOF) >> ${BITMESSAGE_HOME}/keys.dat
39+
testnet = True
40+
(EOF)
41+
fi
42+
1543
# Run
1644
exec pybitmessage "$@"

src/network/__init__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ def start(config, state): # pylint: disable=too-many-locals
4545

4646
readKnownNodes()
4747
pool.connectToStream(1)
48-
for thread in (
49-
BMNetworkThread(pool), InvThread(pool), AddrThread(pool),
50-
DownloadThread(pool), UploadThread(pool)
51-
):
48+
threads_to_start = list()
49+
threads_to_start.append(BMNetworkThread)
50+
if not config.safeGetBoolean('bootstrap', 'threads'):
51+
threads_to_start.extend([InvThread, AddrThread,
52+
DownloadThread, UploadThread])
53+
for thread_class in threads_to_start:
54+
thread = thread_class(pool)
5255
thread.daemon = True
5356
thread.start()
5457

src/network/bmproto.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ def decode_simple(self, char="v"):
314314

315315
def bm_command_error(self):
316316
"""Decode an error message and log it"""
317+
if config.safeGetBoolean('bootstrap', 'commands'):
318+
return
317319
err_values = self.decode_payload_content("vvlsls")
318320
fatalStatus = err_values[0]
319321
# banTime = err_values[1]
@@ -330,6 +332,8 @@ def bm_command_getdata(self):
330332
If we have them and some other conditions are fulfilled,
331333
append them to the write queue.
332334
"""
335+
if config.safeGetBoolean('bootstrap', 'commands'):
336+
return
333337
items = self.decode_payload_content("l32s")
334338
# skip?
335339
now = time.time()
@@ -366,14 +370,20 @@ def _command_inv(self, extend_dandelion_stem=False):
366370

367371
def bm_command_inv(self):
368372
"""Non-dandelion announce"""
373+
if config.safeGetBoolean('bootstrap', 'commands'):
374+
return
369375
return self._command_inv(False)
370376

371377
def bm_command_dinv(self):
372378
"""Dandelion stem announce"""
379+
if config.safeGetBoolean('bootstrap', 'commands'):
380+
return
373381
return self._command_inv(True)
374382

375383
def bm_command_object(self):
376384
"""Incoming object, process it"""
385+
if config.safeGetBoolean('bootstrap', 'commands'):
386+
return
377387
objectOffset = self.payloadOffset
378388
nonce, expiresTime, objectType, version, streamNumber = \
379389
self.decode_payload_content("QQIvv")
@@ -443,6 +453,8 @@ def _decode_addr(self):
443453

444454
def bm_command_addr(self):
445455
"""Incoming addresses, process them"""
456+
if config.safeGetBoolean('bootstrap', 'commands'):
457+
return
446458
# not using services
447459
for seenTime, stream, _, ip, port in self._decode_addr():
448460
ip = bytes(ip)
@@ -474,6 +486,8 @@ def bm_command_addr(self):
474486

475487
def bm_command_portcheck(self):
476488
"""Incoming port check request, queue it."""
489+
if config.safeGetBoolean('bootstrap', 'commands'):
490+
return
477491
if self.isOutbound or self.portCheckRequested:
478492
return True
479493
self.portCheckRequested = True
@@ -483,6 +497,8 @@ def bm_command_portcheck(self):
483497

484498
def bm_command_ping(self):
485499
"""Incoming ping, respond to it."""
500+
if config.safeGetBoolean('bootstrap', 'commands'):
501+
return
486502
self.append_write_buf(protocol.CreatePacket('pong'))
487503
return True
488504

@@ -603,7 +619,8 @@ def peerValidityChecks(self):
603619
' interest in streams.', self.destination)
604620
return False
605621
if self.pool.inboundConnections.get(
606-
self.destination):
622+
self.destination) and not \
623+
config.safeGetBoolean('bootstrap', 'dup_ip'):
607624
try:
608625
if not protocol.checkSocksIP(self.destination.host):
609626
self.append_write_buf(protocol.assembleErrorMessage(

src/network/connectionpool.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ def __init__(self):
6565
' trustedpeer=<hostname>:<portnumber>'
6666
)
6767

68+
# default timeout 300, lower than 30 doesn't make much practical sense
69+
self.idleTimeout = max([30,
70+
config.safeGetInt('bootstrap',
71+
'idle_timeout', 300)
72+
])
73+
6874
def __len__(self):
6975
return len(self.outboundConnections) + len(self.inboundConnections)
7076

@@ -390,7 +396,7 @@ def loop(self): # pylint: disable=too-many-branches,too-many-statements
390396
for i in self.connections():
391397
minTx = time.time() - 20
392398
if i.fullyEstablished:
393-
minTx -= 300 - 20
399+
minTx -= self.idleTimeout - 20
394400
if i.lastTx < minTx:
395401
if i.fullyEstablished:
396402
i.append_write_buf(protocol.CreatePacket('ping'))

src/network/knownnodes.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,12 @@ def trimKnownNodes(recAddrStream=1):
222222
def dns():
223223
"""Add DNS names to knownnodes"""
224224
for port in [8080, 8444]:
225-
addKnownNode(
226-
1, Peer('bootstrap%s.bitmessage.org' % port, port))
225+
if config.safeGetBoolean('boostrap', 'testnet'):
226+
addKnownNode(
227+
1, Peer('bootstrap%s.testnet.bitmessage.org' % port, port))
228+
else:
229+
addKnownNode(
230+
1, Peer('bootstrap%s.bitmessage.org' % port, port))
227231

228232

229233
def cleanupKnownNodes(pool):

src/network/tcp.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,10 @@ def set_connection_fully_established(self):
168168
knownnodes.addKnownNode(
169169
self.streams, self.destination, time.time())
170170
dandelion_ins.maybeAddStem(self, invQueue)
171-
self.sendAddr()
172-
self.sendBigInv()
171+
if not config.safeGetBoolean('bootstrap', 'addr'):
172+
self.sendAddr()
173+
if not config.safeGetBoolean('bootstrap', 'inv'):
174+
self.sendBigInv()
173175

174176
def sendAddr(self):
175177
"""Send a partial list of known addresses to peer."""
@@ -372,7 +374,8 @@ def set_connection_fully_established(self):
372374
"""Only send addr here"""
373375
# pylint: disable=attribute-defined-outside-init
374376
self.fullyEstablished = True
375-
self.sendAddr()
377+
if not config.safeGetBoolean('bootstrap', 'addr'):
378+
self.sendAddr()
376379

377380
def handle_close(self):
378381
"""

src/protocol.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
# Network constants
2828
magic = 0xE9BEB4D9
29+
if config.safeGetBoolean('bootstrap', 'testnet'):
30+
magic = 0xFB110907
2931
#: protocol specification says max 1000 addresses in one addr command
3032
MAX_ADDR_COUNT = 1000
3133
#: address is online if online less than this many seconds ago

0 commit comments

Comments
 (0)