Skip to content
Closed
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
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,21 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
[ AC_MSG_RESULT(no)]
)

# Check for UNIX sockets
AC_MSG_CHECKING(for sockaddr_un)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>
#include <sys/un.h>]],
[[ struct sockaddr_un addr;
addr.sun_family = AF_UNIX; ]])],
[ AC_MSG_RESULT(yes);
AC_DEFINE(HAVE_SOCKADDR_UN, 1,[Define this symbol if the sockaddr_un is available])
AM_CONDITIONAL([BUILD_EVUNIX],[true])
],
[ AC_MSG_RESULT(no)
AM_CONDITIONAL([BUILD_EVUNIX],[false])
]
)

# Check for reduced exports
if test x$use_reduce_exports = xyes; then
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"],
Expand Down
4 changes: 4 additions & 0 deletions qa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ Possible options, which apply to each individual test run:
If you set the environment variable `PYTHON_DEBUG=1` you will get some debug
output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`).

To force the tests to use RPC over TCP instead of a UNIX socket (this
can be useful for troubleshooting) define the environment variable
`BITCOIN_TEST_RPC_TCP` as `1`.

A 200-block -regtest blockchain and wallets for four nodes
is created the first time a regression test is run and
is stored in the cache/ directory. Each node has 25 mature
Expand Down
1 change: 1 addition & 0 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
'rpcnamedargs.py',
'listsinceblock.py',
'p2p-leaktests.py',
'p2p-unixconn.py',
]

ZMQ_SCRIPTS = [
Expand Down
4 changes: 2 additions & 2 deletions qa/rpc-tests/abandonconflict.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def __init__(self):

def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"]))
self.nodes.append(start_node(1, self.options.tmpdir))
self.nodes.append(start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"], rpchost="127.0.0.1"))
self.nodes.append(start_node(1, self.options.tmpdir, [], rpchost="127.0.0.1"))
connect_nodes(self.nodes[0], 1)

def run_test(self):
Expand Down
2 changes: 1 addition & 1 deletion qa/rpc-tests/httpbasics.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self):
self.setup_clean_chain = False

def setup_network(self):
self.nodes = self.setup_nodes()
self.nodes = self.setup_nodes(rpchost="127.0.0.1")

def run_test(self):

Expand Down
16 changes: 6 additions & 10 deletions qa/rpc-tests/multi_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@ def __init__(self):
self.setup_clean_chain = False
self.num_nodes = 1

def setup_chain(self):
super().setup_chain()
#Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")

def setup_network(self):
self.nodes = self.setup_nodes()
# Pass in extra RPC authentication information
extra_args = [[
"-rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144",
"-rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
]]
self.nodes = self.setup_nodes(rpchost='127.0.0.1', extra_args=extra_args)

def run_test(self):

Expand Down
3 changes: 3 additions & 0 deletions qa/rpc-tests/nodehandling.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def __init__(self):
self.num_nodes = 4
self.setup_clean_chain = False

def setup_nodes(self):
return start_nodes(self.num_nodes, self.options.tmpdir, rpchost='127.0.0.1')

def run_test(self):
###########################
# setban/listbanned tests #
Expand Down
67 changes: 67 additions & 0 deletions qa/rpc-tests/p2p-unixconn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test P2P connectivity over UNIX socket."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.uhttpconnection import have_af_unix

def unix_connect_nodes(dirname, from_connection, node_num):
sock_path = ":unix:" + os.path.join(dirname, "node"+str(node_num), 'regtest', 'p2p_sock')
from_connection.addnode(sock_path, "onetry")
# poll until version handshake complete to avoid race conditions
# with transaction relaying
while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()):
time.sleep(0.1)

def unix_connect_nodes_bi(dirname, nodes, a, b):
unix_connect_nodes(dirname, nodes[a], b)
unix_connect_nodes(dirname, nodes[b], a)

class UnixP2PTest (BitcoinTestFramework):
'''Test P2P over UNIX socket'''

def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
"""Return curr_balance after asserting the fee was in range"""
fee = balance_with_fee - curr_balance
assert_fee_amount(fee, tx_size, fee_per_byte * 1000)
return curr_balance

def __init__(self):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 3
# tell nodes to bind P2P on UNIX socket
self.extra_args = [['-bind=:unix:p2p_sock'] for i in range(3)]

def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3])
unix_connect_nodes_bi(self.options.tmpdir, self.nodes,0,1)
unix_connect_nodes_bi(self.options.tmpdir, self.nodes,0,2)
unix_connect_nodes_bi(self.options.tmpdir, self.nodes,1,2)
self.is_network_split=False
self.sync_all()

def run_test (self):
assert_equal(self.nodes[0].getbalance(), 1250)
assert_equal(self.nodes[1].getbalance(), 1250)
assert_equal(self.nodes[2].getbalance(), 1250)

# send 42 BTC to node 2 from node 0 and 1
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
self.nodes[0].generate(1)
self.sync_all()

self.nodes[1].sendtoaddress(self.nodes[2].getnewaddress(), 11)
self.nodes[1].sendtoaddress(self.nodes[2].getnewaddress(), 10)
self.nodes[1].generate(1)
self.sync_all()

assert_equal(self.nodes[2].getbalance(), 1250 + 42)


if __name__ == '__main__':
if have_af_unix:
UnixP2PTest().main()
2 changes: 1 addition & 1 deletion qa/rpc-tests/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self):
self.num_nodes = 3

def setup_network(self, split=False):
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, rpchost='127.0.0.1')
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
Expand Down
75 changes: 75 additions & 0 deletions qa/rpc-tests/test_framework/conninfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import os

from .uhttpconnection import UHTTPConnection

# UNIX socket name for RPC connection (in data directory)
RPC_SOCKET_NAME = "rpc_socket"

class RPCConnectInfo:
'''
Base class for RPC connection info. This class encapsulates both information
required to connect to RPC, as to configure bitcoind to listen on that transport.
'''
def make_connection(self):
'''
Returns the 'connection' argument to pass to the RPCAuthService.
Can be None to let that class figure it out itself.
'''
raise NotImplementedError

@property
def bitcoind_args(self):
'''
Return arguments for setting up bitcoind.
'''
raise NotImplementedError

class RPCConnectInfoTCP:
'''RPC connection info for connecting over TCP'''
def __init__(self, node_number, auth, rpchost, rpcport):
self.node_number = node_number # node number is just for informational purposes
self.auth = auth
self.host = '127.0.0.1'
self.port = rpcport
if rpchost: # "rpchost" can override both host and port
parts = rpchost.split(':')
self.host = parts[0]
if len(parts) == 2:
self.port = int(parts[1])
self.url = "http://%s:%s@%s:%d" % (auth[0], auth[1], self.host, self.port)

def make_connection(self):
# This is done inside the AuthServiceProxy
return None

@property
def bitcoind_args(self):
# rpchost is ignored here because the test will take care of passing in the
# appropriate rpcbind arguments.
return [("rpcuser", self.auth[0]),
("rpcpassword", self.auth[1]),
("rpcport", str(self.port))]

class RPCConnectInfoUNIX:
'''RPC connection info for connecting over UNIX socket'''
def __init__(self, node_number, auth, dirname):
self.node_number = node_number
self.auth = auth
self.sockname = os.path.join(dirname, RPC_SOCKET_NAME)
# use "localhost" as fake hostname. It doesn't matter.
self.url = "http://%s:%s@localhost" % auth

def make_connection(self):
return UHTTPConnection(self.sockname)

@property
def bitcoind_args(self):
return [("rpcuser", self.auth[0]),
("rpcpassword", self.auth[1]),
("rpcbind", ":unix:"+self.sockname),
("rpcconnect", ":unix:"+self.sockname)]

4 changes: 2 additions & 2 deletions qa/rpc-tests/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ def setup_chain(self):
def stop_node(self, num_node):
stop_node(self.nodes[num_node], num_node)

def setup_nodes(self):
return start_nodes(self.num_nodes, self.options.tmpdir)
def setup_nodes(self, rpchost=None, extra_args=None):
return start_nodes(self.num_nodes, self.options.tmpdir, rpchost=rpchost, extra_args=extra_args)

def setup_network(self, split = False):
self.nodes = self.setup_nodes()
Expand Down
33 changes: 33 additions & 0 deletions qa/rpc-tests/test_framework/uhttpconnection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Inspired by "HTTP on Unix sockets with Python"
# From: http://7bits.nl/blog/posts/http-on-unix-sockets-with-python
import http.client
import socket

def have_af_unix():
'''Return True if UNIX sockets are available on this platform.'''
try:
socket.AF_UNIX
except AttributeError:
return False
else:
return True

class UHTTPConnection(http.client.HTTPConnection):
"""Subclass of Python library HTTPConnection that
uses a unix-domain socket.
"""

def __init__(self, path):
http.client.HTTPConnection.__init__(self, 'localhost')
self.path = path

def connect(self):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(self.path)
self.sock = sock

Loading