diff --git a/extensions_setup.py b/extensions_setup.py new file mode 100644 index 000000000..e70a703f7 --- /dev/null +++ b/extensions_setup.py @@ -0,0 +1,133 @@ +# from https://github.com/pybind/python_example/blob/master/setup.py +import sys +import os +import setuptools +import glob +from setuptools import Extension +from setuptools.command.build_ext import build_ext + + +class get_pybind_include(object): + """Helper class to determine the pybind11 include path + + The purpose of this class is to postpone importing pybind11 + until it is actually installed, so that the ``get_include()`` + method can be invoked. """ + + def __init__(self, user=False): + self.user = user + + def __str__(self): + import pybind11 + return pybind11.get_include(self.user) + +#claimtrie_sources = glob.glob('../lbrycrd/src/**/*.cpp') +#claimtrie_sources += glob.glob('../lbrycrd/src/**/*.c') +claimtrie_sources = [] +ext_modules = [ + Extension( + 'lbrycrd', + [ + os.path.join("..", "lbrycrd", "src", "claimtrie", "blob.cpp"), + os.path.join("..", "lbrycrd", "src", "claimtrie", "uints.cpp"), + os.path.join("..", "lbrycrd", "src", "claimtrie", "txoutpoint.cpp"), + os.path.join("..", "lbrycrd", "src", "random.cpp"), + os.path.join("..", "lbrycrd", "src", "support", "lockedpool.cpp"), + os.path.join("..", "lbrycrd", "src", "support", "cleanse.cpp"), + os.path.join("..", "lbrycrd", "src", "util", "time.cpp"), + os.path.join("..", "lbrycrd", "src", "util", "threadnames.cpp"), + os.path.join("..", "lbrycrd", "src", "hash.cpp"), + os.path.join("..", "lbrycrd", "src", "fs.cpp"), + os.path.join("..", "lbrycrd", "src", "logging.cpp"), + os.path.join("..", "lbrycrd", "src", "uint256.cpp"), + os.path.join("..", "lbrycrd", "src", "arith_uint256.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "sha512.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "hmac_sha512.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "ripemd160.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "chacha20.cpp"), + os.path.join("..", "lbrycrd", "src", "primitives", "transaction.cpp"), + os.path.join("..", "lbrycrd", "src", "primitives", "block.cpp"), + os.path.join("..", "lbrycrd", "src", "blockfilter.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "sha256.cpp"), + os.path.join("..", "lbrycrd", "src", "crypto", "siphash.cpp"), + os.path.join("..", "lbrycrd", "src", "script", "script.cpp"), + os.path.join("..", "lbrycrd", "src", "util", "strencodings.cpp"), + os.path.join("..", "lbrycrd", "src", "util", "bytevectorhash.cpp"), + os.path.join("lbrycrd_cpp_bindings", "block_filter.cpp"), + os.path.join("lbrycrd_cpp_bindings", "lbrycrd.cpp"), + ] + claimtrie_sources, + include_dirs=[ + # Path to pybind11 headers + get_pybind_include(), + get_pybind_include(user=True), + os.path.join("..", "lbrycrd", "src"), + os.path.join("..", "lbrycrd", "src", "claimtrie"), + ], + libraries=['boost_thread', 'crypto', 'boost_chrono', 'boost_filesystem'], + language='c++' + ), +] + + +# As of Python 3.6, CCompiler has a `has_flag` method. +# cf http://bugs.python.org/issue26689 +def has_flag(compiler, flagname): + """Return a boolean indicating whether a flag name is supported on + the specified compiler. + """ + import tempfile + with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f: + f.write('int main (int argc, char **argv) { return 0; }') + try: + compiler.compile([f.name], extra_postargs=[flagname]) + except setuptools.distutils.errors.CompileError: + return False + return True + + +def cpp_flag(compiler): + """Return the -std=c++[11/14/17] compiler flag. + + The newer version is prefered over c++11 (when it is available). + """ + flags = ['-std=c++17', '-std=c++14', '-std=c++11'] + + for flag in flags: + if has_flag(compiler, flag): return flag + + raise RuntimeError('Unsupported compiler -- at least C++11 support ' + 'is needed!') + + +class BuildExt(build_ext): + """A custom build extension for adding compiler-specific options.""" + c_opts = { + 'msvc': ['/EHsc'], + 'unix': [], + } + l_opts = { + 'msvc': [], + 'unix': [], + } + + if sys.platform == 'darwin': + darwin_opts = ['-stdlib=libc++', '-mmacosx-version-min=10.14'] + c_opts['unix'] += darwin_opts + l_opts['unix'] += darwin_opts + + def build_extensions(self): + ct = self.compiler.compiler_type + opts = self.c_opts.get(ct, []) + opts.append('-DHAVE_WORKING_BOOST_SLEEP_FOR=1') + link_opts = self.l_opts.get(ct, []) + if ct == 'unix': + opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version()) + opts.append(cpp_flag(self.compiler)) + if has_flag(self.compiler, '-fvisibility=hidden'): + opts.append('-fvisibility=hidden') + elif ct == 'msvc': + opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version()) + for ext in self.extensions: + ext.extra_compile_args = opts + ext.extra_link_args = link_opts + build_ext.build_extensions(self) diff --git a/lbrycrd_cpp_bindings/block_filter.cpp b/lbrycrd_cpp_bindings/block_filter.cpp new file mode 100644 index 000000000..3dfc9895f --- /dev/null +++ b/lbrycrd_cpp_bindings/block_filter.cpp @@ -0,0 +1,67 @@ +#include "block_filter.h" + +PYBlockFilter::PYBlockFilter(std::vector< std::vector< unsigned char > >& hashes) +{ + GCSFilter::ElementSet elements; + for (int i = 0; i < hashes.size(); ++i) + { + GCSFilter::Element element(hashes[i].size()); + for(int j=0;j & encoded_filter) +{ + filter=new GCSFilter({0, 0, 20, 1 << 20}, encoded_filter); +} + +PYBlockFilter::PYBlockFilter(std::string & block_hash, std::vector< unsigned char > & encoded_filter) +{ + uint256 m_block_hash = uint256S(block_hash); + b_filter = new BlockFilter(BlockFilterType::BASIC, m_block_hash, encoded_filter); + const GCSFilter _filter = b_filter->GetFilter(); + filter=new GCSFilter(_filter.GetParams(), _filter.GetEncoded()); +} + +const std::vector& PYBlockFilter::GetEncoded() +{ + return filter->GetEncoded(); +} + +PYBlockFilter::~PYBlockFilter() +{ + delete filter; +} + +bool PYBlockFilter::Match(std::vector< unsigned char >& hash) +{ + GCSFilter::Element element(hash.size()); + for(int j=0;jMatch(element); +} + +bool PYBlockFilter::MatchAny(std::vector< std::vector< unsigned char > >& hashes) +{ + GCSFilter::ElementSet elements; + + for (int i = 0; i < hashes.size(); ++i) + { + GCSFilter::Element element(hashes[i].size()); + for(int j=0;jMatchAny(elements); +} diff --git a/lbrycrd_cpp_bindings/block_filter.h b/lbrycrd_cpp_bindings/block_filter.h new file mode 100644 index 000000000..09a24410a --- /dev/null +++ b/lbrycrd_cpp_bindings/block_filter.h @@ -0,0 +1,24 @@ +#ifndef PY_BLOCK_FILTER_H +#define PY_BLOCK_FILTER_H + +#include + +class PYBlockFilter +{ +public: + GCSFilter *filter; + BlockFilter *b_filter; + +public: + + PYBlockFilter(std::vector< std::vector< unsigned char > >& hashes); + PYBlockFilter(std::vector< unsigned char > & encoded_filter); + PYBlockFilter(std::string & block_hash, std::vector< unsigned char > & encoded_filter); + const std::vector& GetEncoded(); + ~PYBlockFilter(); + + bool Match(std::vector< unsigned char >& hash); + bool MatchAny(std::vector< std::vector< unsigned char > >& hashes); +}; + +#endif diff --git a/lbrycrd_cpp_bindings/lbrycrd.cpp b/lbrycrd_cpp_bindings/lbrycrd.cpp new file mode 100644 index 000000000..6e00d94f1 --- /dev/null +++ b/lbrycrd_cpp_bindings/lbrycrd.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +#include "block_filter.h" + +namespace py = pybind11; + +PYBIND11_MODULE(lbrycrd, mod) { + py::class_> clsPYBlockFilter(mod, "PYBlockFilter"); + + clsPYBlockFilter.def(py::init >&>()); + clsPYBlockFilter.def(py::init< std::vector< unsigned char > &>()); + clsPYBlockFilter.def(py::init< std::string &, std::vector< unsigned char > &>()); + clsPYBlockFilter.def("GetEncoded",(const std::vector< unsigned char >& (PYBlockFilter::*)()) &PYBlockFilter::GetEncoded); + clsPYBlockFilter.def("Match", (bool (PYBlockFilter::*)(std::vector< unsigned char >&)) &PYBlockFilter::Match); + clsPYBlockFilter.def("MatchAny", (bool (PYBlockFilter::*)(std::vector< std::vector< unsigned char > >&)) &PYBlockFilter::MatchAny); +} diff --git a/setup.py b/setup.py index e8fa1b759..8560460a5 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ import os import sys +from extensions_setup import ext_modules, BuildExt from lbry import __name__, __version__ from setuptools import setup, find_packages @@ -32,6 +33,9 @@ setup( 'orchstr8=lbry.wallet.orchstr8.cli:main', ], }, + setup_requires=["pybind11"], + ext_modules=ext_modules, + cmdclass={'build_ext': BuildExt}, install_requires=[ 'aiohttp==3.5.4', 'aioupnp==0.0.17',