mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-12-01 11:27:10 +03:00
pybind and cmake support
This commit is contained in:
parent
b41ad92da7
commit
8f6d3dadd2
32
lib/bip158/CMakeLists.txt
Normal file
32
lib/bip158/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "RELEASE")
|
||||
ENDIF()
|
||||
|
||||
project(chiabip158)
|
||||
|
||||
include_directories(
|
||||
${INCLUDE_DIRECTORIES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
/usr/local/opt/openssl/include
|
||||
)
|
||||
|
||||
set (CMAKE_CXX_FLAGS "-DHAVE_WORKING_BOOST_SLEEP -g -O3 -Wall -msse2 -msse -march=native -std=c++14 -maes")
|
||||
|
||||
FILE(GLOB_RECURSE MyCSources src/*.cpp)
|
||||
ADD_LIBRARY(biplib ${MyCSources})
|
||||
|
||||
add_subdirectory(lib/pybind11)
|
||||
|
||||
pybind11_add_module(chiabip158 ${CMAKE_CURRENT_SOURCE_DIR}/python-bindings/chiabip158.cpp)
|
||||
|
||||
add_executable(bip158
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(bip158 biplib -lboost_system -lpthread -lboost_thread -lboost_filesystem -lssl -lcrypto)
|
||||
target_link_libraries(chiabip158 PRIVATE biplib -lboost_system -lpthread -lboost_thread -lboost_filesystem -lssl -lcrypto)
|
||||
|
1
lib/bip158/README.md
Normal file
1
lib/bip158/README.md
Normal file
@ -0,0 +1 @@
|
||||
This implements the compact block filter construction in BIP 158. The code is not used anywhere in the Bitcoin Core code base yet. The next step towards BIP 157 support would be to create an indexing module similar to TxIndex that constructs the basic and extended filters for each validated block.
|
42
lib/bip158/main.cpp
Normal file
42
lib/bip158/main.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include <iostream>
|
||||
#include "blockfilter.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
srand(time(NULL));
|
||||
for(int loop=0;loop<10;loop++)
|
||||
{
|
||||
GCSFilter::ElementSet elements2;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
elements2.insert(std::move(element));
|
||||
}
|
||||
GCSFilter filter({0, 0, 20, 1 << 20},
|
||||
elements2);
|
||||
|
||||
GCSFilter::ElementSet elements3;
|
||||
|
||||
for (int j=0;j<10;j++)
|
||||
{
|
||||
int i=rand()%50000;
|
||||
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
|
||||
if(filter.Match(element))
|
||||
std::cout << "Found " << i << std::endl;
|
||||
else
|
||||
std::cout << "Not Found " << i << std::endl;
|
||||
elements3.insert(std::move(element));
|
||||
}
|
||||
if(filter.MatchAny(elements3))
|
||||
std::cout << loop << " ***** MatchAny returned true" << std::endl;
|
||||
else
|
||||
std::cout << loop << " ***** MatchAny returned false" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
29
lib/bip158/python-bindings/chiabip158.cpp
Normal file
29
lib/bip158/python-bindings/chiabip158.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 Chia Network Inc
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/operators.h>
|
||||
|
||||
#include "PyBIP158.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
PYBIND11_MODULE(chiabip158, mod) {
|
||||
py::class_<PyBIP158, std::shared_ptr<PyBIP158>> clsPyBIP158(mod, "PyBIP158");
|
||||
|
||||
clsPyBIP158.def(py::init<std::vector< std::vector< unsigned char > >&>());
|
||||
clsPyBIP158.def("Match", (bool (PyBIP158::*)(std::vector< unsigned char >&)) &PyBIP158::Match);
|
||||
clsPyBIP158.def("MatchAny", (bool (PyBIP158::*)(std::vector< std::vector< unsigned char > >&)) &PyBIP158::MatchAny);
|
||||
}
|
13
lib/bip158/python-bindings/test.py
Executable file
13
lib/bip158/python-bindings/test.py
Executable file
@ -0,0 +1,13 @@
|
||||
from chiabip158 import PyBIP158
|
||||
from array import *
|
||||
|
||||
a = [1,2,3]
|
||||
b = [4,5,6]
|
||||
c = [a,b]
|
||||
d = [7,8,9]
|
||||
|
||||
pl = PyBIP158(c)
|
||||
if pl.Match(a):
|
||||
print("OK")
|
||||
else:
|
||||
print("NOT FOUND")
|
80
lib/bip158/setup.py
Normal file
80
lib/bip158/setup.py
Normal file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from setuptools import setup, Extension
|
||||
from setuptools.command.build_ext import build_ext
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
|
||||
class CMakeExtension(Extension):
|
||||
def __init__(self, name, sourcedir=''):
|
||||
Extension.__init__(self, name, sources=['./'])
|
||||
self.sourcedir = os.path.abspath(sourcedir)
|
||||
|
||||
|
||||
class CMakeBuild(build_ext):
|
||||
def run(self):
|
||||
try:
|
||||
out = subprocess.check_output(['cmake', '--version'])
|
||||
except OSError:
|
||||
raise RuntimeError("CMake must be installed to build" +
|
||||
" the following extensions: " +
|
||||
", ".join(e.name for e in self.extensions))
|
||||
|
||||
if platform.system() == "Windows":
|
||||
cmake_version = LooseVersion(
|
||||
re.search(r'version\s*([\d.]+)', out.decode()).group(1))
|
||||
if cmake_version < '3.1.0':
|
||||
raise RuntimeError("CMake >= 3.1.0 is required on Windows")
|
||||
|
||||
for ext in self.extensions:
|
||||
self.build_extension(ext)
|
||||
|
||||
def build_extension(self, ext):
|
||||
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
|
||||
cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(extdir),
|
||||
'-DPYTHON_EXECUTABLE=' + sys.executable]
|
||||
|
||||
cfg = 'Debug' if self.debug else 'Release'
|
||||
build_args = ['--config', cfg]
|
||||
|
||||
if platform.system() == "Windows":
|
||||
cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'
|
||||
.format(cfg.upper(), extdir)]
|
||||
if sys.maxsize > 2**32:
|
||||
cmake_args += ['-A', 'x64']
|
||||
build_args += ['--', '/m']
|
||||
else:
|
||||
cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
|
||||
build_args += ['--', '-j', '6']
|
||||
|
||||
env = os.environ.copy()
|
||||
env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(
|
||||
env.get('CXXFLAGS', ''),
|
||||
self.distribution.get_version())
|
||||
if not os.path.exists(self.build_temp):
|
||||
os.makedirs(self.build_temp)
|
||||
subprocess.check_call(['cmake', ext.sourcedir] +
|
||||
cmake_args, cwd=self.build_temp, env=env)
|
||||
subprocess.check_call(['cmake', '--build', '.'] +
|
||||
build_args, cwd=self.build_temp)
|
||||
|
||||
|
||||
setup(
|
||||
name='chiabip158',
|
||||
version='0.2.2',
|
||||
author='Mariano Sorgente',
|
||||
author_email='mariano@chia.net',
|
||||
description='Chia BIP158 (wraps C++)',
|
||||
license='Apache License',
|
||||
python_requires='>=3.7',
|
||||
install_requires=['pytest', 'cppimport', 'bitstring', 'flake8'],
|
||||
long_description=open('README.md').read(),
|
||||
ext_modules=[CMakeExtension('chiabip158', '.')],
|
||||
cmdclass=dict(build_ext=CMakeBuild),
|
||||
zip_safe=False,
|
||||
)
|
53
lib/bip158/src/PyBIP158.cpp
Normal file
53
lib/bip158/src/PyBIP158.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php./Users/bill/downloads/gene/chia-blockchain/lib/bip158
|
||||
|
||||
#include <PyBIP158.h>
|
||||
|
||||
PyBIP158::PyBIP158(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<hashes[i].size();j++)
|
||||
{
|
||||
element[j] = hashes[i][j];
|
||||
}
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
filter=new GCSFilter({0, 0, 20, 1 << 20},elements);
|
||||
}
|
||||
|
||||
PyBIP158::~PyBIP158()
|
||||
{
|
||||
delete filter;
|
||||
}
|
||||
|
||||
bool PyBIP158::Match(std::vector< unsigned char >& hash)
|
||||
{
|
||||
GCSFilter::Element element(hash.size());
|
||||
for(int j=0;j<hash.size();j++)
|
||||
{
|
||||
element[j] = hash[j];
|
||||
}
|
||||
|
||||
return filter->Match(element);
|
||||
}
|
||||
|
||||
bool PyBIP158::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;j<hashes[i].size();j++)
|
||||
{
|
||||
element[j] = hashes[i][j];
|
||||
}
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
|
||||
return filter->MatchAny(elements);
|
||||
}
|
24
lib/bip158/src/PyBIP158.h
Normal file
24
lib/bip158/src/PyBIP158.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BIP158_H
|
||||
#define BIP158_H
|
||||
|
||||
#include <blockfilter.h>
|
||||
|
||||
class PyBIP158
|
||||
{
|
||||
public:
|
||||
GCSFilter *filter;
|
||||
|
||||
public:
|
||||
|
||||
PyBIP158(std::vector< std::vector< unsigned char > >& hashes);
|
||||
~PyBIP158();
|
||||
|
||||
bool Match(std::vector< unsigned char >& hash);
|
||||
bool MatchAny(std::vector< std::vector< unsigned char > >& hashes);
|
||||
};
|
||||
|
||||
#endif // BIP158_H
|
28
lib/bip158/src/amount.h
Normal file
28
lib/bip158/src/amount.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_AMOUNT_H
|
||||
#define BITCOIN_AMOUNT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Amount in satoshis (Can be negative) */
|
||||
typedef int64_t CAmount;
|
||||
|
||||
static const CAmount COIN = 100000000;
|
||||
|
||||
/** No amount larger than this (in satoshi) is valid.
|
||||
*
|
||||
* Note that this constant is *not* the total money supply, which in Bitcoin
|
||||
* currently happens to be less than 21,000,000 BTC for various reasons, but
|
||||
* rather a sanity check. As this sanity check is used by consensus-critical
|
||||
* validation code, the exact value of the MAX_MONEY constant is consensus
|
||||
* critical; in unusual circumstances like a(nother) overflow bug that allowed
|
||||
* for the creation of coins out of thin air modification could lead to a fork.
|
||||
* */
|
||||
static const CAmount MAX_MONEY = 21000000 * COIN;
|
||||
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
|
||||
|
||||
#endif // BITCOIN_AMOUNT_H
|
22
lib/bip158/src/attributes.h
Normal file
22
lib/bip158/src/attributes.h
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_ATTRIBUTES_H
|
||||
#define BITCOIN_ATTRIBUTES_H
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(nodiscard)
|
||||
# define NODISCARD [[nodiscard]]
|
||||
# endif
|
||||
#endif
|
||||
#ifndef NODISCARD
|
||||
# if defined(_MSC_VER) && _MSC_VER >= 1700
|
||||
# define NODISCARD _Check_return_
|
||||
# else
|
||||
# define NODISCARD __attribute__((warn_unused_result))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BITCOIN_ATTRIBUTES_H
|
338
lib/bip158/src/blockfilter.cpp
Normal file
338
lib/bip158/src/blockfilter.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
#include <blockfilter.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <hash.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
#include <streams.h>
|
||||
|
||||
/// SerType used to serialize parameters in GCS filter encoding.
|
||||
static constexpr int GCS_SER_TYPE = SER_NETWORK;
|
||||
|
||||
/// Protocol version used to serialize parameters in GCS filter encoding.
|
||||
static constexpr int GCS_SER_VERSION = 0;
|
||||
|
||||
static const std::map<BlockFilterType, std::string> g_filter_types = {
|
||||
{BlockFilterType::BASIC, "basic"},
|
||||
};
|
||||
|
||||
template <typename OStream>
|
||||
static void GolombRiceEncode(BitStreamWriter<OStream>& bitwriter, uint8_t P, uint64_t x)
|
||||
{
|
||||
// Write quotient as unary-encoded: q 1's followed by one 0.
|
||||
uint64_t q = x >> P;
|
||||
while (q > 0) {
|
||||
int nbits = q <= 64 ? static_cast<int>(q) : 64;
|
||||
bitwriter.Write(~0ULL, nbits);
|
||||
q -= nbits;
|
||||
}
|
||||
bitwriter.Write(0, 1);
|
||||
|
||||
// Write the remainder in P bits. Since the remainder is just the bottom
|
||||
// P bits of x, there is no need to mask first.
|
||||
bitwriter.Write(x, P);
|
||||
}
|
||||
|
||||
template <typename IStream>
|
||||
static uint64_t GolombRiceDecode(BitStreamReader<IStream>& bitreader, uint8_t P)
|
||||
{
|
||||
// Read unary-encoded quotient: q 1's followed by one 0.
|
||||
uint64_t q = 0;
|
||||
while (bitreader.Read(1) == 1) {
|
||||
++q;
|
||||
}
|
||||
|
||||
uint64_t r = bitreader.Read(P);
|
||||
|
||||
return (q << P) + r;
|
||||
}
|
||||
|
||||
// Map a value x that is uniformly distributed in the range [0, 2^64) to a
|
||||
// value uniformly distributed in [0, n) by returning the upper 64 bits of
|
||||
// x * n.
|
||||
//
|
||||
// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
static uint64_t MapIntoRange(uint64_t x, uint64_t n)
|
||||
{
|
||||
#ifdef __SIZEOF_INT128__
|
||||
return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64;
|
||||
#else
|
||||
// To perform the calculation on 64-bit numbers without losing the
|
||||
// result to overflow, split the numbers into the most significant and
|
||||
// least significant 32 bits and perform multiplication piece-wise.
|
||||
//
|
||||
// See: https://stackoverflow.com/a/26855440
|
||||
uint64_t x_hi = x >> 32;
|
||||
uint64_t x_lo = x & 0xFFFFFFFF;
|
||||
uint64_t n_hi = n >> 32;
|
||||
uint64_t n_lo = n & 0xFFFFFFFF;
|
||||
|
||||
uint64_t ac = x_hi * n_hi;
|
||||
uint64_t ad = x_hi * n_lo;
|
||||
uint64_t bc = x_lo * n_hi;
|
||||
uint64_t bd = x_lo * n_lo;
|
||||
|
||||
uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);
|
||||
uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
|
||||
return upper64;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t GCSFilter::HashToRange(const Element& element) const
|
||||
{
|
||||
uint64_t hash = CSipHasher(m_params.m_siphash_k0, m_params.m_siphash_k1)
|
||||
.Write(element.data(), element.size())
|
||||
.Finalize();
|
||||
return MapIntoRange(hash, m_F);
|
||||
}
|
||||
|
||||
std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const
|
||||
{
|
||||
std::vector<uint64_t> hashed_elements;
|
||||
hashed_elements.reserve(elements.size());
|
||||
for (const Element& element : elements) {
|
||||
hashed_elements.push_back(HashToRange(element));
|
||||
}
|
||||
std::sort(hashed_elements.begin(), hashed_elements.end());
|
||||
return hashed_elements;
|
||||
}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params)
|
||||
: m_params(params), m_N(0), m_F(0), m_encoded{0}
|
||||
{}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
|
||||
: m_params(params), m_encoded(std::move(encoded_filter))
|
||||
{
|
||||
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
uint64_t N = ReadCompactSize(stream);
|
||||
m_N = static_cast<uint32_t>(N);
|
||||
if (m_N != N) {
|
||||
throw std::ios_base::failure("N must be <2^32");
|
||||
}
|
||||
m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
|
||||
|
||||
// Verify that the encoded filter contains exactly N elements. If it has too much or too little
|
||||
// data, a std::ios_base::failure exception will be raised.
|
||||
BitStreamReader<VectorReader> bitreader(stream);
|
||||
for (uint64_t i = 0; i < m_N; ++i) {
|
||||
GolombRiceDecode(bitreader, m_params.m_P);
|
||||
}
|
||||
if (!stream.empty()) {
|
||||
throw std::ios_base::failure("encoded_filter contains excess data");
|
||||
}
|
||||
}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params, const ElementSet& elements)
|
||||
: m_params(params)
|
||||
{
|
||||
size_t N = elements.size();
|
||||
m_N = static_cast<uint32_t>(N);
|
||||
if (m_N != N) {
|
||||
throw std::invalid_argument("N must be <2^32");
|
||||
}
|
||||
m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
|
||||
|
||||
CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
WriteCompactSize(stream, m_N);
|
||||
|
||||
if (elements.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BitStreamWriter<CVectorWriter> bitwriter(stream);
|
||||
|
||||
uint64_t last_value = 0;
|
||||
for (uint64_t value : BuildHashedSet(elements)) {
|
||||
uint64_t delta = value - last_value;
|
||||
GolombRiceEncode(bitwriter, m_params.m_P, delta);
|
||||
last_value = value;
|
||||
}
|
||||
|
||||
bitwriter.Flush();
|
||||
}
|
||||
|
||||
bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
|
||||
{
|
||||
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
// Seek forward by size of N
|
||||
uint64_t N = ReadCompactSize(stream);
|
||||
assert(N == m_N);
|
||||
|
||||
BitStreamReader<VectorReader> bitreader(stream);
|
||||
|
||||
uint64_t value = 0;
|
||||
size_t hashes_index = 0;
|
||||
for (uint32_t i = 0; i < m_N; ++i) {
|
||||
uint64_t delta = GolombRiceDecode(bitreader, m_params.m_P);
|
||||
value += delta;
|
||||
|
||||
while (true) {
|
||||
if (hashes_index == size) {
|
||||
return false;
|
||||
} else if (element_hashes[hashes_index] == value) {
|
||||
return true;
|
||||
} else if (element_hashes[hashes_index] > value) {
|
||||
break;
|
||||
}
|
||||
|
||||
hashes_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GCSFilter::Match(const Element& element) const
|
||||
{
|
||||
uint64_t query = HashToRange(element);
|
||||
return MatchInternal(&query, 1);
|
||||
}
|
||||
|
||||
bool GCSFilter::MatchAny(const ElementSet& elements) const
|
||||
{
|
||||
const std::vector<uint64_t> queries = BuildHashedSet(elements);
|
||||
return MatchInternal(queries.data(), queries.size());
|
||||
}
|
||||
|
||||
const std::string& BlockFilterTypeName(BlockFilterType filter_type)
|
||||
{
|
||||
static std::string unknown_retval = "";
|
||||
auto it = g_filter_types.find(filter_type);
|
||||
return it != g_filter_types.end() ? it->second : unknown_retval;
|
||||
}
|
||||
|
||||
bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type) {
|
||||
for (const auto& entry : g_filter_types) {
|
||||
if (entry.second == name) {
|
||||
filter_type = entry.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<BlockFilterType>& AllBlockFilterTypes()
|
||||
{
|
||||
static std::vector<BlockFilterType> types;
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, []() {
|
||||
types.reserve(g_filter_types.size());
|
||||
for (auto entry : g_filter_types) {
|
||||
types.push_back(entry.first);
|
||||
}
|
||||
});
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
const std::string& ListBlockFilterTypes()
|
||||
{
|
||||
static std::string type_list;
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, []() {
|
||||
std::stringstream ret;
|
||||
bool first = true;
|
||||
for (auto entry : g_filter_types) {
|
||||
if (!first) ret << ", ";
|
||||
ret << entry.second;
|
||||
first = false;
|
||||
}
|
||||
type_list = ret.str();
|
||||
});
|
||||
|
||||
return type_list;
|
||||
}
|
||||
|
||||
static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
|
||||
const CBlockUndo& block_undo)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
|
||||
for (const CTransactionRef& tx : block.vtx) {
|
||||
for (const CTxOut& txout : tx->vout) {
|
||||
const CScript& script = txout.scriptPubKey;
|
||||
if (script.empty() || script[0] == OP_RETURN) continue;
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
|
||||
for (const CTxUndo& tx_undo : block_undo.vtxundo) {
|
||||
for (const Coin& prevout : tx_undo.vprevout) {
|
||||
const CScript& script = prevout.out.scriptPubKey;
|
||||
if (script.empty()) continue;
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
|
||||
std::vector<unsigned char> filter)
|
||||
: m_filter_type(filter_type), m_block_hash(block_hash)
|
||||
{
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::invalid_argument("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, std::move(filter));
|
||||
}
|
||||
|
||||
BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
|
||||
: m_filter_type(filter_type), m_block_hash(block.GetHash())
|
||||
{
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::invalid_argument("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));
|
||||
}
|
||||
|
||||
bool BlockFilter::BuildParams(GCSFilter::Params& params) const
|
||||
{
|
||||
switch (m_filter_type) {
|
||||
case BlockFilterType::BASIC:
|
||||
params.m_siphash_k0 = m_block_hash.GetUint64(0);
|
||||
params.m_siphash_k1 = m_block_hash.GetUint64(1);
|
||||
params.m_P = BASIC_FILTER_P;
|
||||
params.m_M = BASIC_FILTER_M;
|
||||
return true;
|
||||
case BlockFilterType::INVALID:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 BlockFilter::GetHash() const
|
||||
{
|
||||
const std::vector<unsigned char>& data = GetEncodedFilter();
|
||||
|
||||
uint256 result;
|
||||
CHash256().Write(data.data(), data.size()).Finalize(result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
|
||||
{
|
||||
const uint256& filter_hash = GetHash();
|
||||
|
||||
uint256 result;
|
||||
CHash256()
|
||||
.Write(filter_hash.begin(), filter_hash.size())
|
||||
.Write(prev_header.begin(), prev_header.size())
|
||||
.Finalize(result.begin());
|
||||
return result;
|
||||
}
|
170
lib/bip158/src/blockfilter.h
Normal file
170
lib/bip158/src/blockfilter.h
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_BLOCKFILTER_H
|
||||
#define BITCOIN_BLOCKFILTER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <primitives/block.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <undo.h>
|
||||
#include <util/bytevectorhash.h>
|
||||
|
||||
/**
|
||||
* This implements a Golomb-coded set as defined in BIP 158. It is a
|
||||
* compact, probabilistic data structure for testing set membership.
|
||||
*/
|
||||
class GCSFilter
|
||||
{
|
||||
public:
|
||||
typedef std::vector<unsigned char> Element;
|
||||
typedef std::unordered_set<Element, ByteVectorHash> ElementSet;
|
||||
|
||||
struct Params
|
||||
{
|
||||
uint64_t m_siphash_k0;
|
||||
uint64_t m_siphash_k1;
|
||||
uint8_t m_P; //!< Golomb-Rice coding parameter
|
||||
uint32_t m_M; //!< Inverse false positive rate
|
||||
|
||||
Params(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 1)
|
||||
: m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M)
|
||||
{}
|
||||
};
|
||||
|
||||
private:
|
||||
Params m_params;
|
||||
uint32_t m_N; //!< Number of elements in the filter
|
||||
uint64_t m_F; //!< Range of element hashes, F = N * M
|
||||
std::vector<unsigned char> m_encoded;
|
||||
|
||||
/** Hash a data element to an integer in the range [0, N * M). */
|
||||
uint64_t HashToRange(const Element& element) const;
|
||||
|
||||
std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const;
|
||||
|
||||
/** Helper method used to implement Match and MatchAny */
|
||||
bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructs an empty filter. */
|
||||
explicit GCSFilter(const Params& params = Params());
|
||||
|
||||
/** Reconstructs an already-created filter from an encoding. */
|
||||
GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter);
|
||||
|
||||
/** Builds a new filter from the params and set of elements. */
|
||||
GCSFilter(const Params& params, const ElementSet& elements);
|
||||
|
||||
uint32_t GetN() const { return m_N; }
|
||||
const Params& GetParams() const { return m_params; }
|
||||
const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
|
||||
|
||||
/**
|
||||
* Checks if the element may be in the set. False positives are possible
|
||||
* with probability 1/M.
|
||||
*/
|
||||
bool Match(const Element& element) const;
|
||||
|
||||
/**
|
||||
* Checks if any of the given elements may be in the set. False positives
|
||||
* are possible with probability 1/M per element checked. This is more
|
||||
* efficient that checking Match on multiple elements separately.
|
||||
*/
|
||||
bool MatchAny(const ElementSet& elements) const;
|
||||
};
|
||||
|
||||
constexpr uint8_t BASIC_FILTER_P = 19;
|
||||
constexpr uint32_t BASIC_FILTER_M = 784931;
|
||||
|
||||
enum class BlockFilterType : uint8_t
|
||||
{
|
||||
BASIC = 0,
|
||||
INVALID = 255,
|
||||
};
|
||||
|
||||
/** Get the human-readable name for a filter type. Returns empty string for unknown types. */
|
||||
const std::string& BlockFilterTypeName(BlockFilterType filter_type);
|
||||
|
||||
/** Find a filter type by its human-readable name. */
|
||||
bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type);
|
||||
|
||||
/** Get a list of known filter types. */
|
||||
const std::vector<BlockFilterType>& AllBlockFilterTypes();
|
||||
|
||||
/** Get a comma-separated list of known filter type names. */
|
||||
const std::string& ListBlockFilterTypes();
|
||||
|
||||
/**
|
||||
* Complete block filter struct as defined in BIP 157. Serialization matches
|
||||
* payload of "cfilter" messages.
|
||||
*/
|
||||
class BlockFilter
|
||||
{
|
||||
private:
|
||||
BlockFilterType m_filter_type = BlockFilterType::INVALID;
|
||||
uint256 m_block_hash;
|
||||
GCSFilter m_filter;
|
||||
|
||||
bool BuildParams(GCSFilter::Params& params) const;
|
||||
|
||||
public:
|
||||
|
||||
BlockFilter() = default;
|
||||
|
||||
//! Reconstruct a BlockFilter from parts.
|
||||
BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
|
||||
std::vector<unsigned char> filter);
|
||||
|
||||
//! Construct a new BlockFilter of the specified type from a block.
|
||||
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
|
||||
|
||||
BlockFilterType GetFilterType() const { return m_filter_type; }
|
||||
const uint256& GetBlockHash() const { return m_block_hash; }
|
||||
const GCSFilter& GetFilter() const { return m_filter; }
|
||||
|
||||
const std::vector<unsigned char>& GetEncodedFilter() const
|
||||
{
|
||||
return m_filter.GetEncoded();
|
||||
}
|
||||
|
||||
//! Compute the filter hash.
|
||||
uint256 GetHash() const;
|
||||
|
||||
//! Compute the filter header given the previous one.
|
||||
uint256 ComputeHeader(const uint256& prev_header) const;
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
s << m_block_hash
|
||||
<< static_cast<uint8_t>(m_filter_type)
|
||||
<< m_filter.GetEncoded();
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
std::vector<unsigned char> encoded_filter;
|
||||
uint8_t filter_type;
|
||||
|
||||
s >> m_block_hash
|
||||
>> filter_type
|
||||
>> encoded_filter;
|
||||
|
||||
m_filter_type = static_cast<BlockFilterType>(filter_type);
|
||||
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::ios_base::failure("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, std::move(encoded_filter));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_BLOCKFILTER_H
|
343
lib/bip158/src/coins.h
Normal file
343
lib/bip158/src/coins.h
Normal file
@ -0,0 +1,343 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_COINS_H
|
||||
#define BITCOIN_COINS_H
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <compressor.h>
|
||||
#include <core_memusage.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <memusage.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* A UTXO entry.
|
||||
*
|
||||
* Serialized format:
|
||||
* - VARINT((coinbase ? 1 : 0) | (height << 1))
|
||||
* - the non-spent CTxOut (via CTxOutCompressor)
|
||||
*/
|
||||
class Coin
|
||||
{
|
||||
public:
|
||||
//! unspent transaction output
|
||||
CTxOut out;
|
||||
|
||||
//! whether containing transaction was a coinbase
|
||||
unsigned int fCoinBase : 1;
|
||||
|
||||
//! at which height this containing transaction was included in the active block chain
|
||||
uint32_t nHeight : 31;
|
||||
|
||||
//! construct a Coin from a CTxOut and height/coinbase information.
|
||||
Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
|
||||
Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
|
||||
|
||||
void Clear() {
|
||||
out.SetNull();
|
||||
fCoinBase = false;
|
||||
nHeight = 0;
|
||||
}
|
||||
|
||||
//! empty constructor
|
||||
Coin() : fCoinBase(false), nHeight(0) { }
|
||||
|
||||
bool IsCoinBase() const {
|
||||
return fCoinBase;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * 2 + fCoinBase;
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, CTxOutCompressor(REF(out)));
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s) {
|
||||
uint32_t code = 0;
|
||||
::Unserialize(s, VARINT(code));
|
||||
nHeight = code >> 1;
|
||||
fCoinBase = code & 1;
|
||||
::Unserialize(s, CTxOutCompressor(out));
|
||||
}
|
||||
|
||||
bool IsSpent() const {
|
||||
return out.IsNull();
|
||||
}
|
||||
|
||||
size_t DynamicMemoryUsage() const {
|
||||
return memusage::DynamicUsage(out.scriptPubKey);
|
||||
}
|
||||
};
|
||||
|
||||
class SaltedOutpointHasher
|
||||
{
|
||||
private:
|
||||
/** Salt */
|
||||
const uint64_t k0, k1;
|
||||
|
||||
public:
|
||||
SaltedOutpointHasher();
|
||||
|
||||
/**
|
||||
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
|
||||
* unordered_map will behave unpredictably if the custom hasher returns a
|
||||
* uint64_t, resulting in failures when syncing the chain (#4634).
|
||||
*/
|
||||
size_t operator()(const COutPoint& id) const {
|
||||
return SipHashUint256Extra(k0, k1, id.hash, id.n);
|
||||
}
|
||||
};
|
||||
|
||||
struct CCoinsCacheEntry
|
||||
{
|
||||
Coin coin; // The actual cached data.
|
||||
unsigned char flags;
|
||||
|
||||
enum Flags {
|
||||
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
|
||||
FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
|
||||
/* Note that FRESH is a performance optimization with which we can
|
||||
* erase coins that are fully spent if we know we do not need to
|
||||
* flush the changes to the parent cache. It is always safe to
|
||||
* not mark FRESH if that condition is not guaranteed.
|
||||
*/
|
||||
};
|
||||
|
||||
CCoinsCacheEntry() : flags(0) {}
|
||||
explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
|
||||
|
||||
/** Cursor for iterating over CoinsView state */
|
||||
class CCoinsViewCursor
|
||||
{
|
||||
public:
|
||||
CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
|
||||
virtual ~CCoinsViewCursor() {}
|
||||
|
||||
virtual bool GetKey(COutPoint &key) const = 0;
|
||||
virtual bool GetValue(Coin &coin) const = 0;
|
||||
virtual unsigned int GetValueSize() const = 0;
|
||||
|
||||
virtual bool Valid() const = 0;
|
||||
virtual void Next() = 0;
|
||||
|
||||
//! Get best block at the time this cursor was created
|
||||
const uint256 &GetBestBlock() const { return hashBlock; }
|
||||
private:
|
||||
uint256 hashBlock;
|
||||
};
|
||||
|
||||
/** Abstract view on the open txout dataset. */
|
||||
class CCoinsView
|
||||
{
|
||||
public:
|
||||
/** Retrieve the Coin (unspent transaction output) for a given outpoint.
|
||||
* Returns true only when an unspent coin was found, which is returned in coin.
|
||||
* When false is returned, coin's value is unspecified.
|
||||
*/
|
||||
virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
|
||||
|
||||
//! Just check whether a given outpoint is unspent.
|
||||
virtual bool HaveCoin(const COutPoint &outpoint) const;
|
||||
|
||||
//! Retrieve the block hash whose state this CCoinsView currently represents
|
||||
virtual uint256 GetBestBlock() const;
|
||||
|
||||
//! Retrieve the range of blocks that may have been only partially written.
|
||||
//! If the database is in a consistent state, the result is the empty vector.
|
||||
//! Otherwise, a two-element vector is returned consisting of the new and
|
||||
//! the old block hash, in that order.
|
||||
virtual std::vector<uint256> GetHeadBlocks() const;
|
||||
|
||||
//! Do a bulk modification (multiple Coin changes + BestBlock change).
|
||||
//! The passed mapCoins can be modified.
|
||||
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
|
||||
|
||||
//! Get a cursor to iterate over the whole state
|
||||
virtual CCoinsViewCursor *Cursor() const;
|
||||
|
||||
//! As we use CCoinsViews polymorphically, have a virtual destructor
|
||||
virtual ~CCoinsView() {}
|
||||
|
||||
//! Estimate database size (0 if not implemented)
|
||||
virtual size_t EstimateSize() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
/** CCoinsView backed by another CCoinsView */
|
||||
class CCoinsViewBacked : public CCoinsView
|
||||
{
|
||||
protected:
|
||||
CCoinsView *base;
|
||||
|
||||
public:
|
||||
CCoinsViewBacked(CCoinsView *viewIn);
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
std::vector<uint256> GetHeadBlocks() const override;
|
||||
void SetBackend(CCoinsView &viewIn);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
CCoinsViewCursor *Cursor() const override;
|
||||
size_t EstimateSize() const override;
|
||||
};
|
||||
|
||||
|
||||
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
|
||||
class CCoinsViewCache : public CCoinsViewBacked
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Make mutable so that we can "fill the cache" even from Get-methods
|
||||
* declared as "const".
|
||||
*/
|
||||
mutable uint256 hashBlock;
|
||||
mutable CCoinsMap cacheCoins;
|
||||
|
||||
/* Cached dynamic memory usage for the inner Coin objects. */
|
||||
mutable size_t cachedCoinsUsage;
|
||||
|
||||
public:
|
||||
CCoinsViewCache(CCoinsView *baseIn);
|
||||
|
||||
/**
|
||||
* By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
|
||||
*/
|
||||
CCoinsViewCache(const CCoinsViewCache &) = delete;
|
||||
|
||||
// Standard CCoinsView methods
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
void SetBestBlock(const uint256 &hashBlock);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
CCoinsViewCursor* Cursor() const override {
|
||||
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have the given utxo already loaded in this cache.
|
||||
* The semantics are the same as HaveCoin(), but no calls to
|
||||
* the backing CCoinsView are made.
|
||||
*/
|
||||
bool HaveCoinInCache(const COutPoint &outpoint) const;
|
||||
|
||||
/**
|
||||
* Return a reference to Coin in the cache, or a pruned one if not found. This is
|
||||
* more efficient than GetCoin.
|
||||
*
|
||||
* Generally, do not hold the reference returned for more than a short scope.
|
||||
* While the current implementation allows for modifications to the contents
|
||||
* of the cache while holding the reference, this behavior should not be relied
|
||||
* on! To be safe, best to not hold the returned reference through any other
|
||||
* calls to this cache.
|
||||
*/
|
||||
const Coin& AccessCoin(const COutPoint &output) const;
|
||||
|
||||
/**
|
||||
* Add a coin. Set potential_overwrite to true if a non-pruned version may
|
||||
* already exist.
|
||||
*/
|
||||
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
|
||||
|
||||
/**
|
||||
* Spend a coin. Pass moveto in order to get the deleted data.
|
||||
* If no unspent output exists for the passed outpoint, this call
|
||||
* has no effect.
|
||||
*/
|
||||
bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
|
||||
|
||||
/**
|
||||
* Push the modifications applied to this cache to its base.
|
||||
* Failure to call this method before destruction will cause the changes to be forgotten.
|
||||
* If false is returned, the state of this cache (and its backing view) will be undefined.
|
||||
*/
|
||||
bool Flush();
|
||||
|
||||
/**
|
||||
* Removes the UTXO with the given outpoint from the cache, if it is
|
||||
* not modified.
|
||||
*/
|
||||
void Uncache(const COutPoint &outpoint);
|
||||
|
||||
//! Calculate the size of the cache (in number of transaction outputs)
|
||||
unsigned int GetCacheSize() const;
|
||||
|
||||
//! Calculate the size of the cache (in bytes)
|
||||
size_t DynamicMemoryUsage() const;
|
||||
|
||||
/**
|
||||
* Amount of bitcoins coming in to a transaction
|
||||
* Note that lightweight clients may not know anything besides the hash of previous transactions,
|
||||
* so may not be able to calculate this.
|
||||
*
|
||||
* @param[in] tx transaction for which we are checking input total
|
||||
* @return Sum of value of all inputs (scriptSigs)
|
||||
*/
|
||||
CAmount GetValueIn(const CTransaction& tx) const;
|
||||
|
||||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @note this is marked const, but may actually append to `cacheCoins`, increasing
|
||||
* memory usage.
|
||||
*/
|
||||
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
|
||||
};
|
||||
|
||||
//! Utility function to add all of a transaction's outputs to a cache.
|
||||
//! When check is false, this assumes that overwrites are only possible for coinbase transactions.
|
||||
//! When check is true, the underlying view may be queried to determine whether an addition is
|
||||
//! an overwrite.
|
||||
// TODO: pass in a boolean to limit these possible overwrites to known
|
||||
// (pre-BIP34) cases.
|
||||
void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
|
||||
|
||||
//! Utility function to find any unspent output with a given txid.
|
||||
//! This function can be quite expensive because in the event of a transaction
|
||||
//! which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
|
||||
//! lookups to database, so it should be used with care.
|
||||
const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
|
||||
|
||||
/**
|
||||
* This is a minimally invasive approach to shutdown on LevelDB read errors from the
|
||||
* chainstate, while keeping user interface out of the common library, which is shared
|
||||
* between bitcoind, and bitcoin-qt and non-server tools.
|
||||
*
|
||||
* Writes do not need similar protection, as failure to write is handled by the caller.
|
||||
*/
|
||||
class CCoinsViewErrorCatcher final : public CCoinsViewBacked
|
||||
{
|
||||
public:
|
||||
explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
|
||||
|
||||
void AddReadErrCallback(std::function<void()> f) {
|
||||
m_err_callbacks.emplace_back(std::move(f));
|
||||
}
|
||||
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
|
||||
private:
|
||||
/** A list of callbacks to execute upon leveldb read error. */
|
||||
std::vector<std::function<void()>> m_err_callbacks;
|
||||
|
||||
};
|
||||
|
||||
#endif // BITCOIN_COINS_H
|
66
lib/bip158/src/compat/byteswap.h
Normal file
66
lib/bip158/src/compat/byteswap.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_COMPAT_BYTESWAP_H
|
||||
#define BITCOIN_COMPAT_BYTESWAP_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#if defined(MAC_OSX)
|
||||
|
||||
#if !defined(bswap_16)
|
||||
|
||||
// Mac OS X / Darwin features; we include a check for bswap_16 because if it is already defined, protobuf has
|
||||
// defined these macros for us already; if it isn't, we do it ourselves. In either case, we get the exact same
|
||||
// result regardless which path was taken
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#endif // !defined(bswap_16)
|
||||
|
||||
#else
|
||||
// Non-Mac OS X / non-Darwin
|
||||
|
||||
#if HAVE_DECL_BSWAP_16 == 0
|
||||
inline uint16_t bswap_16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP16 == 0
|
||||
|
||||
#if HAVE_DECL_BSWAP_32 == 0
|
||||
inline uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) |
|
||||
((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24));
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP32 == 0
|
||||
|
||||
#if HAVE_DECL_BSWAP_64 == 0
|
||||
inline uint64_t bswap_64(uint64_t x)
|
||||
{
|
||||
return (((x & 0xff00000000000000ull) >> 56)
|
||||
| ((x & 0x00ff000000000000ull) >> 40)
|
||||
| ((x & 0x0000ff0000000000ull) >> 24)
|
||||
| ((x & 0x000000ff00000000ull) >> 8)
|
||||
| ((x & 0x00000000ff000000ull) << 8)
|
||||
| ((x & 0x0000000000ff0000ull) << 24)
|
||||
| ((x & 0x000000000000ff00ull) << 40)
|
||||
| ((x & 0x00000000000000ffull) << 56));
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP64 == 0
|
||||
|
||||
#endif // defined(MAC_OSX)
|
||||
|
||||
#endif // BITCOIN_COMPAT_BYTESWAP_H
|
241
lib/bip158/src/compat/endian.h
Normal file
241
lib/bip158/src/compat/endian.h
Normal file
@ -0,0 +1,241 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_COMPAT_ENDIAN_H
|
||||
#define BITCOIN_COMPAT_ENDIAN_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#include <compat/byteswap.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(HAVE_ENDIAN_H)
|
||||
#include <endian.h>
|
||||
#elif defined(HAVE_SYS_ENDIAN_H)
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
// While not technically a supported configuration, defaulting to defining these
|
||||
// DECLs when we were compiled without autotools makes it easier for other build
|
||||
// systems to build things like libbitcoinconsensus for strange targets.
|
||||
#ifdef htobe16
|
||||
#define HAVE_DECL_HTOBE16 1
|
||||
#endif
|
||||
#ifdef htole16
|
||||
#define HAVE_DECL_HTOLE16 1
|
||||
#endif
|
||||
#ifdef be16toh
|
||||
#define HAVE_DECL_BE16TOH 1
|
||||
#endif
|
||||
#ifdef le16toh
|
||||
#define HAVE_DECL_LE16TOH 1
|
||||
#endif
|
||||
|
||||
#ifdef htobe32
|
||||
#define HAVE_DECL_HTOBE32 1
|
||||
#endif
|
||||
#ifdef htole32
|
||||
#define HAVE_DECL_HTOLE32 1
|
||||
#endif
|
||||
#ifdef be32toh
|
||||
#define HAVE_DECL_BE32TOH 1
|
||||
#endif
|
||||
#ifdef le32toh
|
||||
#define HAVE_DECL_LE32TOH 1
|
||||
#endif
|
||||
|
||||
#ifdef htobe64
|
||||
#define HAVE_DECL_HTOBE64 1
|
||||
#endif
|
||||
#ifdef htole64
|
||||
#define HAVE_DECL_HTOLE64 1
|
||||
#endif
|
||||
#ifdef be64toh
|
||||
#define HAVE_DECL_BE64TOH 1
|
||||
#endif
|
||||
#ifdef le64toh
|
||||
#define HAVE_DECL_LE64TOH 1
|
||||
#endif
|
||||
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
|
||||
#if HAVE_DECL_HTOBE16 == 0
|
||||
inline uint16_t htobe16(uint16_t host_16bits)
|
||||
{
|
||||
return host_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE16
|
||||
|
||||
#if HAVE_DECL_HTOLE16 == 0
|
||||
inline uint16_t htole16(uint16_t host_16bits)
|
||||
{
|
||||
return bswap_16(host_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE16
|
||||
|
||||
#if HAVE_DECL_BE16TOH == 0
|
||||
inline uint16_t be16toh(uint16_t big_endian_16bits)
|
||||
{
|
||||
return big_endian_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE16TOH
|
||||
|
||||
#if HAVE_DECL_LE16TOH == 0
|
||||
inline uint16_t le16toh(uint16_t little_endian_16bits)
|
||||
{
|
||||
return bswap_16(little_endian_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE16TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE32 == 0
|
||||
inline uint32_t htobe32(uint32_t host_32bits)
|
||||
{
|
||||
return host_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE32
|
||||
|
||||
#if HAVE_DECL_HTOLE32 == 0
|
||||
inline uint32_t htole32(uint32_t host_32bits)
|
||||
{
|
||||
return bswap_32(host_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE32
|
||||
|
||||
#if HAVE_DECL_BE32TOH == 0
|
||||
inline uint32_t be32toh(uint32_t big_endian_32bits)
|
||||
{
|
||||
return big_endian_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE32TOH
|
||||
|
||||
#if HAVE_DECL_LE32TOH == 0
|
||||
inline uint32_t le32toh(uint32_t little_endian_32bits)
|
||||
{
|
||||
return bswap_32(little_endian_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE32TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE64 == 0
|
||||
inline uint64_t htobe64(uint64_t host_64bits)
|
||||
{
|
||||
return host_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE64
|
||||
|
||||
#if HAVE_DECL_HTOLE64 == 0
|
||||
inline uint64_t htole64(uint64_t host_64bits)
|
||||
{
|
||||
return bswap_64(host_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE64
|
||||
|
||||
#if HAVE_DECL_BE64TOH == 0
|
||||
inline uint64_t be64toh(uint64_t big_endian_64bits)
|
||||
{
|
||||
return big_endian_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE64TOH
|
||||
|
||||
#if HAVE_DECL_LE64TOH == 0
|
||||
inline uint64_t le64toh(uint64_t little_endian_64bits)
|
||||
{
|
||||
return bswap_64(little_endian_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE64TOH
|
||||
|
||||
#else // WORDS_BIGENDIAN
|
||||
|
||||
#if HAVE_DECL_HTOBE16 == 0
|
||||
inline uint16_t htobe16(uint16_t host_16bits)
|
||||
{
|
||||
return bswap_16(host_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE16
|
||||
|
||||
#if HAVE_DECL_HTOLE16 == 0
|
||||
inline uint16_t htole16(uint16_t host_16bits)
|
||||
{
|
||||
return host_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE16
|
||||
|
||||
#if HAVE_DECL_BE16TOH == 0
|
||||
inline uint16_t be16toh(uint16_t big_endian_16bits)
|
||||
{
|
||||
return bswap_16(big_endian_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE16TOH
|
||||
|
||||
#if HAVE_DECL_LE16TOH == 0
|
||||
inline uint16_t le16toh(uint16_t little_endian_16bits)
|
||||
{
|
||||
return little_endian_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE16TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE32 == 0
|
||||
inline uint32_t htobe32(uint32_t host_32bits)
|
||||
{
|
||||
return bswap_32(host_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE32
|
||||
|
||||
#if HAVE_DECL_HTOLE32 == 0
|
||||
inline uint32_t htole32(uint32_t host_32bits)
|
||||
{
|
||||
return host_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE32
|
||||
|
||||
#if HAVE_DECL_BE32TOH == 0
|
||||
inline uint32_t be32toh(uint32_t big_endian_32bits)
|
||||
{
|
||||
return bswap_32(big_endian_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE32TOH
|
||||
|
||||
#if HAVE_DECL_LE32TOH == 0
|
||||
inline uint32_t le32toh(uint32_t little_endian_32bits)
|
||||
{
|
||||
return little_endian_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE32TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE64 == 0
|
||||
inline uint64_t htobe64(uint64_t host_64bits)
|
||||
{
|
||||
return bswap_64(host_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE64
|
||||
|
||||
#if HAVE_DECL_HTOLE64 == 0
|
||||
inline uint64_t htole64(uint64_t host_64bits)
|
||||
{
|
||||
return host_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE64
|
||||
|
||||
#if HAVE_DECL_BE64TOH == 0
|
||||
inline uint64_t be64toh(uint64_t big_endian_64bits)
|
||||
{
|
||||
return bswap_64(big_endian_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE64TOH
|
||||
|
||||
#if HAVE_DECL_LE64TOH == 0
|
||||
inline uint64_t le64toh(uint64_t little_endian_64bits)
|
||||
{
|
||||
return little_endian_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE64TOH
|
||||
|
||||
#endif // WORDS_BIGENDIAN
|
||||
|
||||
#endif // BITCOIN_COMPAT_ENDIAN_H
|
111
lib/bip158/src/compressor.h
Normal file
111
lib/bip158/src/compressor.h
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_COMPRESSOR_H
|
||||
#define BITCOIN_COMPRESSOR_H
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
#include <serialize.h>
|
||||
#include <span.h>
|
||||
|
||||
class CKeyID;
|
||||
class CPubKey;
|
||||
class CScriptID;
|
||||
|
||||
bool CompressScript(const CScript& script, std::vector<unsigned char> &out);
|
||||
unsigned int GetSpecialScriptSize(unsigned int nSize);
|
||||
bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &out);
|
||||
|
||||
uint64_t CompressAmount(uint64_t nAmount);
|
||||
uint64_t DecompressAmount(uint64_t nAmount);
|
||||
|
||||
/** Compact serializer for scripts.
|
||||
*
|
||||
* It detects common cases and encodes them much more efficiently.
|
||||
* 3 special cases are defined:
|
||||
* * Pay to pubkey hash (encoded as 21 bytes)
|
||||
* * Pay to script hash (encoded as 21 bytes)
|
||||
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
|
||||
*
|
||||
* Other scripts up to 121 bytes require 1 byte + script length. Above
|
||||
* that, scripts up to 16505 bytes require 2 bytes + script length.
|
||||
*/
|
||||
class CScriptCompressor
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* make this static for now (there are only 6 special scripts defined)
|
||||
* this can potentially be extended together with a new nVersion for
|
||||
* transactions, in which case this value becomes dependent on nVersion
|
||||
* and nHeight of the enclosing transaction.
|
||||
*/
|
||||
static const unsigned int nSpecialScripts = 6;
|
||||
|
||||
CScript &script;
|
||||
public:
|
||||
explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
std::vector<unsigned char> compr;
|
||||
if (CompressScript(script, compr)) {
|
||||
s << MakeSpan(compr);
|
||||
return;
|
||||
}
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
s << VARINT(nSize);
|
||||
s << MakeSpan(script);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s) {
|
||||
unsigned int nSize = 0;
|
||||
s >> VARINT(nSize);
|
||||
if (nSize < nSpecialScripts) {
|
||||
std::vector<unsigned char> vch(GetSpecialScriptSize(nSize), 0x00);
|
||||
s >> MakeSpan(vch);
|
||||
DecompressScript(script, nSize, vch);
|
||||
return;
|
||||
}
|
||||
nSize -= nSpecialScripts;
|
||||
if (nSize > MAX_SCRIPT_SIZE) {
|
||||
// Overly long script, replace with a short invalid one
|
||||
script << OP_RETURN;
|
||||
s.ignore(nSize);
|
||||
} else {
|
||||
script.resize(nSize);
|
||||
s >> MakeSpan(script);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** wrapper for CTxOut that provides a more compact serialization */
|
||||
class CTxOutCompressor
|
||||
{
|
||||
private:
|
||||
CTxOut &txout;
|
||||
|
||||
public:
|
||||
explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
if (!ser_action.ForRead()) {
|
||||
uint64_t nVal = CompressAmount(txout.nValue);
|
||||
READWRITE(VARINT(nVal));
|
||||
} else {
|
||||
uint64_t nVal = 0;
|
||||
READWRITE(VARINT(nVal));
|
||||
txout.nValue = DecompressAmount(nVal);
|
||||
}
|
||||
CScriptCompressor cscript(REF(txout.scriptPubKey));
|
||||
READWRITE(cscript);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_COMPRESSOR_H
|
32
lib/bip158/src/consensus/consensus.h
Normal file
32
lib/bip158/src/consensus/consensus.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CONSENSUS_CONSENSUS_H
|
||||
#define BITCOIN_CONSENSUS_CONSENSUS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
|
||||
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
|
||||
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
|
||||
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
|
||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
|
||||
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||
static const int COINBASE_MATURITY = 100;
|
||||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is the lower bound for the size of a valid serialized CTransaction
|
||||
static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
|
||||
|
||||
/** Flags for nSequence and nLockTime locks */
|
||||
/** Interpret sequence numbers as relative lock-time constraints. */
|
||||
static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
|
||||
/** Use GetMedianTimePast() instead of nTime for end point timestamp. */
|
||||
static constexpr unsigned int LOCKTIME_MEDIAN_TIME_PAST = (1 << 1);
|
||||
|
||||
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
|
71
lib/bip158/src/core_memusage.h
Normal file
71
lib/bip158/src/core_memusage.h
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CORE_MEMUSAGE_H
|
||||
#define BITCOIN_CORE_MEMUSAGE_H
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <primitives/block.h>
|
||||
#include <memusage.h>
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CScript& script) {
|
||||
return memusage::DynamicUsage(script);
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CTxIn& in) {
|
||||
size_t mem = RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout) + memusage::DynamicUsage(in.scriptWitness.stack);
|
||||
for (std::vector<std::vector<unsigned char> >::const_iterator it = in.scriptWitness.stack.begin(); it != in.scriptWitness.stack.end(); it++) {
|
||||
mem += memusage::DynamicUsage(*it);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
|
||||
return RecursiveDynamicUsage(out.scriptPubKey);
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
|
||||
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
|
||||
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
|
||||
mem += RecursiveDynamicUsage(*it);
|
||||
}
|
||||
for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
|
||||
mem += RecursiveDynamicUsage(*it);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
|
||||
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
|
||||
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
|
||||
mem += RecursiveDynamicUsage(*it);
|
||||
}
|
||||
for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
|
||||
mem += RecursiveDynamicUsage(*it);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CBlock& block) {
|
||||
size_t mem = memusage::DynamicUsage(block.vtx);
|
||||
for (const auto& tx : block.vtx) {
|
||||
mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) {
|
||||
return memusage::DynamicUsage(locator.vHave);
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
static inline size_t RecursiveDynamicUsage(const std::shared_ptr<X>& p) {
|
||||
return p ? memusage::DynamicUsage(p) + RecursiveDynamicUsage(*p) : 0;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_CORE_MEMUSAGE_H
|
310
lib/bip158/src/crypto/chacha20.cpp
Normal file
310
lib/bip158/src/crypto/chacha20.cpp
Normal file
@ -0,0 +1,310 @@
|
||||
// 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.
|
||||
|
||||
// Based on the public domain implementation 'merged' by D. J. Bernstein
|
||||
// See https://cr.yp.to/chacha.html.
|
||||
|
||||
#include <crypto/common.h>
|
||||
#include <crypto/chacha20.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
|
||||
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
a += b; d = rotl32(d ^ a, 16); \
|
||||
c += d; b = rotl32(b ^ c, 12); \
|
||||
a += b; d = rotl32(d ^ a, 8); \
|
||||
c += d; b = rotl32(b ^ c, 7);
|
||||
|
||||
static const unsigned char sigma[] = "expand 32-byte k";
|
||||
static const unsigned char tau[] = "expand 16-byte k";
|
||||
|
||||
void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
|
||||
{
|
||||
const unsigned char *constants;
|
||||
|
||||
input[4] = ReadLE32(k + 0);
|
||||
input[5] = ReadLE32(k + 4);
|
||||
input[6] = ReadLE32(k + 8);
|
||||
input[7] = ReadLE32(k + 12);
|
||||
if (keylen == 32) { /* recommended */
|
||||
k += 16;
|
||||
constants = sigma;
|
||||
} else { /* keylen == 16 */
|
||||
constants = tau;
|
||||
}
|
||||
input[8] = ReadLE32(k + 0);
|
||||
input[9] = ReadLE32(k + 4);
|
||||
input[10] = ReadLE32(k + 8);
|
||||
input[11] = ReadLE32(k + 12);
|
||||
input[0] = ReadLE32(constants + 0);
|
||||
input[1] = ReadLE32(constants + 4);
|
||||
input[2] = ReadLE32(constants + 8);
|
||||
input[3] = ReadLE32(constants + 12);
|
||||
input[12] = 0;
|
||||
input[13] = 0;
|
||||
input[14] = 0;
|
||||
input[15] = 0;
|
||||
}
|
||||
|
||||
ChaCha20::ChaCha20()
|
||||
{
|
||||
memset(input, 0, sizeof(input));
|
||||
}
|
||||
|
||||
ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
|
||||
{
|
||||
SetKey(k, keylen);
|
||||
}
|
||||
|
||||
void ChaCha20::SetIV(uint64_t iv)
|
||||
{
|
||||
input[14] = iv;
|
||||
input[15] = iv >> 32;
|
||||
}
|
||||
|
||||
void ChaCha20::Seek(uint64_t pos)
|
||||
{
|
||||
input[12] = pos;
|
||||
input[13] = pos >> 32;
|
||||
}
|
||||
|
||||
void ChaCha20::Keystream(unsigned char* c, size_t bytes)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
unsigned char *ctarget = nullptr;
|
||||
unsigned char tmp[64];
|
||||
unsigned int i;
|
||||
|
||||
if (!bytes) return;
|
||||
|
||||
j0 = input[0];
|
||||
j1 = input[1];
|
||||
j2 = input[2];
|
||||
j3 = input[3];
|
||||
j4 = input[4];
|
||||
j5 = input[5];
|
||||
j6 = input[6];
|
||||
j7 = input[7];
|
||||
j8 = input[8];
|
||||
j9 = input[9];
|
||||
j10 = input[10];
|
||||
j11 = input[11];
|
||||
j12 = input[12];
|
||||
j13 = input[13];
|
||||
j14 = input[14];
|
||||
j15 = input[15];
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = 20;i > 0;i -= 2) {
|
||||
QUARTERROUND( x0, x4, x8,x12)
|
||||
QUARTERROUND( x1, x5, x9,x13)
|
||||
QUARTERROUND( x2, x6,x10,x14)
|
||||
QUARTERROUND( x3, x7,x11,x15)
|
||||
QUARTERROUND( x0, x5,x10,x15)
|
||||
QUARTERROUND( x1, x6,x11,x12)
|
||||
QUARTERROUND( x2, x7, x8,x13)
|
||||
QUARTERROUND( x3, x4, x9,x14)
|
||||
}
|
||||
x0 += j0;
|
||||
x1 += j1;
|
||||
x2 += j2;
|
||||
x3 += j3;
|
||||
x4 += j4;
|
||||
x5 += j5;
|
||||
x6 += j6;
|
||||
x7 += j7;
|
||||
x8 += j8;
|
||||
x9 += j9;
|
||||
x10 += j10;
|
||||
x11 += j11;
|
||||
x12 += j12;
|
||||
x13 += j13;
|
||||
x14 += j14;
|
||||
x15 += j15;
|
||||
|
||||
++j12;
|
||||
if (!j12) ++j13;
|
||||
|
||||
WriteLE32(c + 0, x0);
|
||||
WriteLE32(c + 4, x1);
|
||||
WriteLE32(c + 8, x2);
|
||||
WriteLE32(c + 12, x3);
|
||||
WriteLE32(c + 16, x4);
|
||||
WriteLE32(c + 20, x5);
|
||||
WriteLE32(c + 24, x6);
|
||||
WriteLE32(c + 28, x7);
|
||||
WriteLE32(c + 32, x8);
|
||||
WriteLE32(c + 36, x9);
|
||||
WriteLE32(c + 40, x10);
|
||||
WriteLE32(c + 44, x11);
|
||||
WriteLE32(c + 48, x12);
|
||||
WriteLE32(c + 52, x13);
|
||||
WriteLE32(c + 56, x14);
|
||||
WriteLE32(c + 60, x15);
|
||||
|
||||
if (bytes <= 64) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) ctarget[i] = c[i];
|
||||
}
|
||||
input[12] = j12;
|
||||
input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
}
|
||||
}
|
||||
|
||||
void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
unsigned char *ctarget = nullptr;
|
||||
unsigned char tmp[64];
|
||||
unsigned int i;
|
||||
|
||||
if (!bytes) return;
|
||||
|
||||
j0 = input[0];
|
||||
j1 = input[1];
|
||||
j2 = input[2];
|
||||
j3 = input[3];
|
||||
j4 = input[4];
|
||||
j5 = input[5];
|
||||
j6 = input[6];
|
||||
j7 = input[7];
|
||||
j8 = input[8];
|
||||
j9 = input[9];
|
||||
j10 = input[10];
|
||||
j11 = input[11];
|
||||
j12 = input[12];
|
||||
j13 = input[13];
|
||||
j14 = input[14];
|
||||
j15 = input[15];
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
// if m has fewer than 64 bytes available, copy m to tmp and
|
||||
// read from tmp instead
|
||||
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = 20;i > 0;i -= 2) {
|
||||
QUARTERROUND( x0, x4, x8,x12)
|
||||
QUARTERROUND( x1, x5, x9,x13)
|
||||
QUARTERROUND( x2, x6,x10,x14)
|
||||
QUARTERROUND( x3, x7,x11,x15)
|
||||
QUARTERROUND( x0, x5,x10,x15)
|
||||
QUARTERROUND( x1, x6,x11,x12)
|
||||
QUARTERROUND( x2, x7, x8,x13)
|
||||
QUARTERROUND( x3, x4, x9,x14)
|
||||
}
|
||||
x0 += j0;
|
||||
x1 += j1;
|
||||
x2 += j2;
|
||||
x3 += j3;
|
||||
x4 += j4;
|
||||
x5 += j5;
|
||||
x6 += j6;
|
||||
x7 += j7;
|
||||
x8 += j8;
|
||||
x9 += j9;
|
||||
x10 += j10;
|
||||
x11 += j11;
|
||||
x12 += j12;
|
||||
x13 += j13;
|
||||
x14 += j14;
|
||||
x15 += j15;
|
||||
|
||||
x0 ^= ReadLE32(m + 0);
|
||||
x1 ^= ReadLE32(m + 4);
|
||||
x2 ^= ReadLE32(m + 8);
|
||||
x3 ^= ReadLE32(m + 12);
|
||||
x4 ^= ReadLE32(m + 16);
|
||||
x5 ^= ReadLE32(m + 20);
|
||||
x6 ^= ReadLE32(m + 24);
|
||||
x7 ^= ReadLE32(m + 28);
|
||||
x8 ^= ReadLE32(m + 32);
|
||||
x9 ^= ReadLE32(m + 36);
|
||||
x10 ^= ReadLE32(m + 40);
|
||||
x11 ^= ReadLE32(m + 44);
|
||||
x12 ^= ReadLE32(m + 48);
|
||||
x13 ^= ReadLE32(m + 52);
|
||||
x14 ^= ReadLE32(m + 56);
|
||||
x15 ^= ReadLE32(m + 60);
|
||||
|
||||
++j12;
|
||||
if (!j12) ++j13;
|
||||
|
||||
WriteLE32(c + 0, x0);
|
||||
WriteLE32(c + 4, x1);
|
||||
WriteLE32(c + 8, x2);
|
||||
WriteLE32(c + 12, x3);
|
||||
WriteLE32(c + 16, x4);
|
||||
WriteLE32(c + 20, x5);
|
||||
WriteLE32(c + 24, x6);
|
||||
WriteLE32(c + 28, x7);
|
||||
WriteLE32(c + 32, x8);
|
||||
WriteLE32(c + 36, x9);
|
||||
WriteLE32(c + 40, x10);
|
||||
WriteLE32(c + 44, x11);
|
||||
WriteLE32(c + 48, x12);
|
||||
WriteLE32(c + 52, x13);
|
||||
WriteLE32(c + 56, x14);
|
||||
WriteLE32(c + 60, x15);
|
||||
|
||||
if (bytes <= 64) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) ctarget[i] = c[i];
|
||||
}
|
||||
input[12] = j12;
|
||||
input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
34
lib/bip158/src/crypto/chacha20.h
Normal file
34
lib/bip158/src/crypto/chacha20.h
Normal file
@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_CHACHA20_H
|
||||
#define BITCOIN_CRYPTO_CHACHA20_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
|
||||
https://cr.yp.to/chacha/chacha-20080128.pdf */
|
||||
class ChaCha20
|
||||
{
|
||||
private:
|
||||
uint32_t input[16];
|
||||
|
||||
public:
|
||||
ChaCha20();
|
||||
ChaCha20(const unsigned char* key, size_t keylen);
|
||||
void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */
|
||||
void SetIV(uint64_t iv); // set the 64bit nonce
|
||||
void Seek(uint64_t pos); // set the 64bit block counter
|
||||
|
||||
/** outputs the keystream of size <bytes> into <c> */
|
||||
void Keystream(unsigned char* c, size_t bytes);
|
||||
|
||||
/** enciphers the message <input> of length <bytes> and write the enciphered representation into <output>
|
||||
* Used for encryption and decryption (XOR)
|
||||
*/
|
||||
void Crypt(const unsigned char* input, unsigned char* output, size_t bytes);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_CHACHA20_H
|
103
lib/bip158/src/crypto/common.h
Normal file
103
lib/bip158/src/crypto/common.h
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_COMMON_H
|
||||
#define BITCOIN_CRYPTO_COMMON_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <compat/endian.h>
|
||||
|
||||
uint16_t static inline ReadLE16(const unsigned char* ptr)
|
||||
{
|
||||
uint16_t x;
|
||||
memcpy((char*)&x, ptr, 2);
|
||||
return le16toh(x);
|
||||
}
|
||||
|
||||
uint32_t static inline ReadLE32(const unsigned char* ptr)
|
||||
{
|
||||
uint32_t x;
|
||||
memcpy((char*)&x, ptr, 4);
|
||||
return le32toh(x);
|
||||
}
|
||||
|
||||
uint64_t static inline ReadLE64(const unsigned char* ptr)
|
||||
{
|
||||
uint64_t x;
|
||||
memcpy((char*)&x, ptr, 8);
|
||||
return le64toh(x);
|
||||
}
|
||||
|
||||
void static inline WriteLE16(unsigned char* ptr, uint16_t x)
|
||||
{
|
||||
uint16_t v = htole16(x);
|
||||
memcpy(ptr, (char*)&v, 2);
|
||||
}
|
||||
|
||||
void static inline WriteLE32(unsigned char* ptr, uint32_t x)
|
||||
{
|
||||
uint32_t v = htole32(x);
|
||||
memcpy(ptr, (char*)&v, 4);
|
||||
}
|
||||
|
||||
void static inline WriteLE64(unsigned char* ptr, uint64_t x)
|
||||
{
|
||||
uint64_t v = htole64(x);
|
||||
memcpy(ptr, (char*)&v, 8);
|
||||
}
|
||||
|
||||
uint32_t static inline ReadBE32(const unsigned char* ptr)
|
||||
{
|
||||
uint32_t x;
|
||||
memcpy((char*)&x, ptr, 4);
|
||||
return be32toh(x);
|
||||
}
|
||||
|
||||
uint64_t static inline ReadBE64(const unsigned char* ptr)
|
||||
{
|
||||
uint64_t x;
|
||||
memcpy((char*)&x, ptr, 8);
|
||||
return be64toh(x);
|
||||
}
|
||||
|
||||
void static inline WriteBE32(unsigned char* ptr, uint32_t x)
|
||||
{
|
||||
uint32_t v = htobe32(x);
|
||||
memcpy(ptr, (char*)&v, 4);
|
||||
}
|
||||
|
||||
void static inline WriteBE64(unsigned char* ptr, uint64_t x)
|
||||
{
|
||||
uint64_t v = htobe64(x);
|
||||
memcpy(ptr, (char*)&v, 8);
|
||||
}
|
||||
|
||||
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
|
||||
uint64_t static inline CountBits(uint64_t x)
|
||||
{
|
||||
#if HAVE_DECL___BUILTIN_CLZL
|
||||
if (sizeof(unsigned long) >= sizeof(uint64_t)) {
|
||||
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_DECL___BUILTIN_CLZLL
|
||||
if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
|
||||
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
|
||||
}
|
||||
#endif
|
||||
int ret = 0;
|
||||
while (x) {
|
||||
x >>= 1;
|
||||
++ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_CRYPTO_COMMON_H
|
28
lib/bip158/src/crypto/ripemd160.h
Normal file
28
lib/bip158/src/crypto/ripemd160.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_RIPEMD160_H
|
||||
#define BITCOIN_CRYPTO_RIPEMD160_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** A hasher class for RIPEMD-160. */
|
||||
class CRIPEMD160
|
||||
{
|
||||
private:
|
||||
uint32_t s[5];
|
||||
unsigned char buf[64];
|
||||
uint64_t bytes;
|
||||
|
||||
public:
|
||||
static const size_t OUTPUT_SIZE = 20;
|
||||
|
||||
CRIPEMD160();
|
||||
CRIPEMD160& Write(const unsigned char* data, size_t len);
|
||||
void Finalize(unsigned char hash[OUTPUT_SIZE]);
|
||||
CRIPEMD160& Reset();
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_RIPEMD160_H
|
730
lib/bip158/src/crypto/sha256.cpp
Normal file
730
lib/bip158/src/crypto/sha256.cpp
Normal file
@ -0,0 +1,730 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/sha256.h>
|
||||
#include <crypto/common.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <atomic>
|
||||
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
#if defined(USE_ASM)
|
||||
#include <cpuid.h>
|
||||
namespace sha256_sse4
|
||||
{
|
||||
void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace sha256d64_sse41
|
||||
{
|
||||
void Transform_4way(unsigned char* out, const unsigned char* in);
|
||||
}
|
||||
|
||||
namespace sha256d64_avx2
|
||||
{
|
||||
void Transform_8way(unsigned char* out, const unsigned char* in);
|
||||
}
|
||||
|
||||
namespace sha256d64_shani
|
||||
{
|
||||
void Transform_2way(unsigned char* out, const unsigned char* in);
|
||||
}
|
||||
|
||||
namespace sha256_shani
|
||||
{
|
||||
void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);
|
||||
}
|
||||
|
||||
// Internal implementation code.
|
||||
namespace
|
||||
{
|
||||
/// Internal SHA-256 implementation.
|
||||
namespace sha256
|
||||
{
|
||||
uint32_t inline Ch(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); }
|
||||
uint32_t inline Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (z & (x | y)); }
|
||||
uint32_t inline Sigma0(uint32_t x) { return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10); }
|
||||
uint32_t inline Sigma1(uint32_t x) { return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7); }
|
||||
uint32_t inline sigma0(uint32_t x) { return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3); }
|
||||
uint32_t inline sigma1(uint32_t x) { return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10); }
|
||||
|
||||
/** One round of SHA-256. */
|
||||
void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t& d, uint32_t e, uint32_t f, uint32_t g, uint32_t& h, uint32_t k)
|
||||
{
|
||||
uint32_t t1 = h + Sigma1(e) + Ch(e, f, g) + k;
|
||||
uint32_t t2 = Sigma0(a) + Maj(a, b, c);
|
||||
d += t1;
|
||||
h = t1 + t2;
|
||||
}
|
||||
|
||||
/** Initialize SHA-256 state. */
|
||||
void inline Initialize(uint32_t* s)
|
||||
{
|
||||
s[0] = 0x6a09e667ul;
|
||||
s[1] = 0xbb67ae85ul;
|
||||
s[2] = 0x3c6ef372ul;
|
||||
s[3] = 0xa54ff53aul;
|
||||
s[4] = 0x510e527ful;
|
||||
s[5] = 0x9b05688cul;
|
||||
s[6] = 0x1f83d9abul;
|
||||
s[7] = 0x5be0cd19ul;
|
||||
}
|
||||
|
||||
/** Perform a number of SHA-256 transformations, processing 64-byte chunks. */
|
||||
void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
|
||||
{
|
||||
while (blocks--) {
|
||||
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98 + (w0 = ReadBE32(chunk + 0)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x71374491 + (w1 = ReadBE32(chunk + 4)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf + (w2 = ReadBE32(chunk + 8)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5 + (w3 = ReadBE32(chunk + 12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25b + (w4 = ReadBE32(chunk + 16)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1 + (w5 = ReadBE32(chunk + 20)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4 + (w6 = ReadBE32(chunk + 24)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5 + (w7 = ReadBE32(chunk + 28)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98 + (w8 = ReadBE32(chunk + 32)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b01 + (w9 = ReadBE32(chunk + 36)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185be + (w10 = ReadBE32(chunk + 40)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3 + (w11 = ReadBE32(chunk + 44)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74 + (w12 = ReadBE32(chunk + 48)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1fe + (w13 = ReadBE32(chunk + 52)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7 + (w14 = ReadBE32(chunk + 56)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf174 + (w15 = ReadBE32(chunk + 60)));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c1 + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786 + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fc19dc6 + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x240ca1cc + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x2de92c6f + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4a7484aa + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x76f988da + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x983e5152 + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa831c66d + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb00327c8 + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xbf597fc7 + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0xc6e00bf3 + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd5a79147 + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x06ca6351 + (w14 += sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x14292967 + (w15 += sigma1(w13) + w8 + sigma0(w0)));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x27b70a85 + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x2e1b2138 + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x53380d13 + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x650a7354 + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x766a0abb + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x81c2c92e + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x92722c85 + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1 + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa81a664b + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xc24b8b70 + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xc76c51a3 + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0xd192e819 + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd6990624 + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xf40e3585 + (w14 += sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x106aa070 + (w15 += sigma1(w13) + w8 + sigma0(w0)));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x19a4c116 + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x1e376c08 + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x2748774c + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5 + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x391c0cb3 + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5b9cca4f + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x682e6ff3 + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x748f82ee + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x78a5636f + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x84c87814 + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x8cc70208 + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x90befffa + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xa4506ceb + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7 + (w14 + sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc67178f2 + (w15 + sigma1(w13) + w8 + sigma0(w0)));
|
||||
|
||||
s[0] += a;
|
||||
s[1] += b;
|
||||
s[2] += c;
|
||||
s[3] += d;
|
||||
s[4] += e;
|
||||
s[5] += f;
|
||||
s[6] += g;
|
||||
s[7] += h;
|
||||
chunk += 64;
|
||||
}
|
||||
}
|
||||
|
||||
void TransformD64(unsigned char* out, const unsigned char* in)
|
||||
{
|
||||
// Transform 1
|
||||
uint32_t a = 0x6a09e667ul;
|
||||
uint32_t b = 0xbb67ae85ul;
|
||||
uint32_t c = 0x3c6ef372ul;
|
||||
uint32_t d = 0xa54ff53aul;
|
||||
uint32_t e = 0x510e527ful;
|
||||
uint32_t f = 0x9b05688cul;
|
||||
uint32_t g = 0x1f83d9abul;
|
||||
uint32_t h = 0x5be0cd19ul;
|
||||
|
||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98ul + (w0 = ReadBE32(in + 0)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x71374491ul + (w1 = ReadBE32(in + 4)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcful + (w2 = ReadBE32(in + 8)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5ul + (w3 = ReadBE32(in + 12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25bul + (w4 = ReadBE32(in + 16)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1ul + (w5 = ReadBE32(in + 20)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4ul + (w6 = ReadBE32(in + 24)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5ul + (w7 = ReadBE32(in + 28)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98ul + (w8 = ReadBE32(in + 32)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b01ul + (w9 = ReadBE32(in + 36)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185beul + (w10 = ReadBE32(in + 40)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3ul + (w11 = ReadBE32(in + 44)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74ul + (w12 = ReadBE32(in + 48)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1feul + (w13 = ReadBE32(in + 52)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7ul + (w14 = ReadBE32(in + 56)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf174ul + (w15 = ReadBE32(in + 60)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c1ul + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786ul + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fc19dc6ul + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x240ca1ccul + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x2de92c6ful + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4a7484aaul + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcul + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x76f988daul + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x983e5152ul + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa831c66dul + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb00327c8ul + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xbf597fc7ul + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0xc6e00bf3ul + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd5a79147ul + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x06ca6351ul + (w14 += sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x14292967ul + (w15 += sigma1(w13) + w8 + sigma0(w0)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x27b70a85ul + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x2e1b2138ul + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfcul + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x53380d13ul + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x650a7354ul + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x766a0abbul + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x81c2c92eul + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x92722c85ul + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1ul + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa81a664bul + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xc24b8b70ul + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xc76c51a3ul + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0xd192e819ul + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd6990624ul + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xf40e3585ul + (w14 += sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x106aa070ul + (w15 += sigma1(w13) + w8 + sigma0(w0)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x19a4c116ul + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x1e376c08ul + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x2748774cul + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5ul + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x391c0cb3ul + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4aul + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5b9cca4ful + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x682e6ff3ul + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x748f82eeul + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x78a5636ful + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x84c87814ul + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x8cc70208ul + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x90befffaul + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xa4506cebul + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7ul + (w14 + sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc67178f2ul + (w15 + sigma1(w13) + w8 + sigma0(w0)));
|
||||
|
||||
a += 0x6a09e667ul;
|
||||
b += 0xbb67ae85ul;
|
||||
c += 0x3c6ef372ul;
|
||||
d += 0xa54ff53aul;
|
||||
e += 0x510e527ful;
|
||||
f += 0x9b05688cul;
|
||||
g += 0x1f83d9abul;
|
||||
h += 0x5be0cd19ul;
|
||||
|
||||
uint32_t t0 = a, t1 = b, t2 = c, t3 = d, t4 = e, t5 = f, t6 = g, t7 = h;
|
||||
|
||||
// Transform 2
|
||||
Round(a, b, c, d, e, f, g, h, 0xc28a2f98ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0x71374491ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcful);
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25bul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4ul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b01ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185beul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1feul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7ul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf374ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0x649b69c1ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0xf0fe4786ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fe1edc6ul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x240cf254ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x4fe9346ful);
|
||||
Round(d, e, f, g, h, a, b, c, 0x6cc984beul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x61b9411eul);
|
||||
Round(b, c, d, e, f, g, h, a, 0x16f988faul);
|
||||
Round(a, b, c, d, e, f, g, h, 0xf2c65152ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0xa88e5a6dul);
|
||||
Round(g, h, a, b, c, d, e, f, 0xb019fc65ul);
|
||||
Round(f, g, h, a, b, c, d, e, 0xb9d99ec7ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x9a1231c3ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0xe70eeaa0ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0xfdb1232bul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xc7353eb0ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0x3069bad5ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0xcb976d5ful);
|
||||
Round(g, h, a, b, c, d, e, f, 0x5a0f118ful);
|
||||
Round(f, g, h, a, b, c, d, e, 0xdc1eeefdul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x0a35b689ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0xde0b7a04ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x58f4ca9dul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xe15d5b16ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0x007f3e86ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0x37088980ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0xa507ea32ul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x6fab9537ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x17406110ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x0d8cd6f1ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0xcdaa3b6dul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xc0bbbe37ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0x83613bdaul);
|
||||
Round(h, a, b, c, d, e, f, g, 0xdb48a363ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0x0b02e931ul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x6fd15ca7ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x521afacaul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x31338431ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x6ed41a95ul);
|
||||
Round(b, c, d, e, f, g, h, a, 0x6d437890ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0xc39c91f2ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0x9eccabbdul);
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c9a0e6ul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x532fb63cul);
|
||||
Round(e, f, g, h, a, b, c, d, 0xd2c741c6ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x07237ea3ul);
|
||||
Round(c, d, e, f, g, h, a, b, 0xa4954b68ul);
|
||||
Round(b, c, d, e, f, g, h, a, 0x4c191d76ul);
|
||||
|
||||
w0 = t0 + a;
|
||||
w1 = t1 + b;
|
||||
w2 = t2 + c;
|
||||
w3 = t3 + d;
|
||||
w4 = t4 + e;
|
||||
w5 = t5 + f;
|
||||
w6 = t6 + g;
|
||||
w7 = t7 + h;
|
||||
|
||||
// Transform 3
|
||||
a = 0x6a09e667ul;
|
||||
b = 0xbb67ae85ul;
|
||||
c = 0x3c6ef372ul;
|
||||
d = 0xa54ff53aul;
|
||||
e = 0x510e527ful;
|
||||
f = 0x9b05688cul;
|
||||
g = 0x1f83d9abul;
|
||||
h = 0x5be0cd19ul;
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98ul + w0);
|
||||
Round(h, a, b, c, d, e, f, g, 0x71374491ul + w1);
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcful + w2);
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5ul + w3);
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25bul + w4);
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1ul + w5);
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4ul + w6);
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5ul + w7);
|
||||
Round(a, b, c, d, e, f, g, h, 0x5807aa98ul);
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b01ul);
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185beul);
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3ul);
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74ul);
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1feul);
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7ul);
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf274ul);
|
||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c1ul + (w0 += sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786ul + (w1 += 0xa00000ul + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fc19dc6ul + (w2 += sigma1(w0) + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x240ca1ccul + (w3 += sigma1(w1) + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x2de92c6ful + (w4 += sigma1(w2) + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4a7484aaul + (w5 += sigma1(w3) + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcul + (w6 += sigma1(w4) + 0x100ul + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x76f988daul + (w7 += sigma1(w5) + w0 + 0x11002000ul));
|
||||
Round(a, b, c, d, e, f, g, h, 0x983e5152ul + (w8 = 0x80000000ul + sigma1(w6) + w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa831c66dul + (w9 = sigma1(w7) + w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb00327c8ul + (w10 = sigma1(w8) + w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0xbf597fc7ul + (w11 = sigma1(w9) + w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0xc6e00bf3ul + (w12 = sigma1(w10) + w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd5a79147ul + (w13 = sigma1(w11) + w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x06ca6351ul + (w14 = sigma1(w12) + w7 + 0x400022ul));
|
||||
Round(b, c, d, e, f, g, h, a, 0x14292967ul + (w15 = 0x100ul + sigma1(w13) + w8 + sigma0(w0)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x27b70a85ul + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x2e1b2138ul + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfcul + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x53380d13ul + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x650a7354ul + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x766a0abbul + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x81c2c92eul + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x92722c85ul + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1ul + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa81a664bul + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0xc24b8b70ul + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0xc76c51a3ul + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0xd192e819ul + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd6990624ul + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xf40e3585ul + (w14 += sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x106aa070ul + (w15 += sigma1(w13) + w8 + sigma0(w0)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x19a4c116ul + (w0 += sigma1(w14) + w9 + sigma0(w1)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x1e376c08ul + (w1 += sigma1(w15) + w10 + sigma0(w2)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x2748774cul + (w2 += sigma1(w0) + w11 + sigma0(w3)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5ul + (w3 += sigma1(w1) + w12 + sigma0(w4)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x391c0cb3ul + (w4 += sigma1(w2) + w13 + sigma0(w5)));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4aul + (w5 += sigma1(w3) + w14 + sigma0(w6)));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5b9cca4ful + (w6 += sigma1(w4) + w15 + sigma0(w7)));
|
||||
Round(b, c, d, e, f, g, h, a, 0x682e6ff3ul + (w7 += sigma1(w5) + w0 + sigma0(w8)));
|
||||
Round(a, b, c, d, e, f, g, h, 0x748f82eeul + (w8 += sigma1(w6) + w1 + sigma0(w9)));
|
||||
Round(h, a, b, c, d, e, f, g, 0x78a5636ful + (w9 += sigma1(w7) + w2 + sigma0(w10)));
|
||||
Round(g, h, a, b, c, d, e, f, 0x84c87814ul + (w10 += sigma1(w8) + w3 + sigma0(w11)));
|
||||
Round(f, g, h, a, b, c, d, e, 0x8cc70208ul + (w11 += sigma1(w9) + w4 + sigma0(w12)));
|
||||
Round(e, f, g, h, a, b, c, d, 0x90befffaul + (w12 += sigma1(w10) + w5 + sigma0(w13)));
|
||||
Round(d, e, f, g, h, a, b, c, 0xa4506cebul + (w13 += sigma1(w11) + w6 + sigma0(w14)));
|
||||
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7ul + (w14 + sigma1(w12) + w7 + sigma0(w15)));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc67178f2ul + (w15 + sigma1(w13) + w8 + sigma0(w0)));
|
||||
|
||||
// Output
|
||||
WriteBE32(out + 0, a + 0x6a09e667ul);
|
||||
WriteBE32(out + 4, b + 0xbb67ae85ul);
|
||||
WriteBE32(out + 8, c + 0x3c6ef372ul);
|
||||
WriteBE32(out + 12, d + 0xa54ff53aul);
|
||||
WriteBE32(out + 16, e + 0x510e527ful);
|
||||
WriteBE32(out + 20, f + 0x9b05688cul);
|
||||
WriteBE32(out + 24, g + 0x1f83d9abul);
|
||||
WriteBE32(out + 28, h + 0x5be0cd19ul);
|
||||
}
|
||||
|
||||
} // namespace sha256
|
||||
|
||||
typedef void (*TransformType)(uint32_t*, const unsigned char*, size_t);
|
||||
typedef void (*TransformD64Type)(unsigned char*, const unsigned char*);
|
||||
|
||||
template<TransformType tr>
|
||||
void TransformD64Wrapper(unsigned char* out, const unsigned char* in)
|
||||
{
|
||||
uint32_t s[8];
|
||||
static const unsigned char padding1[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0
|
||||
};
|
||||
unsigned char buffer2[64] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0
|
||||
};
|
||||
sha256::Initialize(s);
|
||||
tr(s, in, 1);
|
||||
tr(s, padding1, 1);
|
||||
WriteBE32(buffer2 + 0, s[0]);
|
||||
WriteBE32(buffer2 + 4, s[1]);
|
||||
WriteBE32(buffer2 + 8, s[2]);
|
||||
WriteBE32(buffer2 + 12, s[3]);
|
||||
WriteBE32(buffer2 + 16, s[4]);
|
||||
WriteBE32(buffer2 + 20, s[5]);
|
||||
WriteBE32(buffer2 + 24, s[6]);
|
||||
WriteBE32(buffer2 + 28, s[7]);
|
||||
sha256::Initialize(s);
|
||||
tr(s, buffer2, 1);
|
||||
WriteBE32(out + 0, s[0]);
|
||||
WriteBE32(out + 4, s[1]);
|
||||
WriteBE32(out + 8, s[2]);
|
||||
WriteBE32(out + 12, s[3]);
|
||||
WriteBE32(out + 16, s[4]);
|
||||
WriteBE32(out + 20, s[5]);
|
||||
WriteBE32(out + 24, s[6]);
|
||||
WriteBE32(out + 28, s[7]);
|
||||
}
|
||||
|
||||
TransformType Transform = sha256::Transform;
|
||||
TransformD64Type TransformD64 = sha256::TransformD64;
|
||||
TransformD64Type TransformD64_2way = nullptr;
|
||||
TransformD64Type TransformD64_4way = nullptr;
|
||||
TransformD64Type TransformD64_8way = nullptr;
|
||||
|
||||
bool SelfTest() {
|
||||
// Input state (equal to the initial SHA256 state)
|
||||
static const uint32_t init[8] = {
|
||||
0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul
|
||||
};
|
||||
// Some random input data to test with
|
||||
static const unsigned char data[641] = "-" // Intentionally not aligned
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
|
||||
"eiusmod tempor incididunt ut labore et dolore magna aliqua. Et m"
|
||||
"olestie ac feugiat sed lectus vestibulum mattis ullamcorper. Mor"
|
||||
"bi blandit cursus risus at ultrices mi tempus imperdiet nulla. N"
|
||||
"unc congue nisi vita suscipit tellus mauris. Imperdiet proin fer"
|
||||
"mentum leo vel orci. Massa tempor nec feugiat nisl pretium fusce"
|
||||
" id velit. Telus in metus vulputate eu scelerisque felis. Mi tem"
|
||||
"pus imperdiet nulla malesuada pellentesque. Tristique magna sit.";
|
||||
// Expected output state for hashing the i*64 first input bytes above (excluding SHA256 padding).
|
||||
static const uint32_t result[9][8] = {
|
||||
{0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul},
|
||||
{0x91f8ec6bul, 0x4da10fe3ul, 0x1c9c292cul, 0x45e18185ul, 0x435cc111ul, 0x3ca26f09ul, 0xeb954caeul, 0x402a7069ul},
|
||||
{0xcabea5acul, 0x374fb97cul, 0x182ad996ul, 0x7bd69cbful, 0x450ff900ul, 0xc1d2be8aul, 0x6a41d505ul, 0xe6212dc3ul},
|
||||
{0xbcff09d6ul, 0x3e76f36eul, 0x3ecb2501ul, 0x78866e97ul, 0xe1c1e2fdul, 0x32f4eafful, 0x8aa6c4e5ul, 0xdfc024bcul},
|
||||
{0xa08c5d94ul, 0x0a862f93ul, 0x6b7f2f40ul, 0x8f9fae76ul, 0x6d40439ful, 0x79dcee0cul, 0x3e39ff3aul, 0xdc3bdbb1ul},
|
||||
{0x216a0895ul, 0x9f1a3662ul, 0xe99946f9ul, 0x87ba4364ul, 0x0fb5db2cul, 0x12bed3d3ul, 0x6689c0c7ul, 0x292f1b04ul},
|
||||
{0xca3067f8ul, 0xbc8c2656ul, 0x37cb7e0dul, 0x9b6b8b0ful, 0x46dc380bul, 0xf1287f57ul, 0xc42e4b23ul, 0x3fefe94dul},
|
||||
{0x3e4c4039ul, 0xbb6fca8cul, 0x6f27d2f7ul, 0x301e44a4ul, 0x8352ba14ul, 0x5769ce37ul, 0x48a1155ful, 0xc0e1c4c6ul},
|
||||
{0xfe2fa9ddul, 0x69d0862bul, 0x1ae0db23ul, 0x471f9244ul, 0xf55c0145ul, 0xc30f9c3bul, 0x40a84ea0ul, 0x5b8a266cul},
|
||||
};
|
||||
// Expected output for each of the individual 8 64-byte messages under full double SHA256 (including padding).
|
||||
static const unsigned char result_d64[256] = {
|
||||
0x09, 0x3a, 0xc4, 0xd0, 0x0f, 0xf7, 0x57, 0xe1, 0x72, 0x85, 0x79, 0x42, 0xfe, 0xe7, 0xe0, 0xa0,
|
||||
0xfc, 0x52, 0xd7, 0xdb, 0x07, 0x63, 0x45, 0xfb, 0x53, 0x14, 0x7d, 0x17, 0x22, 0x86, 0xf0, 0x52,
|
||||
0x48, 0xb6, 0x11, 0x9e, 0x6e, 0x48, 0x81, 0x6d, 0xcc, 0x57, 0x1f, 0xb2, 0x97, 0xa8, 0xd5, 0x25,
|
||||
0x9b, 0x82, 0xaa, 0x89, 0xe2, 0xfd, 0x2d, 0x56, 0xe8, 0x28, 0x83, 0x0b, 0xe2, 0xfa, 0x53, 0xb7,
|
||||
0xd6, 0x6b, 0x07, 0x85, 0x83, 0xb0, 0x10, 0xa2, 0xf5, 0x51, 0x3c, 0xf9, 0x60, 0x03, 0xab, 0x45,
|
||||
0x6c, 0x15, 0x6e, 0xef, 0xb5, 0xac, 0x3e, 0x6c, 0xdf, 0xb4, 0x92, 0x22, 0x2d, 0xce, 0xbf, 0x3e,
|
||||
0xe9, 0xe5, 0xf6, 0x29, 0x0e, 0x01, 0x4f, 0xd2, 0xd4, 0x45, 0x65, 0xb3, 0xbb, 0xf2, 0x4c, 0x16,
|
||||
0x37, 0x50, 0x3c, 0x6e, 0x49, 0x8c, 0x5a, 0x89, 0x2b, 0x1b, 0xab, 0xc4, 0x37, 0xd1, 0x46, 0xe9,
|
||||
0x3d, 0x0e, 0x85, 0xa2, 0x50, 0x73, 0xa1, 0x5e, 0x54, 0x37, 0xd7, 0x94, 0x17, 0x56, 0xc2, 0xd8,
|
||||
0xe5, 0x9f, 0xed, 0x4e, 0xae, 0x15, 0x42, 0x06, 0x0d, 0x74, 0x74, 0x5e, 0x24, 0x30, 0xce, 0xd1,
|
||||
0x9e, 0x50, 0xa3, 0x9a, 0xb8, 0xf0, 0x4a, 0x57, 0x69, 0x78, 0x67, 0x12, 0x84, 0x58, 0xbe, 0xc7,
|
||||
0x36, 0xaa, 0xee, 0x7c, 0x64, 0xa3, 0x76, 0xec, 0xff, 0x55, 0x41, 0x00, 0x2a, 0x44, 0x68, 0x4d,
|
||||
0xb6, 0x53, 0x9e, 0x1c, 0x95, 0xb7, 0xca, 0xdc, 0x7f, 0x7d, 0x74, 0x27, 0x5c, 0x8e, 0xa6, 0x84,
|
||||
0xb5, 0xac, 0x87, 0xa9, 0xf3, 0xff, 0x75, 0xf2, 0x34, 0xcd, 0x1a, 0x3b, 0x82, 0x2c, 0x2b, 0x4e,
|
||||
0x6a, 0x46, 0x30, 0xa6, 0x89, 0x86, 0x23, 0xac, 0xf8, 0xa5, 0x15, 0xe9, 0x0a, 0xaa, 0x1e, 0x9a,
|
||||
0xd7, 0x93, 0x6b, 0x28, 0xe4, 0x3b, 0xfd, 0x59, 0xc6, 0xed, 0x7c, 0x5f, 0xa5, 0x41, 0xcb, 0x51
|
||||
};
|
||||
|
||||
|
||||
// Test Transform() for 0 through 8 transformations.
|
||||
for (size_t i = 0; i <= 8; ++i) {
|
||||
uint32_t state[8];
|
||||
std::copy(init, init + 8, state);
|
||||
Transform(state, data + 1, i);
|
||||
if (!std::equal(state, state + 8, result[i])) return false;
|
||||
}
|
||||
|
||||
// Test TransformD64
|
||||
unsigned char out[32];
|
||||
TransformD64(out, data + 1);
|
||||
if (!std::equal(out, out + 32, result_d64)) return false;
|
||||
|
||||
// Test TransformD64_2way, if available.
|
||||
if (TransformD64_2way) {
|
||||
unsigned char out[64];
|
||||
TransformD64_2way(out, data + 1);
|
||||
if (!std::equal(out, out + 64, result_d64)) return false;
|
||||
}
|
||||
|
||||
// Test TransformD64_4way, if available.
|
||||
if (TransformD64_4way) {
|
||||
unsigned char out[128];
|
||||
TransformD64_4way(out, data + 1);
|
||||
if (!std::equal(out, out + 128, result_d64)) return false;
|
||||
}
|
||||
|
||||
// Test TransformD64_8way, if available.
|
||||
if (TransformD64_8way) {
|
||||
unsigned char out[256];
|
||||
TransformD64_8way(out, data + 1);
|
||||
if (!std::equal(out, out + 256, result_d64)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__) || defined(__i386__))
|
||||
// We can't use cpuid.h's __get_cpuid as it does not support subleafs.
|
||||
void inline cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__cpuid_count(leaf, subleaf, a, b, c, d);
|
||||
#else
|
||||
__asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Check whether the OS has enabled AVX registers. */
|
||||
bool AVXEnabled()
|
||||
{
|
||||
uint32_t a, d;
|
||||
__asm__("xgetbv" : "=a"(a), "=d"(d) : "c"(0));
|
||||
return (a & 6) == 6;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
|
||||
std::string SHA256AutoDetect()
|
||||
{
|
||||
std::string ret = "standard";
|
||||
#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__) || defined(__i386__))
|
||||
bool have_sse4 = false;
|
||||
bool have_xsave = false;
|
||||
bool have_avx = false;
|
||||
bool have_avx2 = false;
|
||||
bool have_shani = false;
|
||||
bool enabled_avx = false;
|
||||
|
||||
(void)AVXEnabled;
|
||||
(void)have_sse4;
|
||||
(void)have_avx;
|
||||
(void)have_xsave;
|
||||
(void)have_avx2;
|
||||
(void)have_shani;
|
||||
(void)enabled_avx;
|
||||
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
cpuid(1, 0, eax, ebx, ecx, edx);
|
||||
have_sse4 = (ecx >> 19) & 1;
|
||||
have_xsave = (ecx >> 27) & 1;
|
||||
have_avx = (ecx >> 28) & 1;
|
||||
if (have_xsave && have_avx) {
|
||||
enabled_avx = AVXEnabled();
|
||||
}
|
||||
if (have_sse4) {
|
||||
cpuid(7, 0, eax, ebx, ecx, edx);
|
||||
have_avx2 = (ebx >> 5) & 1;
|
||||
have_shani = (ebx >> 29) & 1;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
|
||||
if (have_shani) {
|
||||
Transform = sha256_shani::Transform;
|
||||
TransformD64 = TransformD64Wrapper<sha256_shani::Transform>;
|
||||
TransformD64_2way = sha256d64_shani::Transform_2way;
|
||||
ret = "shani(1way,2way)";
|
||||
have_sse4 = false; // Disable SSE4/AVX2;
|
||||
have_avx2 = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (have_sse4) {
|
||||
#if defined(__x86_64__) || defined(__amd64__)
|
||||
Transform = sha256_sse4::Transform;
|
||||
TransformD64 = TransformD64Wrapper<sha256_sse4::Transform>;
|
||||
ret = "sse4(1way)";
|
||||
#endif
|
||||
#if defined(ENABLE_SSE41) && !defined(BUILD_BITCOIN_INTERNAL)
|
||||
TransformD64_4way = sha256d64_sse41::Transform_4way;
|
||||
ret += ",sse41(4way)";
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ENABLE_AVX2) && !defined(BUILD_BITCOIN_INTERNAL)
|
||||
if (have_avx2 && have_avx && enabled_avx) {
|
||||
TransformD64_8way = sha256d64_avx2::Transform_8way;
|
||||
ret += ",avx2(8way)";
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
assert(SelfTest());
|
||||
return ret;
|
||||
}
|
||||
|
||||
////// SHA-256
|
||||
|
||||
CSHA256::CSHA256() : bytes(0)
|
||||
{
|
||||
sha256::Initialize(s);
|
||||
}
|
||||
|
||||
CSHA256& CSHA256::Write(const unsigned char* data, size_t len)
|
||||
{
|
||||
const unsigned char* end = data + len;
|
||||
size_t bufsize = bytes % 64;
|
||||
if (bufsize && bufsize + len >= 64) {
|
||||
// Fill the buffer, and process it.
|
||||
memcpy(buf + bufsize, data, 64 - bufsize);
|
||||
bytes += 64 - bufsize;
|
||||
data += 64 - bufsize;
|
||||
Transform(s, buf, 1);
|
||||
bufsize = 0;
|
||||
}
|
||||
if (end - data >= 64) {
|
||||
size_t blocks = (end - data) / 64;
|
||||
Transform(s, data, blocks);
|
||||
data += 64 * blocks;
|
||||
bytes += 64 * blocks;
|
||||
}
|
||||
if (end > data) {
|
||||
// Fill the buffer with what remains.
|
||||
memcpy(buf + bufsize, data, end - data);
|
||||
bytes += end - data;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE])
|
||||
{
|
||||
static const unsigned char pad[64] = {0x80};
|
||||
unsigned char sizedesc[8];
|
||||
WriteBE64(sizedesc, bytes << 3);
|
||||
Write(pad, 1 + ((119 - (bytes % 64)) % 64));
|
||||
Write(sizedesc, 8);
|
||||
WriteBE32(hash, s[0]);
|
||||
WriteBE32(hash + 4, s[1]);
|
||||
WriteBE32(hash + 8, s[2]);
|
||||
WriteBE32(hash + 12, s[3]);
|
||||
WriteBE32(hash + 16, s[4]);
|
||||
WriteBE32(hash + 20, s[5]);
|
||||
WriteBE32(hash + 24, s[6]);
|
||||
WriteBE32(hash + 28, s[7]);
|
||||
}
|
||||
|
||||
CSHA256& CSHA256::Reset()
|
||||
{
|
||||
bytes = 0;
|
||||
sha256::Initialize(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void SHA256D64(unsigned char* out, const unsigned char* in, size_t blocks)
|
||||
{
|
||||
if (TransformD64_8way) {
|
||||
while (blocks >= 8) {
|
||||
TransformD64_8way(out, in);
|
||||
out += 256;
|
||||
in += 512;
|
||||
blocks -= 8;
|
||||
}
|
||||
}
|
||||
if (TransformD64_4way) {
|
||||
while (blocks >= 4) {
|
||||
TransformD64_4way(out, in);
|
||||
out += 128;
|
||||
in += 256;
|
||||
blocks -= 4;
|
||||
}
|
||||
}
|
||||
if (TransformD64_2way) {
|
||||
while (blocks >= 2) {
|
||||
TransformD64_2way(out, in);
|
||||
out += 64;
|
||||
in += 128;
|
||||
blocks -= 2;
|
||||
}
|
||||
}
|
||||
while (blocks) {
|
||||
TransformD64(out, in);
|
||||
out += 32;
|
||||
in += 64;
|
||||
--blocks;
|
||||
}
|
||||
}
|
41
lib/bip158/src/crypto/sha256.h
Normal file
41
lib/bip158/src/crypto/sha256.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_SHA256_H
|
||||
#define BITCOIN_CRYPTO_SHA256_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
/** A hasher class for SHA-256. */
|
||||
class CSHA256
|
||||
{
|
||||
private:
|
||||
uint32_t s[8];
|
||||
unsigned char buf[64];
|
||||
uint64_t bytes;
|
||||
|
||||
public:
|
||||
static const size_t OUTPUT_SIZE = 32;
|
||||
|
||||
CSHA256();
|
||||
CSHA256& Write(const unsigned char* data, size_t len);
|
||||
void Finalize(unsigned char hash[OUTPUT_SIZE]);
|
||||
CSHA256& Reset();
|
||||
};
|
||||
|
||||
/** Autodetect the best available SHA256 implementation.
|
||||
* Returns the name of the implementation.
|
||||
*/
|
||||
std::string SHA256AutoDetect();
|
||||
|
||||
/** Compute multiple double-SHA256's of 64-byte blobs.
|
||||
* output: pointer to a blocks*32 byte output buffer
|
||||
* input: pointer to a blocks*64 byte input buffer
|
||||
* blocks: the number of hashes to compute.
|
||||
*/
|
||||
void SHA256D64(unsigned char* output, const unsigned char* input, size_t blocks);
|
||||
|
||||
#endif // BITCOIN_CRYPTO_SHA256_H
|
207
lib/bip158/src/crypto/sha512.cpp
Normal file
207
lib/bip158/src/crypto/sha512.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2014-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/sha512.h>
|
||||
|
||||
#include <crypto/common.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Internal implementation code.
|
||||
namespace
|
||||
{
|
||||
/// Internal SHA-512 implementation.
|
||||
namespace sha512
|
||||
{
|
||||
uint64_t inline Ch(uint64_t x, uint64_t y, uint64_t z) { return z ^ (x & (y ^ z)); }
|
||||
uint64_t inline Maj(uint64_t x, uint64_t y, uint64_t z) { return (x & y) | (z & (x | y)); }
|
||||
uint64_t inline Sigma0(uint64_t x) { return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); }
|
||||
uint64_t inline Sigma1(uint64_t x) { return (x >> 14 | x << 50) ^ (x >> 18 | x << 46) ^ (x >> 41 | x << 23); }
|
||||
uint64_t inline sigma0(uint64_t x) { return (x >> 1 | x << 63) ^ (x >> 8 | x << 56) ^ (x >> 7); }
|
||||
uint64_t inline sigma1(uint64_t x) { return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); }
|
||||
|
||||
/** One round of SHA-512. */
|
||||
void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, uint64_t f, uint64_t g, uint64_t& h, uint64_t k, uint64_t w)
|
||||
{
|
||||
uint64_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w;
|
||||
uint64_t t2 = Sigma0(a) + Maj(a, b, c);
|
||||
d += t1;
|
||||
h = t1 + t2;
|
||||
}
|
||||
|
||||
/** Initialize SHA-256 state. */
|
||||
void inline Initialize(uint64_t* s)
|
||||
{
|
||||
s[0] = 0x6a09e667f3bcc908ull;
|
||||
s[1] = 0xbb67ae8584caa73bull;
|
||||
s[2] = 0x3c6ef372fe94f82bull;
|
||||
s[3] = 0xa54ff53a5f1d36f1ull;
|
||||
s[4] = 0x510e527fade682d1ull;
|
||||
s[5] = 0x9b05688c2b3e6c1full;
|
||||
s[6] = 0x1f83d9abfb41bd6bull;
|
||||
s[7] = 0x5be0cd19137e2179ull;
|
||||
}
|
||||
|
||||
/** Perform one SHA-512 transformation, processing a 128-byte chunk. */
|
||||
void Transform(uint64_t* s, const unsigned char* chunk)
|
||||
{
|
||||
uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
||||
uint64_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22ull, w0 = ReadBE64(chunk + 0));
|
||||
Round(h, a, b, c, d, e, f, g, 0x7137449123ef65cdull, w1 = ReadBE64(chunk + 8));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2full, w2 = ReadBE64(chunk + 16));
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbcull, w3 = ReadBE64(chunk + 24));
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25bf348b538ull, w4 = ReadBE64(chunk + 32));
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1b605d019ull, w5 = ReadBE64(chunk + 40));
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4af194f9bull, w6 = ReadBE64(chunk + 48));
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118ull, w7 = ReadBE64(chunk + 56));
|
||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98a3030242ull, w8 = ReadBE64(chunk + 64));
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b0145706fbeull, w9 = ReadBE64(chunk + 72));
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185be4ee4b28cull, w10 = ReadBE64(chunk + 80));
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2ull, w11 = ReadBE64(chunk + 88));
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74f27b896full, w12 = ReadBE64(chunk + 96));
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1ull, w13 = ReadBE64(chunk + 104));
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235ull, w14 = ReadBE64(chunk + 112));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf174cf692694ull, w15 = ReadBE64(chunk + 120));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65ull, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275ull, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483ull, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x76f988da831153b5ull, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0x983e5152ee66dfabull, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa831c66d2db43210ull, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb00327c898fb213full, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4ull, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aedull, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x53380d139d95b3dfull, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x650a73548baf63deull, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8ull, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6ull, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x92722c851482353bull, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364ull, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa81a664bbc423001ull, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791ull, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0xc76c51a30654be30ull, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99ull, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8ull, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63ull, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acbull, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373ull, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fcull, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0x78a5636f43172f60ull, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72ull, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0x8cc702081a6439ecull, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1eull, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178ull, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x06f067aa72176fbaull, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6ull, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x113f9804bef90daeull, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x1b710b35131c471bull, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0x28db77f523047d84ull, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0x32caab7b40c72493ull, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebcull, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0x431d67c49c100d4cull, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faecull, w14 + sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0x6c44198c4a475817ull, w15 + sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
s[0] += a;
|
||||
s[1] += b;
|
||||
s[2] += c;
|
||||
s[3] += d;
|
||||
s[4] += e;
|
||||
s[5] += f;
|
||||
s[6] += g;
|
||||
s[7] += h;
|
||||
}
|
||||
|
||||
} // namespace sha512
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
////// SHA-512
|
||||
|
||||
CSHA512::CSHA512() : bytes(0)
|
||||
{
|
||||
sha512::Initialize(s);
|
||||
}
|
||||
|
||||
CSHA512& CSHA512::Write(const unsigned char* data, size_t len)
|
||||
{
|
||||
const unsigned char* end = data + len;
|
||||
size_t bufsize = bytes % 128;
|
||||
if (bufsize && bufsize + len >= 128) {
|
||||
// Fill the buffer, and process it.
|
||||
memcpy(buf + bufsize, data, 128 - bufsize);
|
||||
bytes += 128 - bufsize;
|
||||
data += 128 - bufsize;
|
||||
sha512::Transform(s, buf);
|
||||
bufsize = 0;
|
||||
}
|
||||
while (end - data >= 128) {
|
||||
// Process full chunks directly from the source.
|
||||
sha512::Transform(s, data);
|
||||
data += 128;
|
||||
bytes += 128;
|
||||
}
|
||||
if (end > data) {
|
||||
// Fill the buffer with what remains.
|
||||
memcpy(buf + bufsize, data, end - data);
|
||||
bytes += end - data;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CSHA512::Finalize(unsigned char hash[OUTPUT_SIZE])
|
||||
{
|
||||
static const unsigned char pad[128] = {0x80};
|
||||
unsigned char sizedesc[16] = {0x00};
|
||||
WriteBE64(sizedesc + 8, bytes << 3);
|
||||
Write(pad, 1 + ((239 - (bytes % 128)) % 128));
|
||||
Write(sizedesc, 16);
|
||||
WriteBE64(hash, s[0]);
|
||||
WriteBE64(hash + 8, s[1]);
|
||||
WriteBE64(hash + 16, s[2]);
|
||||
WriteBE64(hash + 24, s[3]);
|
||||
WriteBE64(hash + 32, s[4]);
|
||||
WriteBE64(hash + 40, s[5]);
|
||||
WriteBE64(hash + 48, s[6]);
|
||||
WriteBE64(hash + 56, s[7]);
|
||||
}
|
||||
|
||||
CSHA512& CSHA512::Reset()
|
||||
{
|
||||
bytes = 0;
|
||||
sha512::Initialize(s);
|
||||
return *this;
|
||||
}
|
28
lib/bip158/src/crypto/sha512.h
Normal file
28
lib/bip158/src/crypto/sha512.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_SHA512_H
|
||||
#define BITCOIN_CRYPTO_SHA512_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** A hasher class for SHA-512. */
|
||||
class CSHA512
|
||||
{
|
||||
private:
|
||||
uint64_t s[8];
|
||||
unsigned char buf[128];
|
||||
uint64_t bytes;
|
||||
|
||||
public:
|
||||
static constexpr size_t OUTPUT_SIZE = 64;
|
||||
|
||||
CSHA512();
|
||||
CSHA512& Write(const unsigned char* data, size_t len);
|
||||
void Finalize(unsigned char hash[OUTPUT_SIZE]);
|
||||
CSHA512& Reset();
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_SHA512_H
|
173
lib/bip158/src/crypto/siphash.cpp
Normal file
173
lib/bip158/src/crypto/siphash.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright (c) 2016-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/siphash.h>
|
||||
|
||||
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||||
|
||||
#define SIPROUND do { \
|
||||
v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
|
||||
v0 = ROTL(v0, 32); \
|
||||
v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
|
||||
v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
|
||||
v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
|
||||
v2 = ROTL(v2, 32); \
|
||||
} while (0)
|
||||
|
||||
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
|
||||
{
|
||||
v[0] = 0x736f6d6570736575ULL ^ k0;
|
||||
v[1] = 0x646f72616e646f6dULL ^ k1;
|
||||
v[2] = 0x6c7967656e657261ULL ^ k0;
|
||||
v[3] = 0x7465646279746573ULL ^ k1;
|
||||
count = 0;
|
||||
tmp = 0;
|
||||
}
|
||||
|
||||
CSipHasher& CSipHasher::Write(uint64_t data)
|
||||
{
|
||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
||||
|
||||
assert(count % 8 == 0);
|
||||
|
||||
v3 ^= data;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= data;
|
||||
|
||||
v[0] = v0;
|
||||
v[1] = v1;
|
||||
v[2] = v2;
|
||||
v[3] = v3;
|
||||
|
||||
count += 8;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
|
||||
{
|
||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
||||
uint64_t t = tmp;
|
||||
int c = count;
|
||||
|
||||
while (size--) {
|
||||
t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
|
||||
c++;
|
||||
if ((c & 7) == 0) {
|
||||
v3 ^= t;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= t;
|
||||
t = 0;
|
||||
}
|
||||
}
|
||||
|
||||
v[0] = v0;
|
||||
v[1] = v1;
|
||||
v[2] = v2;
|
||||
v[3] = v3;
|
||||
count = c;
|
||||
tmp = t;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t CSipHasher::Finalize() const
|
||||
{
|
||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
||||
|
||||
uint64_t t = tmp | (((uint64_t)count) << 56);
|
||||
|
||||
v3 ^= t;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= t;
|
||||
v2 ^= 0xFF;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
||||
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
|
||||
{
|
||||
/* Specialized implementation for efficiency */
|
||||
uint64_t d = val.GetUint64(0);
|
||||
|
||||
uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
|
||||
uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
|
||||
uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
|
||||
uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(1);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(2);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(3);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
v3 ^= ((uint64_t)4) << 59;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= ((uint64_t)4) << 59;
|
||||
v2 ^= 0xFF;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
||||
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
|
||||
{
|
||||
/* Specialized implementation for efficiency */
|
||||
uint64_t d = val.GetUint64(0);
|
||||
|
||||
uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
|
||||
uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
|
||||
uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
|
||||
uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
|
||||
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(1);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(2);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = val.GetUint64(3);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
d = (((uint64_t)36) << 56) | extra;
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= d;
|
||||
v2 ^= 0xFF;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
47
lib/bip158/src/crypto/siphash.h
Normal file
47
lib/bip158/src/crypto/siphash.h
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2016-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_SIPHASH_H
|
||||
#define BITCOIN_CRYPTO_SIPHASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <uint256.h>
|
||||
|
||||
/** SipHash-2-4 */
|
||||
class CSipHasher
|
||||
{
|
||||
private:
|
||||
uint64_t v[4];
|
||||
uint64_t tmp;
|
||||
int count;
|
||||
|
||||
public:
|
||||
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
|
||||
CSipHasher(uint64_t k0, uint64_t k1);
|
||||
/** Hash a 64-bit integer worth of data
|
||||
* It is treated as if this was the little-endian interpretation of 8 bytes.
|
||||
* This function can only be used when a multiple of 8 bytes have been written so far.
|
||||
*/
|
||||
CSipHasher& Write(uint64_t data);
|
||||
/** Hash arbitrary bytes. */
|
||||
CSipHasher& Write(const unsigned char* data, size_t size);
|
||||
/** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */
|
||||
uint64_t Finalize() const;
|
||||
};
|
||||
|
||||
/** Optimized SipHash-2-4 implementation for uint256.
|
||||
*
|
||||
* It is identical to:
|
||||
* SipHasher(k0, k1)
|
||||
* .Write(val.GetUint64(0))
|
||||
* .Write(val.GetUint64(1))
|
||||
* .Write(val.GetUint64(2))
|
||||
* .Write(val.GetUint64(3))
|
||||
* .Finalize()
|
||||
*/
|
||||
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
|
||||
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
|
||||
|
||||
#endif // BITCOIN_CRYPTO_SIPHASH_H
|
223
lib/bip158/src/fs.cpp
Normal file
223
lib/bip158/src/fs.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
#include <fs.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <codecvt>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace fsbridge {
|
||||
|
||||
FILE *fopen(const fs::path& p, const char *mode)
|
||||
{
|
||||
#ifndef WIN32
|
||||
return ::fopen(p.string().c_str(), mode);
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt;
|
||||
return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
static std::string GetErrorReason() {
|
||||
return std::strerror(errno);
|
||||
}
|
||||
|
||||
FileLock::FileLock(const fs::path& file)
|
||||
{
|
||||
fd = open(file.string().c_str(), O_RDWR);
|
||||
if (fd == -1) {
|
||||
reason = GetErrorReason();
|
||||
}
|
||||
}
|
||||
|
||||
FileLock::~FileLock()
|
||||
{
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool FileLock::TryLock()
|
||||
{
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_SETLK, &lock) == -1) {
|
||||
reason = GetErrorReason();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
||||
static std::string GetErrorReason() {
|
||||
wchar_t* err;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<WCHAR*>(&err), 0, nullptr);
|
||||
std::wstring err_str(err);
|
||||
LocalFree(err);
|
||||
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(err_str);
|
||||
}
|
||||
|
||||
FileLock::FileLock(const fs::path& file)
|
||||
{
|
||||
hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
reason = GetErrorReason();
|
||||
}
|
||||
}
|
||||
|
||||
FileLock::~FileLock()
|
||||
{
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
}
|
||||
|
||||
bool FileLock::TryLock()
|
||||
{
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
_OVERLAPPED overlapped = {0};
|
||||
if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) {
|
||||
reason = GetErrorReason();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string get_filesystem_error_message(const fs::filesystem_error& e)
|
||||
{
|
||||
#ifndef WIN32
|
||||
return e.what();
|
||||
#else
|
||||
// Convert from Multi Byte to utf-16
|
||||
std::string mb_string(e.what());
|
||||
int size = MultiByteToWideChar(CP_ACP, 0, mb_string.c_str(), mb_string.size(), nullptr, 0);
|
||||
|
||||
std::wstring utf16_string(size, L'\0');
|
||||
MultiByteToWideChar(CP_ACP, 0, mb_string.c_str(), mb_string.size(), &*utf16_string.begin(), size);
|
||||
// Convert from utf-16 to utf-8
|
||||
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(utf16_string);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __GLIBCXX__
|
||||
|
||||
// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
|
||||
|
||||
static std::string openmodeToStr(std::ios_base::openmode mode)
|
||||
{
|
||||
switch (mode & ~std::ios_base::ate) {
|
||||
case std::ios_base::out:
|
||||
case std::ios_base::out | std::ios_base::trunc:
|
||||
return "w";
|
||||
case std::ios_base::out | std::ios_base::app:
|
||||
case std::ios_base::app:
|
||||
return "a";
|
||||
case std::ios_base::in:
|
||||
return "r";
|
||||
case std::ios_base::in | std::ios_base::out:
|
||||
return "r+";
|
||||
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc:
|
||||
return "w+";
|
||||
case std::ios_base::in | std::ios_base::out | std::ios_base::app:
|
||||
case std::ios_base::in | std::ios_base::app:
|
||||
return "a+";
|
||||
case std::ios_base::out | std::ios_base::binary:
|
||||
case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
|
||||
return "wb";
|
||||
case std::ios_base::out | std::ios_base::app | std::ios_base::binary:
|
||||
case std::ios_base::app | std::ios_base::binary:
|
||||
return "ab";
|
||||
case std::ios_base::in | std::ios_base::binary:
|
||||
return "rb";
|
||||
case std::ios_base::in | std::ios_base::out | std::ios_base::binary:
|
||||
return "r+b";
|
||||
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
|
||||
return "w+b";
|
||||
case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary:
|
||||
case std::ios_base::in | std::ios_base::app | std::ios_base::binary:
|
||||
return "a+b";
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
|
||||
{
|
||||
close();
|
||||
mode |= std::ios_base::in;
|
||||
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
|
||||
if (m_file == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
|
||||
rdbuf(&m_filebuf);
|
||||
if (mode & std::ios_base::ate) {
|
||||
seekg(0, std::ios_base::end);
|
||||
}
|
||||
}
|
||||
|
||||
void ifstream::close()
|
||||
{
|
||||
if (m_file != nullptr) {
|
||||
m_filebuf.close();
|
||||
fclose(m_file);
|
||||
}
|
||||
m_file = nullptr;
|
||||
}
|
||||
|
||||
void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
|
||||
{
|
||||
close();
|
||||
mode |= std::ios_base::out;
|
||||
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
|
||||
if (m_file == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
|
||||
rdbuf(&m_filebuf);
|
||||
if (mode & std::ios_base::ate) {
|
||||
seekp(0, std::ios_base::end);
|
||||
}
|
||||
}
|
||||
|
||||
void ofstream::close()
|
||||
{
|
||||
if (m_file != nullptr) {
|
||||
m_filebuf.close();
|
||||
fclose(m_file);
|
||||
}
|
||||
m_file = nullptr;
|
||||
}
|
||||
#else // __GLIBCXX__
|
||||
|
||||
static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
|
||||
"Warning: This build is using boost::filesystem ofstream and ifstream "
|
||||
"implementations which will fail to open paths containing multibyte "
|
||||
"characters. You should delete this static_assert to ignore this warning, "
|
||||
"or switch to a different C++ standard library like the Microsoft C++ "
|
||||
"Standard Library (where boost uses non-standard extensions to construct "
|
||||
"stream objects with wide filenames), or the GNU libstdc++ library (where "
|
||||
"a more complicated workaround has been implemented above).");
|
||||
|
||||
#endif // __GLIBCXX__
|
||||
#endif // WIN32
|
||||
|
||||
} // fsbridge
|
96
lib/bip158/src/fs.h
Normal file
96
lib/bip158/src/fs.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2017-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_FS_H
|
||||
#define BITCOIN_FS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#if defined WIN32 && defined __GLIBCXX__
|
||||
#include <ext/stdio_filebuf.h>
|
||||
#endif
|
||||
|
||||
#define BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
/** Filesystem operations and types */
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
/** Bridge operations to C stdio */
|
||||
namespace fsbridge {
|
||||
FILE *fopen(const fs::path& p, const char *mode);
|
||||
|
||||
class FileLock
|
||||
{
|
||||
public:
|
||||
FileLock() = delete;
|
||||
FileLock(const FileLock&) = delete;
|
||||
FileLock(FileLock&&) = delete;
|
||||
explicit FileLock(const fs::path& file);
|
||||
~FileLock();
|
||||
bool TryLock();
|
||||
std::string GetReason() { return reason; }
|
||||
|
||||
private:
|
||||
std::string reason;
|
||||
#ifndef WIN32
|
||||
int fd = -1;
|
||||
#else
|
||||
void* hFile = (void*)-1; // INVALID_HANDLE_VALUE
|
||||
#endif
|
||||
};
|
||||
|
||||
std::string get_filesystem_error_message(const fs::filesystem_error& e);
|
||||
|
||||
// GNU libstdc++ specific workaround for opening UTF-8 paths on Windows.
|
||||
//
|
||||
// On Windows, it is only possible to reliably access multibyte file paths through
|
||||
// `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't
|
||||
// require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't
|
||||
// provide them (in contrast to the Microsoft C++ library, see
|
||||
// https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032),
|
||||
// Boost is forced to fall back to `char` constructors which may not work properly.
|
||||
//
|
||||
// Work around this issue by creating stream objects with `_wfopen` in
|
||||
// combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed
|
||||
// with an upgrade to C++17, where streams can be constructed directly from
|
||||
// `std::filesystem::path` objects.
|
||||
|
||||
#if defined WIN32 && defined __GLIBCXX__
|
||||
class ifstream : public std::istream
|
||||
{
|
||||
public:
|
||||
ifstream() = default;
|
||||
explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); }
|
||||
~ifstream() { close(); }
|
||||
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in);
|
||||
bool is_open() { return m_filebuf.is_open(); }
|
||||
void close();
|
||||
|
||||
private:
|
||||
__gnu_cxx::stdio_filebuf<char> m_filebuf;
|
||||
FILE* m_file = nullptr;
|
||||
};
|
||||
class ofstream : public std::ostream
|
||||
{
|
||||
public:
|
||||
ofstream() = default;
|
||||
explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); }
|
||||
~ofstream() { close(); }
|
||||
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out);
|
||||
bool is_open() { return m_filebuf.is_open(); }
|
||||
void close();
|
||||
|
||||
private:
|
||||
__gnu_cxx::stdio_filebuf<char> m_filebuf;
|
||||
FILE* m_file = nullptr;
|
||||
};
|
||||
#else // !(WIN32 && __GLIBCXX__)
|
||||
typedef fs::ifstream ifstream;
|
||||
typedef fs::ofstream ofstream;
|
||||
#endif // WIN32 && __GLIBCXX__
|
||||
};
|
||||
|
||||
#endif // BITCOIN_FS_H
|
207
lib/bip158/src/hash.h
Normal file
207
lib/bip158/src/hash.h
Normal file
@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_HASH_H
|
||||
#define BITCOIN_HASH_H
|
||||
|
||||
#include <crypto/common.h>
|
||||
#include <crypto/ripemd160.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <prevector.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <version.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef uint256 ChainCode;
|
||||
|
||||
/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
|
||||
class CHash256 {
|
||||
private:
|
||||
CSHA256 sha;
|
||||
public:
|
||||
static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
|
||||
|
||||
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
||||
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
||||
sha.Finalize(buf);
|
||||
sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
|
||||
}
|
||||
|
||||
CHash256& Write(const unsigned char *data, size_t len) {
|
||||
sha.Write(data, len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CHash256& Reset() {
|
||||
sha.Reset();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/** A hasher class for Bitcoin's 160-bit hash (SHA-256 + RIPEMD-160). */
|
||||
class CHash160 {
|
||||
private:
|
||||
CSHA256 sha;
|
||||
public:
|
||||
static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
|
||||
|
||||
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
|
||||
unsigned char buf[CSHA256::OUTPUT_SIZE];
|
||||
sha.Finalize(buf);
|
||||
CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
|
||||
}
|
||||
|
||||
CHash160& Write(const unsigned char *data, size_t len) {
|
||||
sha.Write(data, len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CHash160& Reset() {
|
||||
sha.Reset();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/** Compute the 256-bit hash of an object. */
|
||||
template<typename T1>
|
||||
inline uint256 Hash(const T1 pbegin, const T1 pend)
|
||||
{
|
||||
static const unsigned char pblank[1] = {};
|
||||
uint256 result;
|
||||
CHash256().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
|
||||
.Finalize((unsigned char*)&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compute the 256-bit hash of the concatenation of two objects. */
|
||||
template<typename T1, typename T2>
|
||||
inline uint256 Hash(const T1 p1begin, const T1 p1end,
|
||||
const T2 p2begin, const T2 p2end) {
|
||||
static const unsigned char pblank[1] = {};
|
||||
uint256 result;
|
||||
CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
|
||||
.Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
|
||||
.Finalize((unsigned char*)&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compute the 160-bit hash an object. */
|
||||
template<typename T1>
|
||||
inline uint160 Hash160(const T1 pbegin, const T1 pend)
|
||||
{
|
||||
static unsigned char pblank[1] = {};
|
||||
uint160 result;
|
||||
CHash160().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
|
||||
.Finalize((unsigned char*)&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Compute the 160-bit hash of a vector. */
|
||||
inline uint160 Hash160(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
return Hash160(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
/** Compute the 160-bit hash of a vector. */
|
||||
template<unsigned int N>
|
||||
inline uint160 Hash160(const prevector<N, unsigned char>& vch)
|
||||
{
|
||||
return Hash160(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
/** A writer stream (for serialization) that computes a 256-bit hash. */
|
||||
class CHashWriter
|
||||
{
|
||||
private:
|
||||
CHash256 ctx;
|
||||
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
public:
|
||||
|
||||
CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
|
||||
|
||||
int GetType() const { return nType; }
|
||||
int GetVersion() const { return nVersion; }
|
||||
|
||||
void write(const char *pch, size_t size) {
|
||||
ctx.Write((const unsigned char*)pch, size);
|
||||
}
|
||||
|
||||
// invalidates the object
|
||||
uint256 GetHash() {
|
||||
uint256 result;
|
||||
ctx.Finalize((unsigned char*)&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first 64 bits from the resulting hash.
|
||||
*/
|
||||
inline uint64_t GetCheapHash() {
|
||||
unsigned char result[CHash256::OUTPUT_SIZE];
|
||||
ctx.Finalize(result);
|
||||
return ReadLE64(result);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CHashWriter& operator<<(const T& obj) {
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Reads data from an underlying stream, while hashing the read data. */
|
||||
template<typename Source>
|
||||
class CHashVerifier : public CHashWriter
|
||||
{
|
||||
private:
|
||||
Source* source;
|
||||
|
||||
public:
|
||||
explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
|
||||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
source->read(pch, nSize);
|
||||
this->write(pch, nSize);
|
||||
}
|
||||
|
||||
void ignore(size_t nSize)
|
||||
{
|
||||
char data[1024];
|
||||
while (nSize > 0) {
|
||||
size_t now = std::min<size_t>(nSize, 1024);
|
||||
read(data, now);
|
||||
nSize -= now;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CHashVerifier<Source>& operator>>(T&& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Compute the 256-bit hash of an object's serialization. */
|
||||
template<typename T>
|
||||
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
|
||||
{
|
||||
CHashWriter ss(nType, nVersion);
|
||||
ss << obj;
|
||||
return ss.GetHash();
|
||||
}
|
||||
|
||||
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
|
||||
|
||||
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
|
||||
|
||||
#endif // BITCOIN_HASH_H
|
56
lib/bip158/src/indirectmap.h
Normal file
56
lib/bip158/src/indirectmap.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_INDIRECTMAP_H
|
||||
#define BITCOIN_INDIRECTMAP_H
|
||||
|
||||
template <class T>
|
||||
struct DereferencingComparator { bool operator()(const T a, const T b) const { return *a < *b; } };
|
||||
|
||||
/* Map whose keys are pointers, but are compared by their dereferenced values.
|
||||
*
|
||||
* Differs from a plain std::map<const K*, T, DereferencingComparator<K*> > in
|
||||
* that methods that take a key for comparison take a K rather than taking a K*
|
||||
* (taking a K* would be confusing, since it's the value rather than the address
|
||||
* of the object for comparison that matters due to the dereferencing comparator).
|
||||
*
|
||||
* Objects pointed to by keys must not be modified in any way that changes the
|
||||
* result of DereferencingComparator.
|
||||
*/
|
||||
template <class K, class T>
|
||||
class indirectmap {
|
||||
private:
|
||||
typedef std::map<const K*, T, DereferencingComparator<const K*> > base;
|
||||
base m;
|
||||
public:
|
||||
typedef typename base::iterator iterator;
|
||||
typedef typename base::const_iterator const_iterator;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::value_type value_type;
|
||||
|
||||
// passthrough (pointer interface)
|
||||
std::pair<iterator, bool> insert(const value_type& value) { return m.insert(value); }
|
||||
|
||||
// pass address (value interface)
|
||||
iterator find(const K& key) { return m.find(&key); }
|
||||
const_iterator find(const K& key) const { return m.find(&key); }
|
||||
iterator lower_bound(const K& key) { return m.lower_bound(&key); }
|
||||
const_iterator lower_bound(const K& key) const { return m.lower_bound(&key); }
|
||||
size_type erase(const K& key) { return m.erase(&key); }
|
||||
size_type count(const K& key) const { return m.count(&key); }
|
||||
|
||||
// passthrough
|
||||
bool empty() const { return m.empty(); }
|
||||
size_type size() const { return m.size(); }
|
||||
size_type max_size() const { return m.max_size(); }
|
||||
void clear() { m.clear(); }
|
||||
iterator begin() { return m.begin(); }
|
||||
iterator end() { return m.end(); }
|
||||
const_iterator begin() const { return m.begin(); }
|
||||
const_iterator end() const { return m.end(); }
|
||||
const_iterator cbegin() const { return m.cbegin(); }
|
||||
const_iterator cend() const { return m.cend(); }
|
||||
};
|
||||
|
||||
#endif // BITCOIN_INDIRECTMAP_H
|
307
lib/bip158/src/logging.cpp
Normal file
307
lib/bip158/src/logging.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <logging.h>
|
||||
#include <util/threadnames.h>
|
||||
#include <util/time.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
|
||||
|
||||
BCLog::Logger& LogInstance()
|
||||
{
|
||||
/**
|
||||
* NOTE: the logger instances is leaked on exit. This is ugly, but will be
|
||||
* cleaned up by the OS/libc. Defining a logger as a global object doesn't work
|
||||
* since the order of destruction of static/global objects is undefined.
|
||||
* Consider if the logger gets destroyed, and then some later destructor calls
|
||||
* LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to
|
||||
* access the logger. When the shutdown sequence is fully audited and tested,
|
||||
* explicit destruction of these objects can be implemented by changing this
|
||||
* from a raw pointer to a std::unique_ptr.
|
||||
* Since the destructor is never called, the logger and all its members must
|
||||
* have a trivial destructor.
|
||||
*
|
||||
* This method of initialization was originally introduced in
|
||||
* ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
|
||||
*/
|
||||
static BCLog::Logger* g_logger{new BCLog::Logger()};
|
||||
return *g_logger;
|
||||
}
|
||||
|
||||
bool fLogIPs = DEFAULT_LOGIPS;
|
||||
|
||||
static int FileWriteStr(const std::string &str, FILE *fp)
|
||||
{
|
||||
return fwrite(str.data(), 1, str.size(), fp);
|
||||
}
|
||||
|
||||
bool BCLog::Logger::StartLogging()
|
||||
{
|
||||
std::lock_guard<std::mutex> scoped_lock(m_cs);
|
||||
|
||||
assert(m_buffering);
|
||||
assert(m_fileout == nullptr);
|
||||
|
||||
if (m_print_to_file) {
|
||||
assert(!m_file_path.empty());
|
||||
m_fileout = fsbridge::fopen(m_file_path, "a");
|
||||
if (!m_fileout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setbuf(m_fileout, nullptr); // unbuffered
|
||||
|
||||
// Add newlines to the logfile to distinguish this execution from the
|
||||
// last one.
|
||||
FileWriteStr("\n\n\n\n\n", m_fileout);
|
||||
}
|
||||
|
||||
// dump buffered messages from before we opened the log
|
||||
m_buffering = false;
|
||||
while (!m_msgs_before_open.empty()) {
|
||||
const std::string& s = m_msgs_before_open.front();
|
||||
|
||||
if (m_print_to_file) FileWriteStr(s, m_fileout);
|
||||
if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
|
||||
|
||||
m_msgs_before_open.pop_front();
|
||||
}
|
||||
if (m_print_to_console) fflush(stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BCLog::Logger::DisconnectTestLogger()
|
||||
{
|
||||
std::lock_guard<std::mutex> scoped_lock(m_cs);
|
||||
m_buffering = true;
|
||||
if (m_fileout != nullptr) fclose(m_fileout);
|
||||
m_fileout = nullptr;
|
||||
}
|
||||
|
||||
void BCLog::Logger::EnableCategory(BCLog::LogFlags flag)
|
||||
{
|
||||
m_categories |= flag;
|
||||
}
|
||||
|
||||
bool BCLog::Logger::EnableCategory(const std::string& str)
|
||||
{
|
||||
BCLog::LogFlags flag;
|
||||
if (!GetLogCategory(flag, str)) return false;
|
||||
EnableCategory(flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BCLog::Logger::DisableCategory(BCLog::LogFlags flag)
|
||||
{
|
||||
m_categories &= ~flag;
|
||||
}
|
||||
|
||||
bool BCLog::Logger::DisableCategory(const std::string& str)
|
||||
{
|
||||
BCLog::LogFlags flag;
|
||||
if (!GetLogCategory(flag, str)) return false;
|
||||
DisableCategory(flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
|
||||
{
|
||||
return (m_categories.load(std::memory_order_relaxed) & category) != 0;
|
||||
}
|
||||
|
||||
bool BCLog::Logger::DefaultShrinkDebugFile() const
|
||||
{
|
||||
return m_categories == BCLog::NONE;
|
||||
}
|
||||
|
||||
struct CLogCategoryDesc
|
||||
{
|
||||
BCLog::LogFlags flag;
|
||||
std::string category;
|
||||
};
|
||||
|
||||
const CLogCategoryDesc LogCategories[] =
|
||||
{
|
||||
{BCLog::NONE, "0"},
|
||||
{BCLog::NONE, "none"},
|
||||
{BCLog::NET, "net"},
|
||||
{BCLog::TOR, "tor"},
|
||||
{BCLog::MEMPOOL, "mempool"},
|
||||
{BCLog::HTTP, "http"},
|
||||
{BCLog::BENCH, "bench"},
|
||||
{BCLog::ZMQ, "zmq"},
|
||||
{BCLog::DB, "db"},
|
||||
{BCLog::RPC, "rpc"},
|
||||
{BCLog::ESTIMATEFEE, "estimatefee"},
|
||||
{BCLog::ADDRMAN, "addrman"},
|
||||
{BCLog::SELECTCOINS, "selectcoins"},
|
||||
{BCLog::REINDEX, "reindex"},
|
||||
{BCLog::CMPCTBLOCK, "cmpctblock"},
|
||||
{BCLog::RAND, "rand"},
|
||||
{BCLog::PRUNE, "prune"},
|
||||
{BCLog::PROXY, "proxy"},
|
||||
{BCLog::MEMPOOLREJ, "mempoolrej"},
|
||||
{BCLog::LIBEVENT, "libevent"},
|
||||
{BCLog::COINDB, "coindb"},
|
||||
{BCLog::QT, "qt"},
|
||||
{BCLog::LEVELDB, "leveldb"},
|
||||
{BCLog::ALL, "1"},
|
||||
{BCLog::ALL, "all"},
|
||||
};
|
||||
|
||||
bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
|
||||
{
|
||||
if (str == "") {
|
||||
flag = BCLog::ALL;
|
||||
return true;
|
||||
}
|
||||
for (const CLogCategoryDesc& category_desc : LogCategories) {
|
||||
if (category_desc.category == str) {
|
||||
flag = category_desc.flag;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string ListLogCategories()
|
||||
{
|
||||
std::string ret;
|
||||
int outcount = 0;
|
||||
for (const CLogCategoryDesc& category_desc : LogCategories) {
|
||||
// Omit the special cases.
|
||||
if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
|
||||
if (outcount != 0) ret += ", ";
|
||||
ret += category_desc.category;
|
||||
outcount++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<CLogCategoryActive> ListActiveLogCategories()
|
||||
{
|
||||
std::vector<CLogCategoryActive> ret;
|
||||
for (const CLogCategoryDesc& category_desc : LogCategories) {
|
||||
// Omit the special cases.
|
||||
if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
|
||||
CLogCategoryActive catActive;
|
||||
catActive.category = category_desc.category;
|
||||
catActive.active = LogAcceptCategory(category_desc.flag);
|
||||
ret.push_back(catActive);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string BCLog::Logger::LogTimestampStr(const std::string& str)
|
||||
{
|
||||
std::string strStamped;
|
||||
|
||||
if (!m_log_timestamps)
|
||||
return str;
|
||||
|
||||
if (m_started_new_line) {
|
||||
int64_t nTimeMicros = GetTimeMicros();
|
||||
strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
|
||||
if (m_log_time_micros) {
|
||||
strStamped.pop_back();
|
||||
strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
|
||||
}
|
||||
int64_t mocktime = GetMockTime();
|
||||
if (mocktime) {
|
||||
strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
|
||||
}
|
||||
strStamped += ' ' + str;
|
||||
} else
|
||||
strStamped = str;
|
||||
|
||||
return strStamped;
|
||||
}
|
||||
|
||||
void BCLog::Logger::LogPrintStr(const std::string& str)
|
||||
{
|
||||
std::lock_guard<std::mutex> scoped_lock(m_cs);
|
||||
std::string str_prefixed = str;
|
||||
|
||||
if (m_log_threadnames && m_started_new_line) {
|
||||
str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
|
||||
}
|
||||
|
||||
str_prefixed = LogTimestampStr(str_prefixed);
|
||||
|
||||
m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
|
||||
|
||||
if (m_buffering) {
|
||||
// buffer if we haven't started logging yet
|
||||
m_msgs_before_open.push_back(str_prefixed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_print_to_console) {
|
||||
// print to console
|
||||
fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (m_print_to_file) {
|
||||
assert(m_fileout != nullptr);
|
||||
|
||||
// reopen the log file, if requested
|
||||
if (m_reopen_file) {
|
||||
m_reopen_file = false;
|
||||
FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
|
||||
if (new_fileout) {
|
||||
setbuf(new_fileout, nullptr); // unbuffered
|
||||
fclose(m_fileout);
|
||||
m_fileout = new_fileout;
|
||||
}
|
||||
}
|
||||
FileWriteStr(str_prefixed, m_fileout);
|
||||
}
|
||||
}
|
||||
|
||||
void BCLog::Logger::ShrinkDebugFile()
|
||||
{
|
||||
// Amount of debug.log to save at end when shrinking (must fit in memory)
|
||||
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
|
||||
|
||||
assert(!m_file_path.empty());
|
||||
|
||||
// Scroll debug.log if it's getting too big
|
||||
FILE* file = fsbridge::fopen(m_file_path, "r");
|
||||
|
||||
// Special files (e.g. device nodes) may not have a size.
|
||||
size_t log_size = 0;
|
||||
try {
|
||||
log_size = fs::file_size(m_file_path);
|
||||
} catch (const fs::filesystem_error&) {}
|
||||
|
||||
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
|
||||
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
|
||||
if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
|
||||
{
|
||||
// Restart the file with some of the end
|
||||
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
|
||||
if (fseek(file, -((long)vch.size()), SEEK_END)) {
|
||||
LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
int nBytes = fread(vch.data(), 1, vch.size(), file);
|
||||
fclose(file);
|
||||
|
||||
file = fsbridge::fopen(m_file_path, "w");
|
||||
if (file)
|
||||
{
|
||||
fwrite(vch.data(), 1, nBytes, file);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
else if (file != nullptr)
|
||||
fclose(file);
|
||||
}
|
166
lib/bip158/src/logging.h
Normal file
166
lib/bip158/src/logging.h
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_LOGGING_H
|
||||
#define BITCOIN_LOGGING_H
|
||||
|
||||
#include <fs.h>
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static const bool DEFAULT_LOGTIMEMICROS = false;
|
||||
static const bool DEFAULT_LOGIPS = false;
|
||||
static const bool DEFAULT_LOGTIMESTAMPS = true;
|
||||
static const bool DEFAULT_LOGTHREADNAMES = false;
|
||||
extern const char * const DEFAULT_DEBUGLOGFILE;
|
||||
|
||||
extern bool fLogIPs;
|
||||
|
||||
struct CLogCategoryActive
|
||||
{
|
||||
std::string category;
|
||||
bool active;
|
||||
};
|
||||
|
||||
namespace BCLog {
|
||||
enum LogFlags : uint32_t {
|
||||
NONE = 0,
|
||||
NET = (1 << 0),
|
||||
TOR = (1 << 1),
|
||||
MEMPOOL = (1 << 2),
|
||||
HTTP = (1 << 3),
|
||||
BENCH = (1 << 4),
|
||||
ZMQ = (1 << 5),
|
||||
DB = (1 << 6),
|
||||
RPC = (1 << 7),
|
||||
ESTIMATEFEE = (1 << 8),
|
||||
ADDRMAN = (1 << 9),
|
||||
SELECTCOINS = (1 << 10),
|
||||
REINDEX = (1 << 11),
|
||||
CMPCTBLOCK = (1 << 12),
|
||||
RAND = (1 << 13),
|
||||
PRUNE = (1 << 14),
|
||||
PROXY = (1 << 15),
|
||||
MEMPOOLREJ = (1 << 16),
|
||||
LIBEVENT = (1 << 17),
|
||||
COINDB = (1 << 18),
|
||||
QT = (1 << 19),
|
||||
LEVELDB = (1 << 20),
|
||||
ALL = ~(uint32_t)0,
|
||||
};
|
||||
|
||||
class Logger
|
||||
{
|
||||
private:
|
||||
mutable std::mutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected
|
||||
FILE* m_fileout = nullptr; // GUARDED_BY(m_cs)
|
||||
std::list<std::string> m_msgs_before_open; // GUARDED_BY(m_cs)
|
||||
bool m_buffering{true}; //!< Buffer messages before logging can be started. GUARDED_BY(m_cs)
|
||||
|
||||
/**
|
||||
* m_started_new_line is a state variable that will suppress printing of
|
||||
* the timestamp when multiple calls are made that don't end in a
|
||||
* newline.
|
||||
*/
|
||||
std::atomic_bool m_started_new_line{true};
|
||||
|
||||
/** Log categories bitfield. */
|
||||
std::atomic<uint32_t> m_categories{0};
|
||||
|
||||
std::string LogTimestampStr(const std::string& str);
|
||||
|
||||
public:
|
||||
bool m_print_to_console = false;
|
||||
bool m_print_to_file = false;
|
||||
|
||||
bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS;
|
||||
bool m_log_time_micros = DEFAULT_LOGTIMEMICROS;
|
||||
bool m_log_threadnames = DEFAULT_LOGTHREADNAMES;
|
||||
|
||||
fs::path m_file_path;
|
||||
std::atomic<bool> m_reopen_file{false};
|
||||
|
||||
/** Send a string to the log output */
|
||||
void LogPrintStr(const std::string& str);
|
||||
|
||||
/** Returns whether logs will be written to any output */
|
||||
bool Enabled() const
|
||||
{
|
||||
std::lock_guard<std::mutex> scoped_lock(m_cs);
|
||||
return m_buffering || m_print_to_console || m_print_to_file;
|
||||
}
|
||||
|
||||
/** Start logging (and flush all buffered messages) */
|
||||
bool StartLogging();
|
||||
/** Only for testing */
|
||||
void DisconnectTestLogger();
|
||||
|
||||
void ShrinkDebugFile();
|
||||
|
||||
uint32_t GetCategoryMask() const { return m_categories.load(); }
|
||||
|
||||
void EnableCategory(LogFlags flag);
|
||||
bool EnableCategory(const std::string& str);
|
||||
void DisableCategory(LogFlags flag);
|
||||
bool DisableCategory(const std::string& str);
|
||||
|
||||
bool WillLogCategory(LogFlags category) const;
|
||||
|
||||
bool DefaultShrinkDebugFile() const;
|
||||
};
|
||||
|
||||
} // namespace BCLog
|
||||
|
||||
BCLog::Logger& LogInstance();
|
||||
|
||||
/** Return true if log accepts specified category */
|
||||
static inline bool LogAcceptCategory(BCLog::LogFlags category)
|
||||
{
|
||||
return LogInstance().WillLogCategory(category);
|
||||
}
|
||||
|
||||
/** Returns a string with the log categories. */
|
||||
std::string ListLogCategories();
|
||||
|
||||
/** Returns a vector of the active log categories. */
|
||||
std::vector<CLogCategoryActive> ListActiveLogCategories();
|
||||
|
||||
/** Return true if str parses as a log category and set the flag */
|
||||
bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str);
|
||||
|
||||
// Be conservative when using LogPrintf/error or other things which
|
||||
// unconditionally log to debug.log! It should not be the case that an inbound
|
||||
// peer can fill up a user's disk with debug.log entries.
|
||||
|
||||
template <typename... Args>
|
||||
static inline void LogPrintf(const char* fmt, const Args&... args)
|
||||
{
|
||||
if (LogInstance().Enabled()) {
|
||||
std::string log_msg;
|
||||
try {
|
||||
log_msg = tfm::format(fmt, args...);
|
||||
} catch (tinyformat::format_error& fmterr) {
|
||||
/* Original format string will have newline so don't add one here */
|
||||
log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt;
|
||||
}
|
||||
LogInstance().LogPrintStr(log_msg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static inline void LogPrint(const BCLog::LogFlags& category, const Args&... args)
|
||||
{
|
||||
if (LogAcceptCategory((category))) {
|
||||
LogPrintf(args...);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BITCOIN_LOGGING_H
|
170
lib/bip158/src/memusage.h
Normal file
170
lib/bip158/src/memusage.h
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_MEMUSAGE_H
|
||||
#define BITCOIN_MEMUSAGE_H
|
||||
|
||||
#include <indirectmap.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
namespace memusage
|
||||
{
|
||||
|
||||
/** Compute the total memory used by allocating alloc bytes. */
|
||||
static size_t MallocUsage(size_t alloc);
|
||||
|
||||
/** Dynamic memory usage for built-in types is zero. */
|
||||
static inline size_t DynamicUsage(const int8_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const uint8_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const int16_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const uint16_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const int32_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const uint32_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const int64_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const uint64_t& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const float& v) { return 0; }
|
||||
static inline size_t DynamicUsage(const double& v) { return 0; }
|
||||
template<typename X> static inline size_t DynamicUsage(X * const &v) { return 0; }
|
||||
template<typename X> static inline size_t DynamicUsage(const X * const &v) { return 0; }
|
||||
|
||||
/** Compute the memory used for dynamically allocated but owned data structures.
|
||||
* For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >)
|
||||
* will compute the memory used for the vector<int>'s, but not for the ints inside.
|
||||
* This is for efficiency reasons, as these functions are intended to be fast. If
|
||||
* application data structures require more accurate inner accounting, they should
|
||||
* iterate themselves, or use more efficient caching + updating on modification.
|
||||
*/
|
||||
|
||||
static inline size_t MallocUsage(size_t alloc)
|
||||
{
|
||||
// Measured on libc6 2.19 on Linux.
|
||||
if (alloc == 0) {
|
||||
return 0;
|
||||
} else if (sizeof(void*) == 8) {
|
||||
return ((alloc + 31) >> 4) << 4;
|
||||
} else if (sizeof(void*) == 4) {
|
||||
return ((alloc + 15) >> 3) << 3;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
// STL data structures
|
||||
|
||||
template<typename X>
|
||||
struct stl_tree_node
|
||||
{
|
||||
private:
|
||||
int color;
|
||||
void* parent;
|
||||
void* left;
|
||||
void* right;
|
||||
X x;
|
||||
};
|
||||
|
||||
struct stl_shared_counter
|
||||
{
|
||||
/* Various platforms use different sized counters here.
|
||||
* Conservatively assume that they won't be larger than size_t. */
|
||||
void* class_type;
|
||||
size_t use_count;
|
||||
size_t weak_count;
|
||||
};
|
||||
|
||||
template<typename X>
|
||||
static inline size_t DynamicUsage(const std::vector<X>& v)
|
||||
{
|
||||
return MallocUsage(v.capacity() * sizeof(X));
|
||||
}
|
||||
|
||||
template<unsigned int N, typename X, typename S, typename D>
|
||||
static inline size_t DynamicUsage(const prevector<N, X, S, D>& v)
|
||||
{
|
||||
return MallocUsage(v.allocated_memory());
|
||||
}
|
||||
|
||||
template<typename X, typename Y>
|
||||
static inline size_t DynamicUsage(const std::set<X, Y>& s)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<X>)) * s.size();
|
||||
}
|
||||
|
||||
template<typename X, typename Y>
|
||||
static inline size_t IncrementalDynamicUsage(const std::set<X, Y>& s)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<X>));
|
||||
}
|
||||
|
||||
template<typename X, typename Y, typename Z>
|
||||
static inline size_t DynamicUsage(const std::map<X, Y, Z>& m)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >)) * m.size();
|
||||
}
|
||||
|
||||
template<typename X, typename Y, typename Z>
|
||||
static inline size_t IncrementalDynamicUsage(const std::map<X, Y, Z>& m)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >));
|
||||
}
|
||||
|
||||
// indirectmap has underlying map with pointer as key
|
||||
|
||||
template<typename X, typename Y>
|
||||
static inline size_t DynamicUsage(const indirectmap<X, Y>& m)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >)) * m.size();
|
||||
}
|
||||
|
||||
template<typename X, typename Y>
|
||||
static inline size_t IncrementalDynamicUsage(const indirectmap<X, Y>& m)
|
||||
{
|
||||
return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >));
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
static inline size_t DynamicUsage(const std::unique_ptr<X>& p)
|
||||
{
|
||||
return p ? MallocUsage(sizeof(X)) : 0;
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
static inline size_t DynamicUsage(const std::shared_ptr<X>& p)
|
||||
{
|
||||
// A shared_ptr can either use a single continuous memory block for both
|
||||
// the counter and the storage (when using std::make_shared), or separate.
|
||||
// We can't observe the difference, however, so assume the worst.
|
||||
return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0;
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
struct unordered_node : private X
|
||||
{
|
||||
private:
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
template<typename X, typename Y>
|
||||
static inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)
|
||||
{
|
||||
return MallocUsage(sizeof(unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
|
||||
}
|
||||
|
||||
template<typename X, typename Y, typename Z>
|
||||
static inline size_t DynamicUsage(const std::unordered_map<X, Y, Z>& m)
|
||||
{
|
||||
return MallocUsage(sizeof(unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BITCOIN_MEMUSAGE_H
|
528
lib/bip158/src/prevector.h
Normal file
528
lib/bip158/src/prevector.h
Normal file
@ -0,0 +1,528 @@
|
||||
// Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_PREVECTOR_H
|
||||
#define BITCOIN_PREVECTOR_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/** Implements a drop-in replacement for std::vector<T> which stores up to N
|
||||
* elements directly (without heap allocation). The types Size and Diff are
|
||||
* used to store element counts, and can be any unsigned + signed type.
|
||||
*
|
||||
* Storage layout is either:
|
||||
* - Direct allocation:
|
||||
* - Size _size: the number of used elements (between 0 and N)
|
||||
* - T direct[N]: an array of N elements of type T
|
||||
* (only the first _size are initialized).
|
||||
* - Indirect allocation:
|
||||
* - Size _size: the number of used elements plus N + 1
|
||||
* - Size capacity: the number of allocated elements
|
||||
* - T* indirect: a pointer to an array of capacity elements of type T
|
||||
* (only the first _size are initialized).
|
||||
*
|
||||
* The data type T must be movable by memmove/realloc(). Once we switch to C++,
|
||||
* move constructors can be used instead.
|
||||
*/
|
||||
template<unsigned int N, typename T, typename Size = uint32_t, typename Diff = int32_t>
|
||||
class prevector {
|
||||
public:
|
||||
typedef Size size_type;
|
||||
typedef Diff difference_type;
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
|
||||
class iterator {
|
||||
T* ptr;
|
||||
public:
|
||||
typedef Diff difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
iterator(T* ptr_) : ptr(ptr_) {}
|
||||
T& operator*() const { return *ptr; }
|
||||
T* operator->() const { return ptr; }
|
||||
T& operator[](size_type pos) { return ptr[pos]; }
|
||||
const T& operator[](size_type pos) const { return ptr[pos]; }
|
||||
iterator& operator++() { ptr++; return *this; }
|
||||
iterator& operator--() { ptr--; return *this; }
|
||||
iterator operator++(int) { iterator copy(*this); ++(*this); return copy; }
|
||||
iterator operator--(int) { iterator copy(*this); --(*this); return copy; }
|
||||
difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); }
|
||||
iterator operator+(size_type n) { return iterator(ptr + n); }
|
||||
iterator& operator+=(size_type n) { ptr += n; return *this; }
|
||||
iterator operator-(size_type n) { return iterator(ptr - n); }
|
||||
iterator& operator-=(size_type n) { ptr -= n; return *this; }
|
||||
bool operator==(iterator x) const { return ptr == x.ptr; }
|
||||
bool operator!=(iterator x) const { return ptr != x.ptr; }
|
||||
bool operator>=(iterator x) const { return ptr >= x.ptr; }
|
||||
bool operator<=(iterator x) const { return ptr <= x.ptr; }
|
||||
bool operator>(iterator x) const { return ptr > x.ptr; }
|
||||
bool operator<(iterator x) const { return ptr < x.ptr; }
|
||||
};
|
||||
|
||||
class reverse_iterator {
|
||||
T* ptr;
|
||||
public:
|
||||
typedef Diff difference_type;
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
reverse_iterator(T* ptr_) : ptr(ptr_) {}
|
||||
T& operator*() { return *ptr; }
|
||||
const T& operator*() const { return *ptr; }
|
||||
T* operator->() { return ptr; }
|
||||
const T* operator->() const { return ptr; }
|
||||
reverse_iterator& operator--() { ptr++; return *this; }
|
||||
reverse_iterator& operator++() { ptr--; return *this; }
|
||||
reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; }
|
||||
reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; }
|
||||
bool operator==(reverse_iterator x) const { return ptr == x.ptr; }
|
||||
bool operator!=(reverse_iterator x) const { return ptr != x.ptr; }
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
const T* ptr;
|
||||
public:
|
||||
typedef Diff difference_type;
|
||||
typedef const T value_type;
|
||||
typedef const T* pointer;
|
||||
typedef const T& reference;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
const_iterator(const T* ptr_) : ptr(ptr_) {}
|
||||
const_iterator(iterator x) : ptr(&(*x)) {}
|
||||
const T& operator*() const { return *ptr; }
|
||||
const T* operator->() const { return ptr; }
|
||||
const T& operator[](size_type pos) const { return ptr[pos]; }
|
||||
const_iterator& operator++() { ptr++; return *this; }
|
||||
const_iterator& operator--() { ptr--; return *this; }
|
||||
const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; }
|
||||
const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; }
|
||||
difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); }
|
||||
const_iterator operator+(size_type n) { return const_iterator(ptr + n); }
|
||||
const_iterator& operator+=(size_type n) { ptr += n; return *this; }
|
||||
const_iterator operator-(size_type n) { return const_iterator(ptr - n); }
|
||||
const_iterator& operator-=(size_type n) { ptr -= n; return *this; }
|
||||
bool operator==(const_iterator x) const { return ptr == x.ptr; }
|
||||
bool operator!=(const_iterator x) const { return ptr != x.ptr; }
|
||||
bool operator>=(const_iterator x) const { return ptr >= x.ptr; }
|
||||
bool operator<=(const_iterator x) const { return ptr <= x.ptr; }
|
||||
bool operator>(const_iterator x) const { return ptr > x.ptr; }
|
||||
bool operator<(const_iterator x) const { return ptr < x.ptr; }
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
const T* ptr;
|
||||
public:
|
||||
typedef Diff difference_type;
|
||||
typedef const T value_type;
|
||||
typedef const T* pointer;
|
||||
typedef const T& reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
const_reverse_iterator(const T* ptr_) : ptr(ptr_) {}
|
||||
const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
|
||||
const T& operator*() const { return *ptr; }
|
||||
const T* operator->() const { return ptr; }
|
||||
const_reverse_iterator& operator--() { ptr++; return *this; }
|
||||
const_reverse_iterator& operator++() { ptr--; return *this; }
|
||||
const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; }
|
||||
const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; }
|
||||
bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; }
|
||||
bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; }
|
||||
};
|
||||
|
||||
private:
|
||||
size_type _size = 0;
|
||||
union direct_or_indirect {
|
||||
char direct[sizeof(T) * N];
|
||||
struct {
|
||||
size_type capacity;
|
||||
char* indirect;
|
||||
};
|
||||
} _union = {};
|
||||
|
||||
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
|
||||
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
|
||||
T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect) + pos; }
|
||||
const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect) + pos; }
|
||||
bool is_direct() const { return _size <= N; }
|
||||
|
||||
void change_capacity(size_type new_capacity) {
|
||||
if (new_capacity <= N) {
|
||||
if (!is_direct()) {
|
||||
T* indirect = indirect_ptr(0);
|
||||
T* src = indirect;
|
||||
T* dst = direct_ptr(0);
|
||||
memcpy(dst, src, size() * sizeof(T));
|
||||
free(indirect);
|
||||
_size -= N + 1;
|
||||
}
|
||||
} else {
|
||||
if (!is_direct()) {
|
||||
/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
|
||||
success. These should instead use an allocator or new/delete so that handlers
|
||||
are called as necessary, but performance would be slightly degraded by doing so. */
|
||||
_union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
|
||||
assert(_union.indirect);
|
||||
_union.capacity = new_capacity;
|
||||
} else {
|
||||
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
|
||||
assert(new_indirect);
|
||||
T* src = direct_ptr(0);
|
||||
T* dst = reinterpret_cast<T*>(new_indirect);
|
||||
memcpy(dst, src, size() * sizeof(T));
|
||||
_union.indirect = new_indirect;
|
||||
_union.capacity = new_capacity;
|
||||
_size += N + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
|
||||
const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
|
||||
|
||||
void fill(T* dst, ptrdiff_t count, const T& value = T{}) {
|
||||
std::fill_n(dst, count, value);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
void fill(T* dst, InputIterator first, InputIterator last) {
|
||||
while (first != last) {
|
||||
new(static_cast<void*>(dst)) T(*first);
|
||||
++dst;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void assign(size_type n, const T& val) {
|
||||
clear();
|
||||
if (capacity() < n) {
|
||||
change_capacity(n);
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), n, val);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
void assign(InputIterator first, InputIterator last) {
|
||||
size_type n = last - first;
|
||||
clear();
|
||||
if (capacity() < n) {
|
||||
change_capacity(n);
|
||||
}
|
||||
_size += n;
|
||||
fill(item_ptr(0), first, last);
|
||||
}
|
||||
|
||||
prevector() {}
|
||||
|
||||
explicit prevector(size_type n) {
|
||||
resize(n);
|
||||
}
|
||||
|
||||
explicit prevector(size_type n, const T& val) {
|
||||
change_capacity(n);
|
||||
_size += n;
|
||||
fill(item_ptr(0), n, val);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
prevector(InputIterator first, InputIterator last) {
|
||||
size_type n = last - first;
|
||||
change_capacity(n);
|
||||
_size += n;
|
||||
fill(item_ptr(0), first, last);
|
||||
}
|
||||
|
||||
prevector(const prevector<N, T, Size, Diff>& other) {
|
||||
size_type n = other.size();
|
||||
change_capacity(n);
|
||||
_size += n;
|
||||
fill(item_ptr(0), other.begin(), other.end());
|
||||
}
|
||||
|
||||
prevector(prevector<N, T, Size, Diff>&& other) {
|
||||
swap(other);
|
||||
}
|
||||
|
||||
prevector& operator=(const prevector<N, T, Size, Diff>& other) {
|
||||
if (&other == this) {
|
||||
return *this;
|
||||
}
|
||||
assign(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
prevector& operator=(prevector<N, T, Size, Diff>&& other) {
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return is_direct() ? _size : _size - N - 1;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(item_ptr(0)); }
|
||||
const_iterator begin() const { return const_iterator(item_ptr(0)); }
|
||||
iterator end() { return iterator(item_ptr(size())); }
|
||||
const_iterator end() const { return const_iterator(item_ptr(size())); }
|
||||
|
||||
reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); }
|
||||
const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); }
|
||||
reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); }
|
||||
|
||||
size_t capacity() const {
|
||||
if (is_direct()) {
|
||||
return N;
|
||||
} else {
|
||||
return _union.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
T& operator[](size_type pos) {
|
||||
return *item_ptr(pos);
|
||||
}
|
||||
|
||||
const T& operator[](size_type pos) const {
|
||||
return *item_ptr(pos);
|
||||
}
|
||||
|
||||
void resize(size_type new_size) {
|
||||
size_type cur_size = size();
|
||||
if (cur_size == new_size) {
|
||||
return;
|
||||
}
|
||||
if (cur_size > new_size) {
|
||||
erase(item_ptr(new_size), end());
|
||||
return;
|
||||
}
|
||||
if (new_size > capacity()) {
|
||||
change_capacity(new_size);
|
||||
}
|
||||
ptrdiff_t increase = new_size - cur_size;
|
||||
fill(item_ptr(cur_size), increase);
|
||||
_size += increase;
|
||||
}
|
||||
|
||||
void reserve(size_type new_capacity) {
|
||||
if (new_capacity > capacity()) {
|
||||
change_capacity(new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
void shrink_to_fit() {
|
||||
change_capacity(size());
|
||||
}
|
||||
|
||||
void clear() {
|
||||
resize(0);
|
||||
}
|
||||
|
||||
iterator insert(iterator pos, const T& value) {
|
||||
size_type p = pos - begin();
|
||||
size_type new_size = size() + 1;
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + 1, ptr, (size() - p) * sizeof(T));
|
||||
_size++;
|
||||
new(static_cast<void*>(ptr)) T(value);
|
||||
return iterator(ptr);
|
||||
}
|
||||
|
||||
void insert(iterator pos, size_type count, const T& value) {
|
||||
size_type p = pos - begin();
|
||||
size_type new_size = size() + count;
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
|
||||
_size += count;
|
||||
fill(item_ptr(p), count, value);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
void insert(iterator pos, InputIterator first, InputIterator last) {
|
||||
size_type p = pos - begin();
|
||||
difference_type count = last - first;
|
||||
size_type new_size = size() + count;
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
T* ptr = item_ptr(p);
|
||||
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
|
||||
_size += count;
|
||||
fill(ptr, first, last);
|
||||
}
|
||||
|
||||
inline void resize_uninitialized(size_type new_size) {
|
||||
// resize_uninitialized changes the size of the prevector but does not initialize it.
|
||||
// If size < new_size, the added elements must be initialized explicitly.
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size);
|
||||
_size += new_size - size();
|
||||
return;
|
||||
}
|
||||
if (new_size < size()) {
|
||||
erase(item_ptr(new_size), end());
|
||||
} else {
|
||||
_size += new_size - size();
|
||||
}
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) {
|
||||
return erase(pos, pos + 1);
|
||||
}
|
||||
|
||||
iterator erase(iterator first, iterator last) {
|
||||
// Erase is not allowed to the change the object's capacity. That means
|
||||
// that when starting with an indirectly allocated prevector with
|
||||
// size and capacity > N, the result may be a still indirectly allocated
|
||||
// prevector with size <= N and capacity > N. A shrink_to_fit() call is
|
||||
// necessary to switch to the (more efficient) directly allocated
|
||||
// representation (with capacity N and size <= N).
|
||||
iterator p = first;
|
||||
char* endp = (char*)&(*end());
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
while (p != last) {
|
||||
(*p).~T();
|
||||
_size--;
|
||||
++p;
|
||||
}
|
||||
} else {
|
||||
_size -= last - p;
|
||||
}
|
||||
memmove(&(*first), &(*last), endp - ((char*)(&(*last))));
|
||||
return first;
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
size_type new_size = size() + 1;
|
||||
if (capacity() < new_size) {
|
||||
change_capacity(new_size + (new_size >> 1));
|
||||
}
|
||||
new(item_ptr(size())) T(value);
|
||||
_size++;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
erase(end() - 1, end());
|
||||
}
|
||||
|
||||
T& front() {
|
||||
return *item_ptr(0);
|
||||
}
|
||||
|
||||
const T& front() const {
|
||||
return *item_ptr(0);
|
||||
}
|
||||
|
||||
T& back() {
|
||||
return *item_ptr(size() - 1);
|
||||
}
|
||||
|
||||
const T& back() const {
|
||||
return *item_ptr(size() - 1);
|
||||
}
|
||||
|
||||
void swap(prevector<N, T, Size, Diff>& other) {
|
||||
std::swap(_union, other._union);
|
||||
std::swap(_size, other._size);
|
||||
}
|
||||
|
||||
~prevector() {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
clear();
|
||||
}
|
||||
if (!is_direct()) {
|
||||
free(_union.indirect);
|
||||
_union.indirect = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const prevector<N, T, Size, Diff>& other) const {
|
||||
if (other.size() != size()) {
|
||||
return false;
|
||||
}
|
||||
const_iterator b1 = begin();
|
||||
const_iterator b2 = other.begin();
|
||||
const_iterator e1 = end();
|
||||
while (b1 != e1) {
|
||||
if ((*b1) != (*b2)) {
|
||||
return false;
|
||||
}
|
||||
++b1;
|
||||
++b2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const prevector<N, T, Size, Diff>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool operator<(const prevector<N, T, Size, Diff>& other) const {
|
||||
if (size() < other.size()) {
|
||||
return true;
|
||||
}
|
||||
if (size() > other.size()) {
|
||||
return false;
|
||||
}
|
||||
const_iterator b1 = begin();
|
||||
const_iterator b2 = other.begin();
|
||||
const_iterator e1 = end();
|
||||
while (b1 != e1) {
|
||||
if ((*b1) < (*b2)) {
|
||||
return true;
|
||||
}
|
||||
if ((*b2) < (*b1)) {
|
||||
return false;
|
||||
}
|
||||
++b1;
|
||||
++b2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t allocated_memory() const {
|
||||
if (is_direct()) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((size_t)(sizeof(T))) * _union.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
value_type* data() {
|
||||
return item_ptr(0);
|
||||
}
|
||||
|
||||
const value_type* data() const {
|
||||
return item_ptr(0);
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // BITCOIN_PREVECTOR_H
|
31
lib/bip158/src/primitives/block.cpp
Normal file
31
lib/bip158/src/primitives/block.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <primitives/block.h>
|
||||
|
||||
#include <hash.h>
|
||||
#include <tinyformat.h>
|
||||
#include <crypto/common.h>
|
||||
|
||||
uint256 CBlockHeader::GetHash() const
|
||||
{
|
||||
return SerializeHash(*this);
|
||||
}
|
||||
|
||||
std::string CBlock::ToString() const
|
||||
{
|
||||
std::stringstream s;
|
||||
s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
|
||||
GetHash().ToString(),
|
||||
nVersion,
|
||||
hashPrevBlock.ToString(),
|
||||
hashMerkleRoot.ToString(),
|
||||
nTime, nBits, nNonce,
|
||||
vtx.size());
|
||||
for (const auto& tx : vtx) {
|
||||
s << " " << tx->ToString() << "\n";
|
||||
}
|
||||
return s.str();
|
||||
}
|
155
lib/bip158/src/primitives/block.h
Normal file
155
lib/bip158/src/primitives/block.h
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_PRIMITIVES_BLOCK_H
|
||||
#define BITCOIN_PRIMITIVES_BLOCK_H
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
|
||||
/** Nodes collect new transactions into a block, hash them into a hash tree,
|
||||
* and scan through nonce values to make the block's hash satisfy proof-of-work
|
||||
* requirements. When they solve the proof-of-work, they broadcast the block
|
||||
* to everyone and the block is added to the block chain. The first transaction
|
||||
* in the block is a special one that creates a new coin owned by the creator
|
||||
* of the block.
|
||||
*/
|
||||
class CBlockHeader
|
||||
{
|
||||
public:
|
||||
// header
|
||||
int32_t nVersion;
|
||||
uint256 hashPrevBlock;
|
||||
uint256 hashMerkleRoot;
|
||||
uint32_t nTime;
|
||||
uint32_t nBits;
|
||||
uint32_t nNonce;
|
||||
|
||||
CBlockHeader()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(this->nVersion);
|
||||
READWRITE(hashPrevBlock);
|
||||
READWRITE(hashMerkleRoot);
|
||||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = 0;
|
||||
hashPrevBlock.SetNull();
|
||||
hashMerkleRoot.SetNull();
|
||||
nTime = 0;
|
||||
nBits = 0;
|
||||
nNonce = 0;
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (nBits == 0);
|
||||
}
|
||||
|
||||
uint256 GetHash() const;
|
||||
|
||||
int64_t GetBlockTime() const
|
||||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CBlock : public CBlockHeader
|
||||
{
|
||||
public:
|
||||
// network and disk
|
||||
std::vector<CTransactionRef> vtx;
|
||||
|
||||
// memory only
|
||||
mutable bool fChecked;
|
||||
|
||||
CBlock()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
CBlock(const CBlockHeader &header)
|
||||
{
|
||||
SetNull();
|
||||
*(static_cast<CBlockHeader*>(this)) = header;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITEAS(CBlockHeader, *this);
|
||||
READWRITE(vtx);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
CBlockHeader::SetNull();
|
||||
vtx.clear();
|
||||
fChecked = false;
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
block.hashPrevBlock = hashPrevBlock;
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
/** Describes a place in the block chain to another node such that if the
|
||||
* other node doesn't have the same branch, it can find a recent common trunk.
|
||||
* The further back it is, the further before the fork it may be.
|
||||
*/
|
||||
struct CBlockLocator
|
||||
{
|
||||
std::vector<uint256> vHave;
|
||||
|
||||
CBlockLocator() {}
|
||||
|
||||
explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
int nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(vHave);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
vHave.clear();
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return vHave.empty();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_PRIMITIVES_BLOCK_H
|
115
lib/bip158/src/primitives/transaction.cpp
Normal file
115
lib/bip158/src/primitives/transaction.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
|
||||
#include <hash.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
std::string COutPoint::ToString() const
|
||||
{
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
|
||||
}
|
||||
|
||||
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
|
||||
{
|
||||
prevout = prevoutIn;
|
||||
scriptSig = scriptSigIn;
|
||||
nSequence = nSequenceIn;
|
||||
}
|
||||
|
||||
CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
|
||||
{
|
||||
prevout = COutPoint(hashPrevTx, nOut);
|
||||
scriptSig = scriptSigIn;
|
||||
nSequence = nSequenceIn;
|
||||
}
|
||||
|
||||
std::string CTxIn::ToString() const
|
||||
{
|
||||
std::string str;
|
||||
str += "CTxIn(";
|
||||
str += prevout.ToString();
|
||||
if (prevout.IsNull())
|
||||
str += strprintf(", coinbase %s", HexStr(scriptSig));
|
||||
else
|
||||
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
|
||||
if (nSequence != SEQUENCE_FINAL)
|
||||
str += strprintf(", nSequence=%u", nSequence);
|
||||
str += ")";
|
||||
return str;
|
||||
}
|
||||
|
||||
CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
|
||||
{
|
||||
nValue = nValueIn;
|
||||
scriptPubKey = scriptPubKeyIn;
|
||||
}
|
||||
|
||||
std::string CTxOut::ToString() const
|
||||
{
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
|
||||
|
||||
uint256 CMutableTransaction::GetHash() const
|
||||
{
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
}
|
||||
|
||||
uint256 CTransaction::ComputeHash() const
|
||||
{
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
}
|
||||
|
||||
uint256 CTransaction::ComputeWitnessHash() const
|
||||
{
|
||||
if (!HasWitness()) {
|
||||
return hash;
|
||||
}
|
||||
return SerializeHash(*this, SER_GETHASH, 0);
|
||||
}
|
||||
|
||||
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
|
||||
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{} {}
|
||||
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
|
||||
CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
CAmount nValueOut = 0;
|
||||
for (const auto& tx_out : vout) {
|
||||
nValueOut += tx_out.nValue;
|
||||
if (!MoneyRange(tx_out.nValue) || !MoneyRange(nValueOut))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
}
|
||||
return nValueOut;
|
||||
}
|
||||
|
||||
unsigned int CTransaction::GetTotalSize() const
|
||||
{
|
||||
return ::GetSerializeSize(*this, PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
std::string CTransaction::ToString() const
|
||||
{
|
||||
std::string str;
|
||||
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
|
||||
GetHash().ToString().substr(0,10),
|
||||
nVersion,
|
||||
vin.size(),
|
||||
vout.size(),
|
||||
nLockTime);
|
||||
for (const auto& tx_in : vin)
|
||||
str += " " + tx_in.ToString() + "\n";
|
||||
for (const auto& tx_in : vin)
|
||||
str += " " + tx_in.scriptWitness.ToString() + "\n";
|
||||
for (const auto& tx_out : vout)
|
||||
str += " " + tx_out.ToString() + "\n";
|
||||
return str;
|
||||
}
|
412
lib/bip158/src/primitives/transaction.h
Normal file
412
lib/bip158/src/primitives/transaction.h
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
|
||||
#define BITCOIN_PRIMITIVES_TRANSACTION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <amount.h>
|
||||
#include <script/script.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
|
||||
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
{
|
||||
public:
|
||||
uint256 hash;
|
||||
uint32_t n;
|
||||
|
||||
static constexpr uint32_t NULL_INDEX = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
COutPoint(): n(NULL_INDEX) { }
|
||||
COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(hash);
|
||||
READWRITE(n);
|
||||
}
|
||||
|
||||
void SetNull() { hash.SetNull(); n = NULL_INDEX; }
|
||||
bool IsNull() const { return (hash.IsNull() && n == NULL_INDEX); }
|
||||
|
||||
friend bool operator<(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
int cmp = a.hash.Compare(b.hash);
|
||||
return cmp < 0 || (cmp == 0 && a.n < b.n);
|
||||
}
|
||||
|
||||
friend bool operator==(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
return (a.hash == b.hash && a.n == b.n);
|
||||
}
|
||||
|
||||
friend bool operator!=(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
/** An input of a transaction. It contains the location of the previous
|
||||
* transaction's output that it claims and a signature that matches the
|
||||
* output's public key.
|
||||
*/
|
||||
class CTxIn
|
||||
{
|
||||
public:
|
||||
COutPoint prevout;
|
||||
CScript scriptSig;
|
||||
uint32_t nSequence;
|
||||
CScriptWitness scriptWitness; //!< Only serialized through CTransaction
|
||||
|
||||
/* Setting nSequence to this value for every input in a transaction
|
||||
* disables nLockTime. */
|
||||
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
|
||||
|
||||
/* Below flags apply in the context of BIP 68*/
|
||||
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
|
||||
* relative lock-time. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1U << 31);
|
||||
|
||||
/* If CTxIn::nSequence encodes a relative lock-time and this flag
|
||||
* is set, the relative lock-time has units of 512 seconds,
|
||||
* otherwise it specifies blocks with a granularity of 1. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
|
||||
|
||||
/* If CTxIn::nSequence encodes a relative lock-time, this mask is
|
||||
* applied to extract that lock-time from the sequence field. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
|
||||
|
||||
/* In order to use the same number of bits to encode roughly the
|
||||
* same wall-clock duration, and because blocks are naturally
|
||||
* limited to occur every 600s on average, the minimum granularity
|
||||
* for time-based relative lock-time is fixed at 512 seconds.
|
||||
* Converting from CTxIn::nSequence to seconds is performed by
|
||||
* multiplying by 512 = 2^9, or equivalently shifting up by
|
||||
* 9 bits. */
|
||||
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
|
||||
|
||||
CTxIn()
|
||||
{
|
||||
nSequence = SEQUENCE_FINAL;
|
||||
}
|
||||
|
||||
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
|
||||
CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(prevout);
|
||||
READWRITE(scriptSig);
|
||||
READWRITE(nSequence);
|
||||
}
|
||||
|
||||
friend bool operator==(const CTxIn& a, const CTxIn& b)
|
||||
{
|
||||
return (a.prevout == b.prevout &&
|
||||
a.scriptSig == b.scriptSig &&
|
||||
a.nSequence == b.nSequence);
|
||||
}
|
||||
|
||||
friend bool operator!=(const CTxIn& a, const CTxIn& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
/** An output of a transaction. It contains the public key that the next input
|
||||
* must be able to sign with to claim it.
|
||||
*/
|
||||
class CTxOut
|
||||
{
|
||||
public:
|
||||
CAmount nValue;
|
||||
CScript scriptPubKey;
|
||||
|
||||
CTxOut()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(nValue);
|
||||
READWRITE(scriptPubKey);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nValue = -1;
|
||||
scriptPubKey.clear();
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (nValue == -1);
|
||||
}
|
||||
|
||||
friend bool operator==(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return (a.nValue == b.nValue &&
|
||||
a.scriptPubKey == b.scriptPubKey);
|
||||
}
|
||||
|
||||
friend bool operator!=(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
struct CMutableTransaction;
|
||||
|
||||
/**
|
||||
* Basic transaction serialization format:
|
||||
* - int32_t nVersion
|
||||
* - std::vector<CTxIn> vin
|
||||
* - std::vector<CTxOut> vout
|
||||
* - uint32_t nLockTime
|
||||
*
|
||||
* Extended transaction serialization format:
|
||||
* - int32_t nVersion
|
||||
* - unsigned char dummy = 0x00
|
||||
* - unsigned char flags (!= 0)
|
||||
* - std::vector<CTxIn> vin
|
||||
* - std::vector<CTxOut> vout
|
||||
* - if (flags & 1):
|
||||
* - CTxWitness wit;
|
||||
* - uint32_t nLockTime
|
||||
*/
|
||||
template<typename Stream, typename TxType>
|
||||
inline void UnserializeTransaction(TxType& tx, Stream& s) {
|
||||
const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
|
||||
s >> tx.nVersion;
|
||||
unsigned char flags = 0;
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
|
||||
s >> tx.vin;
|
||||
if (tx.vin.size() == 0 && fAllowWitness) {
|
||||
/* We read a dummy or an empty vin. */
|
||||
s >> flags;
|
||||
if (flags != 0) {
|
||||
s >> tx.vin;
|
||||
s >> tx.vout;
|
||||
}
|
||||
} else {
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
s >> tx.vout;
|
||||
}
|
||||
if ((flags & 1) && fAllowWitness) {
|
||||
/* The witness flag is present, and we support witnesses. */
|
||||
flags ^= 1;
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
s >> tx.vin[i].scriptWitness.stack;
|
||||
}
|
||||
if (!tx.HasWitness()) {
|
||||
/* It's illegal to encode witnesses when all witness stacks are empty. */
|
||||
throw std::ios_base::failure("Superfluous witness record");
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Unknown flag in the serialization */
|
||||
throw std::ios_base::failure("Unknown transaction optional data");
|
||||
}
|
||||
s >> tx.nLockTime;
|
||||
}
|
||||
|
||||
template<typename Stream, typename TxType>
|
||||
inline void SerializeTransaction(const TxType& tx, Stream& s) {
|
||||
const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
|
||||
s << tx.nVersion;
|
||||
unsigned char flags = 0;
|
||||
// Consistency check
|
||||
if (fAllowWitness) {
|
||||
/* Check whether witnesses need to be serialized. */
|
||||
if (tx.HasWitness()) {
|
||||
flags |= 1;
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Use extended format in case witnesses are to be serialized. */
|
||||
std::vector<CTxIn> vinDummy;
|
||||
s << vinDummy;
|
||||
s << flags;
|
||||
}
|
||||
s << tx.vin;
|
||||
s << tx.vout;
|
||||
if (flags & 1) {
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
s << tx.vin[i].scriptWitness.stack;
|
||||
}
|
||||
}
|
||||
s << tx.nLockTime;
|
||||
}
|
||||
|
||||
|
||||
/** The basic transaction that is broadcasted on the network and contained in
|
||||
* blocks. A transaction can contain multiple inputs and outputs.
|
||||
*/
|
||||
class CTransaction
|
||||
{
|
||||
public:
|
||||
// Default transaction version.
|
||||
static const int32_t CURRENT_VERSION=2;
|
||||
|
||||
// Changing the default transaction version requires a two step process: first
|
||||
// adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date
|
||||
// bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and
|
||||
// MAX_STANDARD_VERSION will be equal.
|
||||
static const int32_t MAX_STANDARD_VERSION=2;
|
||||
|
||||
// The local variables are made const to prevent unintended modification
|
||||
// without updating the cached hash value. However, CTransaction is not
|
||||
// actually immutable; deserialization and assignment are implemented,
|
||||
// and bypass the constness. This is safe, as they update the entire
|
||||
// structure, including the hash.
|
||||
const std::vector<CTxIn> vin;
|
||||
const std::vector<CTxOut> vout;
|
||||
const int32_t nVersion;
|
||||
const uint32_t nLockTime;
|
||||
|
||||
private:
|
||||
/** Memory only. */
|
||||
const uint256 hash;
|
||||
const uint256 m_witness_hash;
|
||||
|
||||
uint256 ComputeHash() const;
|
||||
uint256 ComputeWitnessHash() const;
|
||||
|
||||
public:
|
||||
/** Construct a CTransaction that qualifies as IsNull() */
|
||||
CTransaction();
|
||||
|
||||
/** Convert a CMutableTransaction into a CTransaction. */
|
||||
explicit CTransaction(const CMutableTransaction &tx);
|
||||
CTransaction(CMutableTransaction &&tx);
|
||||
|
||||
template <typename Stream>
|
||||
inline void Serialize(Stream& s) const {
|
||||
SerializeTransaction(*this, s);
|
||||
}
|
||||
|
||||
/** This deserializing constructor is provided instead of an Unserialize method.
|
||||
* Unserialize is not possible, since it would require overwriting const fields. */
|
||||
template <typename Stream>
|
||||
CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
|
||||
|
||||
bool IsNull() const {
|
||||
return vin.empty() && vout.empty();
|
||||
}
|
||||
|
||||
const uint256& GetHash() const { return hash; }
|
||||
const uint256& GetWitnessHash() const { return m_witness_hash; };
|
||||
|
||||
// Return sum of txouts.
|
||||
CAmount GetValueOut() const;
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// inputs must be known to compute value in.
|
||||
|
||||
/**
|
||||
* Get the total transaction size in bytes, including witness data.
|
||||
* "Total Size" defined in BIP141 and BIP144.
|
||||
* @return Total transaction size in bytes
|
||||
*/
|
||||
unsigned int GetTotalSize() const;
|
||||
|
||||
bool IsCoinBase() const
|
||||
{
|
||||
return (vin.size() == 1 && vin[0].prevout.IsNull());
|
||||
}
|
||||
|
||||
friend bool operator==(const CTransaction& a, const CTransaction& b)
|
||||
{
|
||||
return a.hash == b.hash;
|
||||
}
|
||||
|
||||
friend bool operator!=(const CTransaction& a, const CTransaction& b)
|
||||
{
|
||||
return a.hash != b.hash;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
bool HasWitness() const
|
||||
{
|
||||
for (size_t i = 0; i < vin.size(); i++) {
|
||||
if (!vin[i].scriptWitness.IsNull()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** A mutable version of CTransaction. */
|
||||
struct CMutableTransaction
|
||||
{
|
||||
std::vector<CTxIn> vin;
|
||||
std::vector<CTxOut> vout;
|
||||
int32_t nVersion;
|
||||
uint32_t nLockTime;
|
||||
|
||||
CMutableTransaction();
|
||||
explicit CMutableTransaction(const CTransaction& tx);
|
||||
|
||||
template <typename Stream>
|
||||
inline void Serialize(Stream& s) const {
|
||||
SerializeTransaction(*this, s);
|
||||
}
|
||||
|
||||
|
||||
template <typename Stream>
|
||||
inline void Unserialize(Stream& s) {
|
||||
UnserializeTransaction(*this, s);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
CMutableTransaction(deserialize_type, Stream& s) {
|
||||
Unserialize(s);
|
||||
}
|
||||
|
||||
/** Compute the hash of this CMutableTransaction. This is computed on the
|
||||
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
|
||||
*/
|
||||
uint256 GetHash() const;
|
||||
|
||||
bool HasWitness() const
|
||||
{
|
||||
for (size_t i = 0; i < vin.size(); i++) {
|
||||
if (!vin[i].scriptWitness.IsNull()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const CTransaction> CTransactionRef;
|
||||
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
|
||||
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
|
||||
|
||||
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
|
790
lib/bip158/src/random.cpp
Normal file
790
lib/bip158/src/random.cpp
Normal file
@ -0,0 +1,790 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <random.h>
|
||||
|
||||
#include <crypto/sha512.h>
|
||||
#include <support/cleanse.h>
|
||||
#ifdef WIN32
|
||||
#include <compat.h> // for Windows API
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
#include <logging.h> // for LogPrint()
|
||||
#include <sync.h> // for WAIT_LOCK
|
||||
#include <util/time.h> // for GetTime()
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <support/allocators/secure.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_GETRANDOM
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/random.h>
|
||||
#endif
|
||||
#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYSCTL_ARND
|
||||
#include <util/strencodings.h> // for ARRAYLEN
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
[[noreturn]] static void RandFailure()
|
||||
{
|
||||
LogPrintf("Failed to read randomness, aborting\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
static inline int64_t GetPerformanceCounter() noexcept
|
||||
{
|
||||
// Read the hardware time stamp counter when available.
|
||||
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
return __rdtsc();
|
||||
#elif !defined(_MSC_VER) && defined(__i386__)
|
||||
uint64_t r = 0;
|
||||
__asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
|
||||
return r;
|
||||
#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
|
||||
uint64_t r1 = 0, r2 = 0;
|
||||
__asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
|
||||
return (r2 << 32) | r1;
|
||||
#else
|
||||
// Fall back to using C++11 clock (usually microsecond or nanosecond precision)
|
||||
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
static bool g_rdrand_supported = false;
|
||||
static bool g_rdseed_supported = false;
|
||||
static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
|
||||
static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
|
||||
#ifdef bit_RDRND
|
||||
static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND");
|
||||
#endif
|
||||
#ifdef bit_RDSEED
|
||||
static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED, "Unexpected value for bit_RDSEED");
|
||||
#endif
|
||||
static void inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
|
||||
{
|
||||
// We can't use __get_cpuid as it doesn't support subleafs.
|
||||
#ifdef __GNUC__
|
||||
__cpuid_count(leaf, subleaf, a, b, c, d);
|
||||
#else
|
||||
__asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void InitHardwareRand()
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
GetCPUID(1, 0, eax, ebx, ecx, edx);
|
||||
if (ecx & CPUID_F1_ECX_RDRAND) {
|
||||
g_rdrand_supported = true;
|
||||
}
|
||||
GetCPUID(7, 0, eax, ebx, ecx, edx);
|
||||
if (ebx & CPUID_F7_EBX_RDSEED) {
|
||||
g_rdseed_supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ReportHardwareRand()
|
||||
{
|
||||
// This must be done in a separate function, as HWRandInit() may be indirectly called
|
||||
// from global constructors, before logging is initialized.
|
||||
if (g_rdseed_supported) {
|
||||
LogPrintf("Using RdSeed as additional entropy source\n");
|
||||
}
|
||||
if (g_rdrand_supported) {
|
||||
LogPrintf("Using RdRand as an additional entropy source\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Read 64 bits of entropy using rdrand.
|
||||
*
|
||||
* Must only be called when RdRand is supported.
|
||||
*/
|
||||
static uint64_t GetRdRand() noexcept
|
||||
{
|
||||
// RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk.
|
||||
#ifdef __i386__
|
||||
uint8_t ok;
|
||||
uint32_t r1, r2;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
__asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %eax
|
||||
if (ok) break;
|
||||
}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
__asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdrand %eax
|
||||
if (ok) break;
|
||||
}
|
||||
return (((uint64_t)r2) << 32) | r1;
|
||||
#elif defined(__x86_64__) || defined(__amd64__)
|
||||
uint8_t ok;
|
||||
uint64_t r1;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
__asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %rax
|
||||
if (ok) break;
|
||||
}
|
||||
return r1;
|
||||
#else
|
||||
#error "RdRand is only supported on x86 and x86_64"
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Read 64 bits of entropy using rdseed.
|
||||
*
|
||||
* Must only be called when RdSeed is supported.
|
||||
*/
|
||||
static uint64_t GetRdSeed() noexcept
|
||||
{
|
||||
// RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered,
|
||||
// but pause after every failure.
|
||||
#ifdef __i386__
|
||||
uint8_t ok;
|
||||
uint32_t r1, r2;
|
||||
do {
|
||||
__asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %eax
|
||||
if (ok) break;
|
||||
__asm__ volatile ("pause");
|
||||
} while(true);
|
||||
do {
|
||||
__asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdseed %eax
|
||||
if (ok) break;
|
||||
__asm__ volatile ("pause");
|
||||
} while(true);
|
||||
return (((uint64_t)r2) << 32) | r1;
|
||||
#elif defined(__x86_64__) || defined(__amd64__)
|
||||
uint8_t ok;
|
||||
uint64_t r1;
|
||||
do {
|
||||
__asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %rax
|
||||
if (ok) break;
|
||||
__asm__ volatile ("pause");
|
||||
} while(true);
|
||||
return r1;
|
||||
#else
|
||||
#error "RdSeed is only supported on x86 and x86_64"
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
/* Access to other hardware random number generators could be added here later,
|
||||
* assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
|
||||
* Slower sources should probably be invoked separately, and/or only from
|
||||
* RandAddSeedSleep (which is called during idle background operation).
|
||||
*/
|
||||
static void InitHardwareRand() {}
|
||||
static void ReportHardwareRand() {}
|
||||
#endif
|
||||
|
||||
/** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
|
||||
static void SeedHardwareFast(CSHA512& hasher) noexcept {
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
if (g_rdrand_supported) {
|
||||
uint64_t out = GetRdRand();
|
||||
hasher.Write((const unsigned char*)&out, sizeof(out));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
|
||||
static void SeedHardwareSlow(CSHA512& hasher) noexcept {
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
// When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's
|
||||
// guaranteed to produce independent randomness on every call.
|
||||
if (g_rdseed_supported) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
uint64_t out = GetRdSeed();
|
||||
hasher.Write((const unsigned char*)&out, sizeof(out));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// When falling back to RdRand, XOR the result of 1024 results.
|
||||
// This guarantees a reseeding occurs between each.
|
||||
if (g_rdrand_supported) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
uint64_t out = 0;
|
||||
for (int j = 0; j < 1024; ++j) out ^= GetRdRand();
|
||||
hasher.Write((const unsigned char*)&out, sizeof(out));
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
|
||||
static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
|
||||
{
|
||||
CSHA512 inner_hasher;
|
||||
inner_hasher.Write(seed, sizeof(seed));
|
||||
|
||||
// Hash loop
|
||||
unsigned char buffer[64];
|
||||
int64_t stop = GetTimeMicros() + microseconds;
|
||||
do {
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
inner_hasher.Finalize(buffer);
|
||||
inner_hasher.Reset();
|
||||
inner_hasher.Write(buffer, sizeof(buffer));
|
||||
}
|
||||
// Benchmark operation and feed it into outer hasher.
|
||||
int64_t perf = GetPerformanceCounter();
|
||||
hasher.Write((const unsigned char*)&perf, sizeof(perf));
|
||||
} while (GetTimeMicros() < stop);
|
||||
|
||||
// Produce output from inner state and feed it to outer hasher.
|
||||
inner_hasher.Finalize(buffer);
|
||||
hasher.Write(buffer, sizeof(buffer));
|
||||
// Try to clean up.
|
||||
inner_hasher.Reset();
|
||||
memory_cleanse(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static void RandAddSeedPerfmon(CSHA512& hasher)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
|
||||
// Seed with the entire set of perfmon data
|
||||
|
||||
// This can take up to 2 seconds, so only do it every 10 minutes
|
||||
static int64_t nLastPerfmon;
|
||||
if (GetTime() < nLastPerfmon + 10 * 60)
|
||||
return;
|
||||
nLastPerfmon = GetTime();
|
||||
|
||||
std::vector<unsigned char> vData(250000, 0);
|
||||
long ret = 0;
|
||||
unsigned long nSize = 0;
|
||||
const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
|
||||
while (true) {
|
||||
nSize = vData.size();
|
||||
ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr, nullptr, vData.data(), &nSize);
|
||||
if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
|
||||
break;
|
||||
vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially
|
||||
}
|
||||
RegCloseKey(HKEY_PERFORMANCE_DATA);
|
||||
if (ret == ERROR_SUCCESS) {
|
||||
hasher.Write(vData.data(), nSize);
|
||||
memory_cleanse(vData.data(), nSize);
|
||||
} else {
|
||||
// Performance data is only a best-effort attempt at improving the
|
||||
// situation when the OS randomness (and other sources) aren't
|
||||
// adequate. As a result, failure to read it is isn't considered critical,
|
||||
// so we don't call RandFailure().
|
||||
// TODO: Add logging when the logger is made functional before global
|
||||
// constructors have been invoked.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
|
||||
* compatible way to get cryptographic randomness on UNIX-ish platforms.
|
||||
*/
|
||||
static void GetDevURandom(unsigned char *ent32)
|
||||
{
|
||||
int f = open("/dev/urandom", O_RDONLY);
|
||||
if (f == -1) {
|
||||
RandFailure();
|
||||
}
|
||||
int have = 0;
|
||||
do {
|
||||
ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
|
||||
if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
|
||||
close(f);
|
||||
RandFailure();
|
||||
}
|
||||
have += n;
|
||||
} while (have < NUM_OS_RANDOM_BYTES);
|
||||
close(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Get 32 bytes of system entropy. */
|
||||
void GetOSRand(unsigned char *ent32)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
HCRYPTPROV hProvider;
|
||||
int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
|
||||
if (!ret) {
|
||||
RandFailure();
|
||||
}
|
||||
ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
|
||||
if (!ret) {
|
||||
RandFailure();
|
||||
}
|
||||
CryptReleaseContext(hProvider, 0);
|
||||
#elif defined(HAVE_SYS_GETRANDOM)
|
||||
/* Linux. From the getrandom(2) man page:
|
||||
* "If the urandom source has been initialized, reads of up to 256 bytes
|
||||
* will always return as many bytes as requested and will not be
|
||||
* interrupted by signals."
|
||||
*/
|
||||
int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
|
||||
if (rv != NUM_OS_RANDOM_BYTES) {
|
||||
if (rv < 0 && errno == ENOSYS) {
|
||||
/* Fallback for kernel <3.17: the return value will be -1 and errno
|
||||
* ENOSYS if the syscall is not available, in that case fall back
|
||||
* to /dev/urandom.
|
||||
*/
|
||||
GetDevURandom(ent32);
|
||||
} else {
|
||||
RandFailure();
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
|
||||
/* On OpenBSD this can return up to 256 bytes of entropy, will return an
|
||||
* error if more are requested.
|
||||
* The call cannot return less than the requested number of bytes.
|
||||
getentropy is explicitly limited to openbsd here, as a similar (but not
|
||||
the same) function may exist on other platforms via glibc.
|
||||
*/
|
||||
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
|
||||
RandFailure();
|
||||
}
|
||||
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
|
||||
// We need a fallback for OSX < 10.12
|
||||
if (&getentropy != nullptr) {
|
||||
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
|
||||
RandFailure();
|
||||
}
|
||||
} else {
|
||||
GetDevURandom(ent32);
|
||||
}
|
||||
#elif defined(HAVE_SYSCTL_ARND)
|
||||
/* FreeBSD and similar. It is possible for the call to return less
|
||||
* bytes than requested, so need to read in a loop.
|
||||
*/
|
||||
static const int name[2] = {CTL_KERN, KERN_ARND};
|
||||
int have = 0;
|
||||
do {
|
||||
size_t len = NUM_OS_RANDOM_BYTES - have;
|
||||
if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, nullptr, 0) != 0) {
|
||||
RandFailure();
|
||||
}
|
||||
have += len;
|
||||
} while (have < NUM_OS_RANDOM_BYTES);
|
||||
#else
|
||||
/* Fall back to /dev/urandom if there is no specific method implemented to
|
||||
* get system entropy for this OS.
|
||||
*/
|
||||
GetDevURandom(ent32);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LockingCallbackOpenSSL(int mode, int i, const char* file, int line);
|
||||
|
||||
namespace {
|
||||
|
||||
class RNGState {
|
||||
Mutex m_mutex;
|
||||
/* The RNG state consists of 256 bits of entropy, taken from the output of
|
||||
* one operation's SHA512 output, and fed as input to the next one.
|
||||
* Carrying 256 bits of entropy should be sufficient to guarantee
|
||||
* unpredictability as long as any entropy source was ever unpredictable
|
||||
* to an attacker. To protect against situations where an attacker might
|
||||
* observe the RNG's state, fresh entropy is always mixed when
|
||||
* GetStrongRandBytes is called.
|
||||
*/
|
||||
unsigned char m_state[32] GUARDED_BY(m_mutex) = {0};
|
||||
uint64_t m_counter GUARDED_BY(m_mutex) = 0;
|
||||
bool m_strongly_seeded GUARDED_BY(m_mutex) = false;
|
||||
std::unique_ptr<Mutex[]> m_mutex_openssl;
|
||||
|
||||
public:
|
||||
RNGState() noexcept
|
||||
{
|
||||
InitHardwareRand();
|
||||
|
||||
// Init OpenSSL library multithreading support
|
||||
m_mutex_openssl.reset(new Mutex[CRYPTO_num_locks()]);
|
||||
CRYPTO_set_locking_callback(LockingCallbackOpenSSL);
|
||||
|
||||
// OpenSSL can optionally load a config file which lists optional loadable modules and engines.
|
||||
// We don't use them so we don't require the config. However some of our libs may call functions
|
||||
// which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
|
||||
// or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
|
||||
// that the config appears to have been loaded and there are no modules/engines available.
|
||||
OPENSSL_no_config();
|
||||
}
|
||||
|
||||
~RNGState()
|
||||
{
|
||||
// Securely erase the memory used by the OpenSSL PRNG
|
||||
RAND_cleanup();
|
||||
// Shutdown OpenSSL library multithreading support
|
||||
CRYPTO_set_locking_callback(nullptr);
|
||||
}
|
||||
|
||||
/** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher.
|
||||
*
|
||||
* If this function has never been called with strong_seed = true, false is returned.
|
||||
*/
|
||||
bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept
|
||||
{
|
||||
assert(num <= 32);
|
||||
unsigned char buf[64];
|
||||
static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
|
||||
bool ret;
|
||||
{
|
||||
LOCK(m_mutex);
|
||||
ret = (m_strongly_seeded |= strong_seed);
|
||||
// Write the current state of the RNG into the hasher
|
||||
hasher.Write(m_state, 32);
|
||||
// Write a new counter number into the state
|
||||
hasher.Write((const unsigned char*)&m_counter, sizeof(m_counter));
|
||||
++m_counter;
|
||||
// Finalize the hasher
|
||||
hasher.Finalize(buf);
|
||||
// Store the last 32 bytes of the hash output as new RNG state.
|
||||
memcpy(m_state, buf + 32, 32);
|
||||
}
|
||||
// If desired, copy (up to) the first 32 bytes of the hash output as output.
|
||||
if (num) {
|
||||
assert(out != nullptr);
|
||||
memcpy(out, buf, num);
|
||||
}
|
||||
// Best effort cleanup of internal state
|
||||
hasher.Reset();
|
||||
memory_cleanse(buf, 64);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mutex& GetOpenSSLMutex(int i) { return m_mutex_openssl[i]; }
|
||||
};
|
||||
|
||||
RNGState& GetRNGState() noexcept
|
||||
{
|
||||
// This C++11 idiom relies on the guarantee that static variable are initialized
|
||||
// on first call, even when multiple parallel calls are permitted.
|
||||
static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
|
||||
return g_rng[0];
|
||||
}
|
||||
}
|
||||
|
||||
void LockingCallbackOpenSSL(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
|
||||
{
|
||||
RNGState& rng = GetRNGState();
|
||||
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
rng.GetOpenSSLMutex(i).lock();
|
||||
} else {
|
||||
rng.GetOpenSSLMutex(i).unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/* A note on the use of noexcept in the seeding functions below:
|
||||
*
|
||||
* None of the RNG code should ever throw any exception, with the sole exception
|
||||
* of MilliSleep in SeedSleep, which can (and does) support interruptions which
|
||||
* cause a boost::thread_interrupted to be thrown.
|
||||
*
|
||||
* This means that SeedSleep, and all functions that invoke it are throwing.
|
||||
* However, we know that GetRandBytes() and GetStrongRandBytes() never trigger
|
||||
* this sleeping logic, so they are noexcept. The same is true for all the
|
||||
* GetRand*() functions that use GetRandBytes() indirectly.
|
||||
*
|
||||
* TODO: After moving away from interruptible boost-based thread management,
|
||||
* everything can become noexcept here.
|
||||
*/
|
||||
|
||||
static void SeedTimestamp(CSHA512& hasher) noexcept
|
||||
{
|
||||
int64_t perfcounter = GetPerformanceCounter();
|
||||
hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
|
||||
}
|
||||
|
||||
static void SeedFast(CSHA512& hasher) noexcept
|
||||
{
|
||||
unsigned char buffer[32];
|
||||
|
||||
// Stack pointer to indirectly commit to thread/callstack
|
||||
const unsigned char* ptr = buffer;
|
||||
hasher.Write((const unsigned char*)&ptr, sizeof(ptr));
|
||||
|
||||
// Hardware randomness is very fast when available; use it always.
|
||||
SeedHardwareFast(hasher);
|
||||
|
||||
// High-precision timestamp
|
||||
SeedTimestamp(hasher);
|
||||
}
|
||||
|
||||
static void SeedSlow(CSHA512& hasher) noexcept
|
||||
{
|
||||
unsigned char buffer[32];
|
||||
|
||||
// Everything that the 'fast' seeder includes
|
||||
SeedFast(hasher);
|
||||
|
||||
// OS randomness
|
||||
GetOSRand(buffer);
|
||||
hasher.Write(buffer, sizeof(buffer));
|
||||
|
||||
// OpenSSL RNG (for now)
|
||||
RAND_bytes(buffer, sizeof(buffer));
|
||||
hasher.Write(buffer, sizeof(buffer));
|
||||
|
||||
// High-precision timestamp.
|
||||
//
|
||||
// Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a
|
||||
// benchmark of all the entropy gathering sources in this function).
|
||||
SeedTimestamp(hasher);
|
||||
}
|
||||
|
||||
/** Extract entropy from rng, strengthen it, and feed it into hasher. */
|
||||
static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept
|
||||
{
|
||||
static std::atomic<int64_t> last_strengthen{0};
|
||||
int64_t last_time = last_strengthen.load();
|
||||
int64_t current_time = GetTimeMicros();
|
||||
if (current_time > last_time + 60000000) { // Only run once a minute
|
||||
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
|
||||
unsigned char strengthen_seed[32];
|
||||
rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
|
||||
// Strengthen it for 10ms (100ms on first run), and feed it into hasher.
|
||||
Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher);
|
||||
last_strengthen = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
static void SeedSleep(CSHA512& hasher, RNGState& rng)
|
||||
{
|
||||
// Everything that the 'fast' seeder includes
|
||||
SeedFast(hasher);
|
||||
|
||||
// High-precision timestamp
|
||||
SeedTimestamp(hasher);
|
||||
|
||||
// Sleep for 1ms
|
||||
MilliSleep(1);
|
||||
|
||||
// High-precision timestamp after sleeping (as we commit to both the time before and after, this measures the delay)
|
||||
SeedTimestamp(hasher);
|
||||
|
||||
// Windows performance monitor data (once every 10 minutes)
|
||||
RandAddSeedPerfmon(hasher);
|
||||
|
||||
// Strengthen every minute
|
||||
SeedStrengthen(hasher, rng);
|
||||
}
|
||||
|
||||
static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
|
||||
{
|
||||
#ifdef WIN32
|
||||
RAND_screen();
|
||||
#endif
|
||||
|
||||
// Gather 256 bits of hardware randomness, if available
|
||||
SeedHardwareSlow(hasher);
|
||||
|
||||
// Everything that the 'slow' seeder includes.
|
||||
SeedSlow(hasher);
|
||||
|
||||
// Windows performance monitor data.
|
||||
RandAddSeedPerfmon(hasher);
|
||||
|
||||
// Strengthen
|
||||
SeedStrengthen(hasher, rng);
|
||||
}
|
||||
|
||||
enum class RNGLevel {
|
||||
FAST, //!< Automatically called by GetRandBytes
|
||||
SLOW, //!< Automatically called by GetStrongRandBytes
|
||||
SLEEP, //!< Called by RandAddSeedSleep()
|
||||
};
|
||||
|
||||
static void ProcRand(unsigned char* out, int num, RNGLevel level)
|
||||
{
|
||||
// Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available).
|
||||
RNGState& rng = GetRNGState();
|
||||
|
||||
assert(num <= 32);
|
||||
|
||||
CSHA512 hasher;
|
||||
switch (level) {
|
||||
case RNGLevel::FAST:
|
||||
SeedFast(hasher);
|
||||
break;
|
||||
case RNGLevel::SLOW:
|
||||
SeedSlow(hasher);
|
||||
break;
|
||||
case RNGLevel::SLEEP:
|
||||
SeedSleep(hasher, rng);
|
||||
break;
|
||||
}
|
||||
|
||||
// Combine with and update state
|
||||
if (!rng.MixExtract(out, num, std::move(hasher), false)) {
|
||||
// On the first invocation, also seed with SeedStartup().
|
||||
CSHA512 startup_hasher;
|
||||
SeedStartup(startup_hasher, rng);
|
||||
rng.MixExtract(out, num, std::move(startup_hasher), true);
|
||||
}
|
||||
|
||||
// For anything but the 'fast' level, feed the resulting RNG output (after an additional hashing step) back into OpenSSL.
|
||||
if (level != RNGLevel::FAST) {
|
||||
unsigned char buf[64];
|
||||
CSHA512().Write(out, num).Finalize(buf);
|
||||
RAND_add(buf, sizeof(buf), num);
|
||||
memory_cleanse(buf, 64);
|
||||
}
|
||||
}
|
||||
|
||||
void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
|
||||
void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
|
||||
void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); }
|
||||
|
||||
bool g_mock_deterministic_tests{false};
|
||||
|
||||
uint64_t GetRand(uint64_t nMax) noexcept
|
||||
{
|
||||
return FastRandomContext(g_mock_deterministic_tests).randrange(nMax);
|
||||
}
|
||||
|
||||
int GetRandInt(int nMax) noexcept
|
||||
{
|
||||
return GetRand(nMax);
|
||||
}
|
||||
|
||||
uint256 GetRandHash() noexcept
|
||||
{
|
||||
uint256 hash;
|
||||
GetRandBytes((unsigned char*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
|
||||
void FastRandomContext::RandomSeed()
|
||||
{
|
||||
uint256 seed = GetRandHash();
|
||||
rng.SetKey(seed.begin(), 32);
|
||||
requires_seed = false;
|
||||
}
|
||||
|
||||
uint256 FastRandomContext::rand256() noexcept
|
||||
{
|
||||
if (bytebuf_size < 32) {
|
||||
FillByteBuffer();
|
||||
}
|
||||
uint256 ret;
|
||||
memcpy(ret.begin(), bytebuf + 64 - bytebuf_size, 32);
|
||||
bytebuf_size -= 32;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
|
||||
{
|
||||
if (requires_seed) RandomSeed();
|
||||
std::vector<unsigned char> ret(len);
|
||||
if (len > 0) {
|
||||
rng.Keystream(&ret[0], len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
|
||||
{
|
||||
rng.SetKey(seed.begin(), 32);
|
||||
}
|
||||
|
||||
bool Random_SanityCheck()
|
||||
{
|
||||
uint64_t start = GetPerformanceCounter();
|
||||
|
||||
/* This does not measure the quality of randomness, but it does test that
|
||||
* OSRandom() overwrites all 32 bytes of the output given a maximum
|
||||
* number of tries.
|
||||
*/
|
||||
static const ssize_t MAX_TRIES = 1024;
|
||||
uint8_t data[NUM_OS_RANDOM_BYTES];
|
||||
bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */
|
||||
int num_overwritten;
|
||||
int tries = 0;
|
||||
/* Loop until all bytes have been overwritten at least once, or max number tries reached */
|
||||
do {
|
||||
memset(data, 0, NUM_OS_RANDOM_BYTES);
|
||||
GetOSRand(data);
|
||||
for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
|
||||
overwritten[x] |= (data[x] != 0);
|
||||
}
|
||||
|
||||
num_overwritten = 0;
|
||||
for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
|
||||
if (overwritten[x]) {
|
||||
num_overwritten += 1;
|
||||
}
|
||||
}
|
||||
|
||||
tries += 1;
|
||||
} while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
|
||||
if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */
|
||||
|
||||
// Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
uint64_t stop = GetPerformanceCounter();
|
||||
if (stop == start) return false;
|
||||
|
||||
// We called GetPerformanceCounter. Use it as entropy.
|
||||
CSHA512 to_add;
|
||||
to_add.Write((const unsigned char*)&start, sizeof(start));
|
||||
to_add.Write((const unsigned char*)&stop, sizeof(stop));
|
||||
GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
|
||||
{
|
||||
if (!fDeterministic) {
|
||||
return;
|
||||
}
|
||||
uint256 seed;
|
||||
rng.SetKey(seed.begin(), 32);
|
||||
}
|
||||
|
||||
FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept
|
||||
{
|
||||
requires_seed = from.requires_seed;
|
||||
rng = from.rng;
|
||||
std::copy(std::begin(from.bytebuf), std::end(from.bytebuf), std::begin(bytebuf));
|
||||
bytebuf_size = from.bytebuf_size;
|
||||
bitbuf = from.bitbuf;
|
||||
bitbuf_size = from.bitbuf_size;
|
||||
from.requires_seed = true;
|
||||
from.bytebuf_size = 0;
|
||||
from.bitbuf_size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RandomInit()
|
||||
{
|
||||
// Invoke RNG code to trigger initialization (if not already performed)
|
||||
ProcRand(nullptr, 0, RNGLevel::FAST);
|
||||
|
||||
ReportHardwareRand();
|
||||
}
|
242
lib/bip158/src/random.h
Normal file
242
lib/bip158/src/random.h
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_RANDOM_H
|
||||
#define BITCOIN_RANDOM_H
|
||||
|
||||
#include <crypto/chacha20.h>
|
||||
#include <crypto/common.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
* Overall design of the RNG and entropy sources.
|
||||
*
|
||||
* We maintain a single global 256-bit RNG state for all high-quality randomness.
|
||||
* The following (classes of) functions interact with that state by mixing in new
|
||||
* entropy, and optionally extracting random output from it:
|
||||
*
|
||||
* - The GetRand*() class of functions, as well as construction of FastRandomContext objects,
|
||||
* perform 'fast' seeding, consisting of mixing in:
|
||||
* - A stack pointer (indirectly committing to calling thread and call stack)
|
||||
* - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise)
|
||||
* - 64 bits from the hardware RNG (rdrand) when available.
|
||||
* These entropy sources are very fast, and only designed to protect against situations
|
||||
* where a VM state restore/copy results in multiple systems with the same randomness.
|
||||
* FastRandomContext on the other hand does not protect against this once created, but
|
||||
* is even faster (and acceptable to use inside tight loops).
|
||||
*
|
||||
* - The GetStrongRand*() class of function perform 'slow' seeding, including everything
|
||||
* that fast seeding includes, but additionally:
|
||||
* - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if
|
||||
* this entropy source fails.
|
||||
* - Bytes from OpenSSL's RNG (which itself may be seeded from various sources)
|
||||
* - Another high-precision timestamp (indirectly committing to a benchmark of all the
|
||||
* previous sources).
|
||||
* These entropy sources are slower, but designed to make sure the RNG state contains
|
||||
* fresh data that is unpredictable to attackers.
|
||||
*
|
||||
* - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally:
|
||||
* - A high-precision timestamp before and after sleeping 1ms.
|
||||
* - (On Windows) Once every 10 minutes, performance monitoring data from the OS.
|
||||
- - Once every minute, strengthen the entropy for 10 ms using repeated SHA512.
|
||||
* These just exploit the fact the system is idle to improve the quality of the RNG
|
||||
* slightly.
|
||||
*
|
||||
* On first use of the RNG (regardless of what function is called first), all entropy
|
||||
* sources used in the 'slow' seeder are included, but also:
|
||||
* - 256 bits from the hardware RNG (rdseed or rdrand) when available.
|
||||
* - (On Windows) Performance monitoring data from the OS.
|
||||
* - (On Windows) Through OpenSSL, the screen contents.
|
||||
* - Strengthen the entropy for 100 ms using repeated SHA512.
|
||||
*
|
||||
* When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
|
||||
* (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
|
||||
* become the new RNG state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate random data via the internal PRNG.
|
||||
*
|
||||
* These functions are designed to be fast (sub microsecond), but do not necessarily
|
||||
* meaningfully add entropy to the PRNG state.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
void GetRandBytes(unsigned char* buf, int num) noexcept;
|
||||
uint64_t GetRand(uint64_t nMax) noexcept;
|
||||
int GetRandInt(int nMax) noexcept;
|
||||
uint256 GetRandHash() noexcept;
|
||||
|
||||
/**
|
||||
* Gather entropy from various sources, feed it into the internal PRNG, and
|
||||
* generate random data using it.
|
||||
*
|
||||
* This function will cause failure whenever the OS RNG fails.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
|
||||
|
||||
/**
|
||||
* Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
void RandAddSeedSleep();
|
||||
|
||||
/**
|
||||
* Fast randomness source. This is seeded once with secure random data, but
|
||||
* is completely deterministic and does not gather more entropy after that.
|
||||
*
|
||||
* This class is not thread-safe.
|
||||
*/
|
||||
class FastRandomContext {
|
||||
private:
|
||||
bool requires_seed;
|
||||
ChaCha20 rng;
|
||||
|
||||
unsigned char bytebuf[64];
|
||||
int bytebuf_size;
|
||||
|
||||
uint64_t bitbuf;
|
||||
int bitbuf_size;
|
||||
|
||||
void RandomSeed();
|
||||
|
||||
void FillByteBuffer()
|
||||
{
|
||||
if (requires_seed) {
|
||||
RandomSeed();
|
||||
}
|
||||
rng.Keystream(bytebuf, sizeof(bytebuf));
|
||||
bytebuf_size = sizeof(bytebuf);
|
||||
}
|
||||
|
||||
void FillBitBuffer()
|
||||
{
|
||||
bitbuf = rand64();
|
||||
bitbuf_size = 64;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit FastRandomContext(bool fDeterministic = false) noexcept;
|
||||
|
||||
/** Initialize with explicit seed (only for testing) */
|
||||
explicit FastRandomContext(const uint256& seed) noexcept;
|
||||
|
||||
// Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded).
|
||||
FastRandomContext(const FastRandomContext&) = delete;
|
||||
FastRandomContext(FastRandomContext&&) = delete;
|
||||
FastRandomContext& operator=(const FastRandomContext&) = delete;
|
||||
|
||||
/** Move a FastRandomContext. If the original one is used again, it will be reseeded. */
|
||||
FastRandomContext& operator=(FastRandomContext&& from) noexcept;
|
||||
|
||||
/** Generate a random 64-bit integer. */
|
||||
uint64_t rand64() noexcept
|
||||
{
|
||||
if (bytebuf_size < 8) FillByteBuffer();
|
||||
uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
|
||||
bytebuf_size -= 8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Generate a random (bits)-bit integer. */
|
||||
uint64_t randbits(int bits) noexcept {
|
||||
if (bits == 0) {
|
||||
return 0;
|
||||
} else if (bits > 32) {
|
||||
return rand64() >> (64 - bits);
|
||||
} else {
|
||||
if (bitbuf_size < bits) FillBitBuffer();
|
||||
uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
|
||||
bitbuf >>= bits;
|
||||
bitbuf_size -= bits;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate a random integer in the range [0..range). */
|
||||
uint64_t randrange(uint64_t range) noexcept
|
||||
{
|
||||
--range;
|
||||
int bits = CountBits(range);
|
||||
while (true) {
|
||||
uint64_t ret = randbits(bits);
|
||||
if (ret <= range) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate random bytes. */
|
||||
std::vector<unsigned char> randbytes(size_t len);
|
||||
|
||||
/** Generate a random 32-bit integer. */
|
||||
uint32_t rand32() noexcept { return randbits(32); }
|
||||
|
||||
/** generate a random uint256. */
|
||||
uint256 rand256() noexcept;
|
||||
|
||||
/** Generate a random boolean. */
|
||||
bool randbool() noexcept { return randbits(1); }
|
||||
|
||||
// Compatibility with the C++11 UniformRandomBitGenerator concept
|
||||
typedef uint64_t result_type;
|
||||
static constexpr uint64_t min() { return 0; }
|
||||
static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); }
|
||||
inline uint64_t operator()() noexcept { return rand64(); }
|
||||
};
|
||||
|
||||
/** More efficient than using std::shuffle on a FastRandomContext.
|
||||
*
|
||||
* This is more efficient as std::shuffle will consume entropy in groups of
|
||||
* 64 bits at the time and throw away most.
|
||||
*
|
||||
* This also works around a bug in libstdc++ std::shuffle that may cause
|
||||
* type::operator=(type&&) to be invoked on itself, which the library's
|
||||
* debug mode detects and panics on. This is a known issue, see
|
||||
* https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle
|
||||
*/
|
||||
template<typename I, typename R>
|
||||
void Shuffle(I first, I last, R&& rng)
|
||||
{
|
||||
while (first != last) {
|
||||
size_t j = rng.randrange(last - first);
|
||||
if (j) {
|
||||
using std::swap;
|
||||
swap(*first, *(first + j));
|
||||
}
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
/* Number of random bytes returned by GetOSRand.
|
||||
* When changing this constant make sure to change all call sites, and make
|
||||
* sure that the underlying OS APIs for all platforms support the number.
|
||||
* (many cap out at 256 bytes).
|
||||
*/
|
||||
static const int NUM_OS_RANDOM_BYTES = 32;
|
||||
|
||||
/** Get 32 bytes of system entropy. Do not use this in application code: use
|
||||
* GetStrongRandBytes instead.
|
||||
*/
|
||||
void GetOSRand(unsigned char *ent32);
|
||||
|
||||
/** Check that OS randomness is available and returning the requested number
|
||||
* of bytes.
|
||||
*/
|
||||
bool Random_SanityCheck();
|
||||
|
||||
/**
|
||||
* Initialize global RNG state and log any CPU features that are used.
|
||||
*
|
||||
* Calling this function is optional. RNG state will be initialized when first
|
||||
* needed if it is not called.
|
||||
*/
|
||||
void RandomInit();
|
||||
|
||||
#endif // BITCOIN_RANDOM_H
|
328
lib/bip158/src/script/script.cpp
Normal file
328
lib/bip158/src/script/script.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <script/script.h>
|
||||
|
||||
#include <util/strencodings.h>
|
||||
|
||||
const char* GetOpName(opcodetype opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
// push value
|
||||
case OP_0 : return "0";
|
||||
case OP_PUSHDATA1 : return "OP_PUSHDATA1";
|
||||
case OP_PUSHDATA2 : return "OP_PUSHDATA2";
|
||||
case OP_PUSHDATA4 : return "OP_PUSHDATA4";
|
||||
case OP_1NEGATE : return "-1";
|
||||
case OP_RESERVED : return "OP_RESERVED";
|
||||
case OP_1 : return "1";
|
||||
case OP_2 : return "2";
|
||||
case OP_3 : return "3";
|
||||
case OP_4 : return "4";
|
||||
case OP_5 : return "5";
|
||||
case OP_6 : return "6";
|
||||
case OP_7 : return "7";
|
||||
case OP_8 : return "8";
|
||||
case OP_9 : return "9";
|
||||
case OP_10 : return "10";
|
||||
case OP_11 : return "11";
|
||||
case OP_12 : return "12";
|
||||
case OP_13 : return "13";
|
||||
case OP_14 : return "14";
|
||||
case OP_15 : return "15";
|
||||
case OP_16 : return "16";
|
||||
|
||||
// control
|
||||
case OP_NOP : return "OP_NOP";
|
||||
case OP_VER : return "OP_VER";
|
||||
case OP_IF : return "OP_IF";
|
||||
case OP_NOTIF : return "OP_NOTIF";
|
||||
case OP_VERIF : return "OP_VERIF";
|
||||
case OP_VERNOTIF : return "OP_VERNOTIF";
|
||||
case OP_ELSE : return "OP_ELSE";
|
||||
case OP_ENDIF : return "OP_ENDIF";
|
||||
case OP_VERIFY : return "OP_VERIFY";
|
||||
case OP_RETURN : return "OP_RETURN";
|
||||
|
||||
// stack ops
|
||||
case OP_TOALTSTACK : return "OP_TOALTSTACK";
|
||||
case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
|
||||
case OP_2DROP : return "OP_2DROP";
|
||||
case OP_2DUP : return "OP_2DUP";
|
||||
case OP_3DUP : return "OP_3DUP";
|
||||
case OP_2OVER : return "OP_2OVER";
|
||||
case OP_2ROT : return "OP_2ROT";
|
||||
case OP_2SWAP : return "OP_2SWAP";
|
||||
case OP_IFDUP : return "OP_IFDUP";
|
||||
case OP_DEPTH : return "OP_DEPTH";
|
||||
case OP_DROP : return "OP_DROP";
|
||||
case OP_DUP : return "OP_DUP";
|
||||
case OP_NIP : return "OP_NIP";
|
||||
case OP_OVER : return "OP_OVER";
|
||||
case OP_PICK : return "OP_PICK";
|
||||
case OP_ROLL : return "OP_ROLL";
|
||||
case OP_ROT : return "OP_ROT";
|
||||
case OP_SWAP : return "OP_SWAP";
|
||||
case OP_TUCK : return "OP_TUCK";
|
||||
|
||||
// splice ops
|
||||
case OP_CAT : return "OP_CAT";
|
||||
case OP_SUBSTR : return "OP_SUBSTR";
|
||||
case OP_LEFT : return "OP_LEFT";
|
||||
case OP_RIGHT : return "OP_RIGHT";
|
||||
case OP_SIZE : return "OP_SIZE";
|
||||
|
||||
// bit logic
|
||||
case OP_INVERT : return "OP_INVERT";
|
||||
case OP_AND : return "OP_AND";
|
||||
case OP_OR : return "OP_OR";
|
||||
case OP_XOR : return "OP_XOR";
|
||||
case OP_EQUAL : return "OP_EQUAL";
|
||||
case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
|
||||
case OP_RESERVED1 : return "OP_RESERVED1";
|
||||
case OP_RESERVED2 : return "OP_RESERVED2";
|
||||
|
||||
// numeric
|
||||
case OP_1ADD : return "OP_1ADD";
|
||||
case OP_1SUB : return "OP_1SUB";
|
||||
case OP_2MUL : return "OP_2MUL";
|
||||
case OP_2DIV : return "OP_2DIV";
|
||||
case OP_NEGATE : return "OP_NEGATE";
|
||||
case OP_ABS : return "OP_ABS";
|
||||
case OP_NOT : return "OP_NOT";
|
||||
case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
|
||||
case OP_ADD : return "OP_ADD";
|
||||
case OP_SUB : return "OP_SUB";
|
||||
case OP_MUL : return "OP_MUL";
|
||||
case OP_DIV : return "OP_DIV";
|
||||
case OP_MOD : return "OP_MOD";
|
||||
case OP_LSHIFT : return "OP_LSHIFT";
|
||||
case OP_RSHIFT : return "OP_RSHIFT";
|
||||
case OP_BOOLAND : return "OP_BOOLAND";
|
||||
case OP_BOOLOR : return "OP_BOOLOR";
|
||||
case OP_NUMEQUAL : return "OP_NUMEQUAL";
|
||||
case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
|
||||
case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
|
||||
case OP_LESSTHAN : return "OP_LESSTHAN";
|
||||
case OP_GREATERTHAN : return "OP_GREATERTHAN";
|
||||
case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
|
||||
case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
|
||||
case OP_MIN : return "OP_MIN";
|
||||
case OP_MAX : return "OP_MAX";
|
||||
case OP_WITHIN : return "OP_WITHIN";
|
||||
|
||||
// crypto
|
||||
case OP_RIPEMD160 : return "OP_RIPEMD160";
|
||||
case OP_SHA1 : return "OP_SHA1";
|
||||
case OP_SHA256 : return "OP_SHA256";
|
||||
case OP_HASH160 : return "OP_HASH160";
|
||||
case OP_HASH256 : return "OP_HASH256";
|
||||
case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
|
||||
case OP_CHECKSIG : return "OP_CHECKSIG";
|
||||
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
|
||||
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
|
||||
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
|
||||
|
||||
// expansion
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
|
||||
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
|
||||
case OP_NOP4 : return "OP_NOP4";
|
||||
case OP_NOP5 : return "OP_NOP5";
|
||||
case OP_NOP6 : return "OP_NOP6";
|
||||
case OP_NOP7 : return "OP_NOP7";
|
||||
case OP_NOP8 : return "OP_NOP8";
|
||||
case OP_NOP9 : return "OP_NOP9";
|
||||
case OP_NOP10 : return "OP_NOP10";
|
||||
|
||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||
|
||||
default:
|
||||
return "OP_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CScript::GetSigOpCount(bool fAccurate) const
|
||||
{
|
||||
unsigned int n = 0;
|
||||
const_iterator pc = begin();
|
||||
opcodetype lastOpcode = OP_INVALIDOPCODE;
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
break;
|
||||
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
|
||||
n++;
|
||||
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
|
||||
{
|
||||
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
|
||||
n += DecodeOP_N(lastOpcode);
|
||||
else
|
||||
n += MAX_PUBKEYS_PER_MULTISIG;
|
||||
}
|
||||
lastOpcode = opcode;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
||||
{
|
||||
if (!IsPayToScriptHash())
|
||||
return GetSigOpCount(true);
|
||||
|
||||
// This is a pay-to-script-hash scriptPubKey;
|
||||
// get the last item that the scriptSig
|
||||
// pushes onto the stack:
|
||||
const_iterator pc = scriptSig.begin();
|
||||
std::vector<unsigned char> vData;
|
||||
while (pc < scriptSig.end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!scriptSig.GetOp(pc, opcode, vData))
|
||||
return 0;
|
||||
if (opcode > OP_16)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ... and return its opcount:
|
||||
CScript subscript(vData.begin(), vData.end());
|
||||
return subscript.GetSigOpCount(true);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
return (this->size() == 23 &&
|
||||
(*this)[0] == OP_HASH160 &&
|
||||
(*this)[1] == 0x14 &&
|
||||
(*this)[22] == OP_EQUAL);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToWitnessScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-witness-script-hash CScripts:
|
||||
return (this->size() == 34 &&
|
||||
(*this)[0] == OP_0 &&
|
||||
(*this)[1] == 0x20);
|
||||
}
|
||||
|
||||
// A witness program is any valid CScript that consists of a 1-byte push opcode
|
||||
// followed by a data push between 2 and 40 bytes.
|
||||
bool CScript::IsWitnessProgram(int& version, std::vector<unsigned char>& program) const
|
||||
{
|
||||
if (this->size() < 4 || this->size() > 42) {
|
||||
return false;
|
||||
}
|
||||
if ((*this)[0] != OP_0 && ((*this)[0] < OP_1 || (*this)[0] > OP_16)) {
|
||||
return false;
|
||||
}
|
||||
if ((size_t)((*this)[1] + 2) == this->size()) {
|
||||
version = DecodeOP_N((opcodetype)(*this)[0]);
|
||||
program = std::vector<unsigned char>(this->begin() + 2, this->end());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly(const_iterator pc) const
|
||||
{
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
return false;
|
||||
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
|
||||
// push-type opcode, however execution of OP_RESERVED fails, so
|
||||
// it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
|
||||
// the P2SH special validation code being executed.
|
||||
if (opcode > OP_16)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly() const
|
||||
{
|
||||
return this->IsPushOnly(begin());
|
||||
}
|
||||
|
||||
std::string CScriptWitness::ToString() const
|
||||
{
|
||||
std::string ret = "CScriptWitness(";
|
||||
for (unsigned int i = 0; i < stack.size(); i++) {
|
||||
if (i) {
|
||||
ret += ", ";
|
||||
}
|
||||
ret += HexStr(stack[i]);
|
||||
}
|
||||
return ret + ")";
|
||||
}
|
||||
|
||||
bool CScript::HasValidOps() const
|
||||
{
|
||||
CScript::const_iterator it = begin();
|
||||
while (it < end()) {
|
||||
opcodetype opcode;
|
||||
std::vector<unsigned char> item;
|
||||
if (!GetOp(it, opcode, item) || opcode > MAX_OPCODE || item.size() > MAX_SCRIPT_ELEMENT_SIZE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet)
|
||||
{
|
||||
opcodeRet = OP_INVALIDOPCODE;
|
||||
if (pvchRet)
|
||||
pvchRet->clear();
|
||||
if (pc >= end)
|
||||
return false;
|
||||
|
||||
// Read instruction
|
||||
if (end - pc < 1)
|
||||
return false;
|
||||
unsigned int opcode = *pc++;
|
||||
|
||||
// Immediate operand
|
||||
if (opcode <= OP_PUSHDATA4)
|
||||
{
|
||||
unsigned int nSize = 0;
|
||||
if (opcode < OP_PUSHDATA1)
|
||||
{
|
||||
nSize = opcode;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA1)
|
||||
{
|
||||
if (end - pc < 1)
|
||||
return false;
|
||||
nSize = *pc++;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA2)
|
||||
{
|
||||
if (end - pc < 2)
|
||||
return false;
|
||||
nSize = ReadLE16(&pc[0]);
|
||||
pc += 2;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA4)
|
||||
{
|
||||
if (end - pc < 4)
|
||||
return false;
|
||||
nSize = ReadLE32(&pc[0]);
|
||||
pc += 4;
|
||||
}
|
||||
if (end - pc < 0 || (unsigned int)(end - pc) < nSize)
|
||||
return false;
|
||||
if (pvchRet)
|
||||
pvchRet->assign(pc, pc + nSize);
|
||||
pc += nSize;
|
||||
}
|
||||
|
||||
opcodeRet = static_cast<opcodetype>(opcode);
|
||||
return true;
|
||||
}
|
586
lib/bip158/src/script/script.h
Normal file
586
lib/bip158/src/script/script.h
Normal file
@ -0,0 +1,586 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_SCRIPT_H
|
||||
#define BITCOIN_SCRIPT_SCRIPT_H
|
||||
|
||||
#include <crypto/common.h>
|
||||
#include <prevector.h>
|
||||
#include <serialize.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Maximum number of bytes pushable to the stack
|
||||
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
|
||||
|
||||
// Maximum number of non-push operations per script
|
||||
static const int MAX_OPS_PER_SCRIPT = 201;
|
||||
|
||||
// Maximum number of public keys per multisig
|
||||
static const int MAX_PUBKEYS_PER_MULTISIG = 20;
|
||||
|
||||
// Maximum script length in bytes
|
||||
static const int MAX_SCRIPT_SIZE = 10000;
|
||||
|
||||
// Maximum number of values on script interpreter stack
|
||||
static const int MAX_STACK_SIZE = 1000;
|
||||
|
||||
// Threshold for nLockTime: below this value it is interpreted as block number,
|
||||
// otherwise as UNIX timestamp.
|
||||
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
||||
|
||||
// Maximum nLockTime. Since a lock time indicates the last invalid timestamp, a
|
||||
// transaction with this lock time will never be valid unless lock time
|
||||
// checking is disabled (by setting all input sequence numbers to
|
||||
// SEQUENCE_FINAL).
|
||||
static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU;
|
||||
|
||||
template <typename T>
|
||||
std::vector<unsigned char> ToByteVector(const T& in)
|
||||
{
|
||||
return std::vector<unsigned char>(in.begin(), in.end());
|
||||
}
|
||||
|
||||
/** Script opcodes */
|
||||
enum opcodetype
|
||||
{
|
||||
// push value
|
||||
OP_0 = 0x00,
|
||||
OP_FALSE = OP_0,
|
||||
OP_PUSHDATA1 = 0x4c,
|
||||
OP_PUSHDATA2 = 0x4d,
|
||||
OP_PUSHDATA4 = 0x4e,
|
||||
OP_1NEGATE = 0x4f,
|
||||
OP_RESERVED = 0x50,
|
||||
OP_1 = 0x51,
|
||||
OP_TRUE=OP_1,
|
||||
OP_2 = 0x52,
|
||||
OP_3 = 0x53,
|
||||
OP_4 = 0x54,
|
||||
OP_5 = 0x55,
|
||||
OP_6 = 0x56,
|
||||
OP_7 = 0x57,
|
||||
OP_8 = 0x58,
|
||||
OP_9 = 0x59,
|
||||
OP_10 = 0x5a,
|
||||
OP_11 = 0x5b,
|
||||
OP_12 = 0x5c,
|
||||
OP_13 = 0x5d,
|
||||
OP_14 = 0x5e,
|
||||
OP_15 = 0x5f,
|
||||
OP_16 = 0x60,
|
||||
|
||||
// control
|
||||
OP_NOP = 0x61,
|
||||
OP_VER = 0x62,
|
||||
OP_IF = 0x63,
|
||||
OP_NOTIF = 0x64,
|
||||
OP_VERIF = 0x65,
|
||||
OP_VERNOTIF = 0x66,
|
||||
OP_ELSE = 0x67,
|
||||
OP_ENDIF = 0x68,
|
||||
OP_VERIFY = 0x69,
|
||||
OP_RETURN = 0x6a,
|
||||
|
||||
// stack ops
|
||||
OP_TOALTSTACK = 0x6b,
|
||||
OP_FROMALTSTACK = 0x6c,
|
||||
OP_2DROP = 0x6d,
|
||||
OP_2DUP = 0x6e,
|
||||
OP_3DUP = 0x6f,
|
||||
OP_2OVER = 0x70,
|
||||
OP_2ROT = 0x71,
|
||||
OP_2SWAP = 0x72,
|
||||
OP_IFDUP = 0x73,
|
||||
OP_DEPTH = 0x74,
|
||||
OP_DROP = 0x75,
|
||||
OP_DUP = 0x76,
|
||||
OP_NIP = 0x77,
|
||||
OP_OVER = 0x78,
|
||||
OP_PICK = 0x79,
|
||||
OP_ROLL = 0x7a,
|
||||
OP_ROT = 0x7b,
|
||||
OP_SWAP = 0x7c,
|
||||
OP_TUCK = 0x7d,
|
||||
|
||||
// splice ops
|
||||
OP_CAT = 0x7e,
|
||||
OP_SUBSTR = 0x7f,
|
||||
OP_LEFT = 0x80,
|
||||
OP_RIGHT = 0x81,
|
||||
OP_SIZE = 0x82,
|
||||
|
||||
// bit logic
|
||||
OP_INVERT = 0x83,
|
||||
OP_AND = 0x84,
|
||||
OP_OR = 0x85,
|
||||
OP_XOR = 0x86,
|
||||
OP_EQUAL = 0x87,
|
||||
OP_EQUALVERIFY = 0x88,
|
||||
OP_RESERVED1 = 0x89,
|
||||
OP_RESERVED2 = 0x8a,
|
||||
|
||||
// numeric
|
||||
OP_1ADD = 0x8b,
|
||||
OP_1SUB = 0x8c,
|
||||
OP_2MUL = 0x8d,
|
||||
OP_2DIV = 0x8e,
|
||||
OP_NEGATE = 0x8f,
|
||||
OP_ABS = 0x90,
|
||||
OP_NOT = 0x91,
|
||||
OP_0NOTEQUAL = 0x92,
|
||||
|
||||
OP_ADD = 0x93,
|
||||
OP_SUB = 0x94,
|
||||
OP_MUL = 0x95,
|
||||
OP_DIV = 0x96,
|
||||
OP_MOD = 0x97,
|
||||
OP_LSHIFT = 0x98,
|
||||
OP_RSHIFT = 0x99,
|
||||
|
||||
OP_BOOLAND = 0x9a,
|
||||
OP_BOOLOR = 0x9b,
|
||||
OP_NUMEQUAL = 0x9c,
|
||||
OP_NUMEQUALVERIFY = 0x9d,
|
||||
OP_NUMNOTEQUAL = 0x9e,
|
||||
OP_LESSTHAN = 0x9f,
|
||||
OP_GREATERTHAN = 0xa0,
|
||||
OP_LESSTHANOREQUAL = 0xa1,
|
||||
OP_GREATERTHANOREQUAL = 0xa2,
|
||||
OP_MIN = 0xa3,
|
||||
OP_MAX = 0xa4,
|
||||
|
||||
OP_WITHIN = 0xa5,
|
||||
|
||||
// crypto
|
||||
OP_RIPEMD160 = 0xa6,
|
||||
OP_SHA1 = 0xa7,
|
||||
OP_SHA256 = 0xa8,
|
||||
OP_HASH160 = 0xa9,
|
||||
OP_HASH256 = 0xaa,
|
||||
OP_CODESEPARATOR = 0xab,
|
||||
OP_CHECKSIG = 0xac,
|
||||
OP_CHECKSIGVERIFY = 0xad,
|
||||
OP_CHECKMULTISIG = 0xae,
|
||||
OP_CHECKMULTISIGVERIFY = 0xaf,
|
||||
|
||||
// expansion
|
||||
OP_NOP1 = 0xb0,
|
||||
OP_CHECKLOCKTIMEVERIFY = 0xb1,
|
||||
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_CHECKSEQUENCEVERIFY = 0xb2,
|
||||
OP_NOP3 = OP_CHECKSEQUENCEVERIFY,
|
||||
OP_NOP4 = 0xb3,
|
||||
OP_NOP5 = 0xb4,
|
||||
OP_NOP6 = 0xb5,
|
||||
OP_NOP7 = 0xb6,
|
||||
OP_NOP8 = 0xb7,
|
||||
OP_NOP9 = 0xb8,
|
||||
OP_NOP10 = 0xb9,
|
||||
|
||||
OP_INVALIDOPCODE = 0xff,
|
||||
};
|
||||
|
||||
// Maximum value that an opcode can be
|
||||
static const unsigned int MAX_OPCODE = OP_NOP10;
|
||||
|
||||
const char* GetOpName(opcodetype opcode);
|
||||
|
||||
class scriptnum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
class CScriptNum
|
||||
{
|
||||
/**
|
||||
* Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
|
||||
* The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
|
||||
* but results may overflow (and are valid as long as they are not used in a subsequent
|
||||
* numeric operation). CScriptNum enforces those semantics by storing results as
|
||||
* an int64 and allowing out-of-range values to be returned as a vector of bytes but
|
||||
* throwing an exception if arithmetic is done or the result is interpreted as an integer.
|
||||
*/
|
||||
public:
|
||||
|
||||
explicit CScriptNum(const int64_t& n)
|
||||
{
|
||||
m_value = n;
|
||||
}
|
||||
|
||||
static const size_t nDefaultMaxNumSize = 4;
|
||||
|
||||
explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal,
|
||||
const size_t nMaxNumSize = nDefaultMaxNumSize)
|
||||
{
|
||||
if (vch.size() > nMaxNumSize) {
|
||||
throw scriptnum_error("script number overflow");
|
||||
}
|
||||
if (fRequireMinimal && vch.size() > 0) {
|
||||
// Check that the number is encoded with the minimum possible
|
||||
// number of bytes.
|
||||
//
|
||||
// If the most-significant-byte - excluding the sign bit - is zero
|
||||
// then we're not minimal. Note how this test also rejects the
|
||||
// negative-zero encoding, 0x80.
|
||||
if ((vch.back() & 0x7f) == 0) {
|
||||
// One exception: if there's more than one byte and the most
|
||||
// significant bit of the second-most-significant-byte is set
|
||||
// it would conflict with the sign bit. An example of this case
|
||||
// is +-255, which encode to 0xff00 and 0xff80 respectively.
|
||||
// (big-endian).
|
||||
if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
|
||||
throw scriptnum_error("non-minimally encoded script number");
|
||||
}
|
||||
}
|
||||
}
|
||||
m_value = set_vch(vch);
|
||||
}
|
||||
|
||||
inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
|
||||
inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
|
||||
inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
|
||||
inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
|
||||
inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
|
||||
inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
|
||||
|
||||
inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }
|
||||
inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }
|
||||
inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }
|
||||
inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }
|
||||
inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }
|
||||
inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}
|
||||
inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}
|
||||
inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }
|
||||
inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }
|
||||
|
||||
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
|
||||
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator&( const int64_t& rhs) const { return CScriptNum(m_value & rhs);}
|
||||
inline CScriptNum operator&( const CScriptNum& rhs) const { return operator&(rhs.m_value); }
|
||||
|
||||
inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator-() const
|
||||
{
|
||||
assert(m_value != std::numeric_limits<int64_t>::min());
|
||||
return CScriptNum(-m_value);
|
||||
}
|
||||
|
||||
inline CScriptNum& operator=( const int64_t& rhs)
|
||||
{
|
||||
m_value = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator+=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
|
||||
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
|
||||
m_value += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator-=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
|
||||
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
|
||||
m_value -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator&=( const int64_t& rhs)
|
||||
{
|
||||
m_value &= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int getint() const
|
||||
{
|
||||
if (m_value > std::numeric_limits<int>::max())
|
||||
return std::numeric_limits<int>::max();
|
||||
else if (m_value < std::numeric_limits<int>::min())
|
||||
return std::numeric_limits<int>::min();
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getvch() const
|
||||
{
|
||||
return serialize(m_value);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> serialize(const int64_t& value)
|
||||
{
|
||||
if(value == 0)
|
||||
return std::vector<unsigned char>();
|
||||
|
||||
std::vector<unsigned char> result;
|
||||
const bool neg = value < 0;
|
||||
uint64_t absvalue = neg ? -value : value;
|
||||
|
||||
while(absvalue)
|
||||
{
|
||||
result.push_back(absvalue & 0xff);
|
||||
absvalue >>= 8;
|
||||
}
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is positive, push a
|
||||
// new zero-byte to make the significant byte < 0x80 again.
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is negative, push a
|
||||
// new 0x80 byte that will be popped off when converting to an integral.
|
||||
|
||||
// - If the most significant byte is < 0x80 and the value is negative, add
|
||||
// 0x80 to it, since it will be subtracted and interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
if (result.back() & 0x80)
|
||||
result.push_back(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result.back() |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static int64_t set_vch(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.empty())
|
||||
return 0;
|
||||
|
||||
int64_t result = 0;
|
||||
for (size_t i = 0; i != vch.size(); ++i)
|
||||
result |= static_cast<int64_t>(vch[i]) << 8*i;
|
||||
|
||||
// If the input vector's most significant byte is 0x80, remove it from
|
||||
// the result's msb and return a negative.
|
||||
if (vch.back() & 0x80)
|
||||
return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t m_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* We use a prevector for the script to reduce the considerable memory overhead
|
||||
* of vectors in cases where they normally contain a small number of small elements.
|
||||
* Tests in October 2015 showed use of this reduced dbcache memory usage by 23%
|
||||
* and made an initial sync 13% faster.
|
||||
*/
|
||||
typedef prevector<28, unsigned char> CScriptBase;
|
||||
|
||||
bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet);
|
||||
|
||||
/** Serialized script, used inside transaction inputs and outputs */
|
||||
class CScript : public CScriptBase
|
||||
{
|
||||
protected:
|
||||
CScript& push_int64(int64_t n)
|
||||
{
|
||||
if (n == -1 || (n >= 1 && n <= 16))
|
||||
{
|
||||
push_back(n + (OP_1 - 1));
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
push_back(OP_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*this << CScriptNum::serialize(n);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
CScript() { }
|
||||
CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { }
|
||||
CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { }
|
||||
CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITEAS(CScriptBase, *this);
|
||||
}
|
||||
|
||||
CScript& operator+=(const CScript& b)
|
||||
{
|
||||
reserve(size() + b.size());
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CScript operator+(const CScript& a, const CScript& b)
|
||||
{
|
||||
CScript ret = a;
|
||||
ret += b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CScript(int64_t b) { operator<<(b); }
|
||||
|
||||
explicit CScript(opcodetype b) { operator<<(b); }
|
||||
explicit CScript(const CScriptNum& b) { operator<<(b); }
|
||||
// delete non-existent constructor to defend against future introduction
|
||||
// e.g. via prevector
|
||||
explicit CScript(const std::vector<unsigned char>& b) = delete;
|
||||
|
||||
|
||||
CScript& operator<<(int64_t b) { return push_int64(b); }
|
||||
|
||||
CScript& operator<<(opcodetype opcode)
|
||||
{
|
||||
if (opcode < 0 || opcode > 0xff)
|
||||
throw std::runtime_error("CScript::operator<<(): invalid opcode");
|
||||
insert(end(), (unsigned char)opcode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CScriptNum& b)
|
||||
{
|
||||
*this << b.getvch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const std::vector<unsigned char>& b)
|
||||
{
|
||||
if (b.size() < OP_PUSHDATA1)
|
||||
{
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA1);
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xffff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA2);
|
||||
uint8_t _data[2];
|
||||
WriteLE16(_data, b.size());
|
||||
insert(end(), _data, _data + sizeof(_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
insert(end(), OP_PUSHDATA4);
|
||||
uint8_t _data[4];
|
||||
WriteLE32(_data, b.size());
|
||||
insert(end(), _data, _data + sizeof(_data));
|
||||
}
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CScript& b)
|
||||
{
|
||||
// I'm not sure if this should push the script or concatenate scripts.
|
||||
// If there's ever a use for pushing a script onto a script, delete this member fn
|
||||
assert(!"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
|
||||
{
|
||||
return GetScriptOp(pc, end(), opcodeRet, &vchRet);
|
||||
}
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
|
||||
{
|
||||
return GetScriptOp(pc, end(), opcodeRet, nullptr);
|
||||
}
|
||||
|
||||
|
||||
/** Encode/decode small integers: */
|
||||
static int DecodeOP_N(opcodetype opcode)
|
||||
{
|
||||
if (opcode == OP_0)
|
||||
return 0;
|
||||
assert(opcode >= OP_1 && opcode <= OP_16);
|
||||
return (int)opcode - (int)(OP_1 - 1);
|
||||
}
|
||||
static opcodetype EncodeOP_N(int n)
|
||||
{
|
||||
assert(n >= 0 && n <= 16);
|
||||
if (n == 0)
|
||||
return OP_0;
|
||||
return (opcodetype)(OP_1+n-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
|
||||
* as 20 sigops. With pay-to-script-hash, that changed:
|
||||
* CHECKMULTISIGs serialized in scriptSigs are
|
||||
* counted more accurately, assuming they are of the form
|
||||
* ... OP_N CHECKMULTISIG ...
|
||||
*/
|
||||
unsigned int GetSigOpCount(bool fAccurate) const;
|
||||
|
||||
/**
|
||||
* Accurately count sigOps, including sigOps in
|
||||
* pay-to-script-hash transactions:
|
||||
*/
|
||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||
|
||||
bool IsPayToScriptHash() const;
|
||||
bool IsPayToWitnessScriptHash() const;
|
||||
bool IsWitnessProgram(int& version, std::vector<unsigned char>& program) const;
|
||||
|
||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||
bool IsPushOnly(const_iterator pc) const;
|
||||
bool IsPushOnly() const;
|
||||
|
||||
/** Check if the script contains valid OP_CODES */
|
||||
bool HasValidOps() const;
|
||||
|
||||
/**
|
||||
* Returns whether the script is guaranteed to fail at execution,
|
||||
* regardless of the initial stack. This allows outputs to be pruned
|
||||
* instantly when entering the UTXO set.
|
||||
*/
|
||||
bool IsUnspendable() const
|
||||
{
|
||||
return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
// The default prevector::clear() does not release memory
|
||||
CScriptBase::clear();
|
||||
shrink_to_fit();
|
||||
}
|
||||
};
|
||||
|
||||
struct CScriptWitness
|
||||
{
|
||||
// Note that this encodes the data elements being pushed, rather than
|
||||
// encoding them as a CScript that pushes them.
|
||||
std::vector<std::vector<unsigned char> > stack;
|
||||
|
||||
// Some compilers complain without a default constructor
|
||||
CScriptWitness() { }
|
||||
|
||||
bool IsNull() const { return stack.empty(); }
|
||||
|
||||
void SetNull() { stack.clear(); stack.shrink_to_fit(); }
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SCRIPT_H
|
1005
lib/bip158/src/serialize.h
Normal file
1005
lib/bip158/src/serialize.h
Normal file
File diff suppressed because it is too large
Load Diff
60
lib/bip158/src/span.h
Normal file
60
lib/bip158/src/span.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SPAN_H
|
||||
#define BITCOIN_SPAN_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
|
||||
/** A Span is an object that can refer to a contiguous sequence of objects.
|
||||
*
|
||||
* It implements a subset of C++20's std::span.
|
||||
*/
|
||||
template<typename C>
|
||||
class Span
|
||||
{
|
||||
C* m_data;
|
||||
std::ptrdiff_t m_size;
|
||||
|
||||
public:
|
||||
constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
|
||||
constexpr Span(C* data, std::ptrdiff_t size) noexcept : m_data(data), m_size(size) {}
|
||||
constexpr Span(C* data, C* end) noexcept : m_data(data), m_size(end - data) {}
|
||||
|
||||
constexpr C* data() const noexcept { return m_data; }
|
||||
constexpr C* begin() const noexcept { return m_data; }
|
||||
constexpr C* end() const noexcept { return m_data + m_size; }
|
||||
constexpr std::ptrdiff_t size() const noexcept { return m_size; }
|
||||
constexpr C& operator[](std::ptrdiff_t pos) const noexcept { return m_data[pos]; }
|
||||
|
||||
constexpr Span<C> subspan(std::ptrdiff_t offset) const noexcept { return Span<C>(m_data + offset, m_size - offset); }
|
||||
constexpr Span<C> subspan(std::ptrdiff_t offset, std::ptrdiff_t count) const noexcept { return Span<C>(m_data + offset, count); }
|
||||
constexpr Span<C> first(std::ptrdiff_t count) const noexcept { return Span<C>(m_data, count); }
|
||||
constexpr Span<C> last(std::ptrdiff_t count) const noexcept { return Span<C>(m_data + m_size - count, count); }
|
||||
|
||||
friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }
|
||||
friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); }
|
||||
friend constexpr bool operator<(const Span& a, const Span& b) noexcept { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); }
|
||||
friend constexpr bool operator<=(const Span& a, const Span& b) noexcept { return !(b < a); }
|
||||
friend constexpr bool operator>(const Span& a, const Span& b) noexcept { return (b < a); }
|
||||
friend constexpr bool operator>=(const Span& a, const Span& b) noexcept { return !(a < b); }
|
||||
};
|
||||
|
||||
/** Create a span to a container exposing data() and size().
|
||||
*
|
||||
* This correctly deals with constness: the returned Span's element type will be
|
||||
* whatever data() returns a pointer to. If either the passed container is const,
|
||||
* or its element type is const, the resulting span will have a const element type.
|
||||
*
|
||||
* std::span will have a constructor that implements this functionality directly.
|
||||
*/
|
||||
template<typename A, int N>
|
||||
constexpr Span<A> MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
|
||||
|
||||
template<typename V>
|
||||
constexpr Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type> MakeSpan(V& v) { return Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type>(v.data(), v.size()); }
|
||||
|
||||
#endif
|
857
lib/bip158/src/streams.h
Normal file
857
lib/bip158/src/streams.h
Normal file
@ -0,0 +1,857 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_STREAMS_H
|
||||
#define BITCOIN_STREAMS_H
|
||||
|
||||
#include <support/allocators/zeroafterfree.h>
|
||||
#include <serialize.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <ios>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
template<typename Stream>
|
||||
class OverrideStream
|
||||
{
|
||||
Stream* stream;
|
||||
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
|
||||
public:
|
||||
OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
|
||||
|
||||
template<typename T>
|
||||
OverrideStream<Stream>& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
OverrideStream<Stream>& operator>>(T&& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
stream->write(pch, nSize);
|
||||
}
|
||||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
stream->read(pch, nSize);
|
||||
}
|
||||
|
||||
int GetVersion() const { return nVersion; }
|
||||
int GetType() const { return nType; }
|
||||
size_t size() const { return stream->size(); }
|
||||
};
|
||||
|
||||
/* Minimal stream for overwriting and/or appending to an existing byte vector
|
||||
*
|
||||
* The referenced vector will grow as necessary
|
||||
*/
|
||||
class CVectorWriter
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* @param[in] nTypeIn Serialization Type
|
||||
* @param[in] nVersionIn Serialization Version (including any flags)
|
||||
* @param[in] vchDataIn Referenced byte vector to overwrite/append
|
||||
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
|
||||
* grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
|
||||
*/
|
||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
|
||||
{
|
||||
if(nPos > vchData.size())
|
||||
vchData.resize(nPos);
|
||||
}
|
||||
/*
|
||||
* (other params same as above)
|
||||
* @param[in] args A list of items to serialize starting at nPosIn.
|
||||
*/
|
||||
template <typename... Args>
|
||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
|
||||
{
|
||||
::SerializeMany(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
assert(nPos <= vchData.size());
|
||||
size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
|
||||
if (nOverwrite) {
|
||||
memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
|
||||
}
|
||||
if (nOverwrite < nSize) {
|
||||
vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
|
||||
}
|
||||
nPos += nSize;
|
||||
}
|
||||
template<typename T>
|
||||
CVectorWriter& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
int GetVersion() const
|
||||
{
|
||||
return nVersion;
|
||||
}
|
||||
int GetType() const
|
||||
{
|
||||
return nType;
|
||||
}
|
||||
private:
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
std::vector<unsigned char>& vchData;
|
||||
size_t nPos;
|
||||
};
|
||||
|
||||
/** Minimal stream for reading from an existing vector by reference
|
||||
*/
|
||||
class VectorReader
|
||||
{
|
||||
private:
|
||||
const int m_type;
|
||||
const int m_version;
|
||||
const std::vector<unsigned char>& m_data;
|
||||
size_t m_pos = 0;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param[in] type Serialization Type
|
||||
* @param[in] version Serialization Version (including any flags)
|
||||
* @param[in] data Referenced byte vector to overwrite/append
|
||||
* @param[in] pos Starting position. Vector index where reads should start.
|
||||
*/
|
||||
VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
|
||||
: m_type(type), m_version(version), m_data(data), m_pos(pos)
|
||||
{
|
||||
if (m_pos > m_data.size()) {
|
||||
throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (other params same as above)
|
||||
* @param[in] args A list of items to deserialize starting at pos.
|
||||
*/
|
||||
template <typename... Args>
|
||||
VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
|
||||
Args&&... args)
|
||||
: VectorReader(type, version, data, pos)
|
||||
{
|
||||
::UnserializeMany(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
VectorReader& operator>>(T& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
int GetVersion() const { return m_version; }
|
||||
int GetType() const { return m_type; }
|
||||
|
||||
size_t size() const { return m_data.size() - m_pos; }
|
||||
bool empty() const { return m_data.size() == m_pos; }
|
||||
|
||||
void read(char* dst, size_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read from the beginning of the buffer
|
||||
size_t pos_next = m_pos + n;
|
||||
if (pos_next > m_data.size()) {
|
||||
throw std::ios_base::failure("VectorReader::read(): end of data");
|
||||
}
|
||||
memcpy(dst, m_data.data() + m_pos, n);
|
||||
m_pos = pos_next;
|
||||
}
|
||||
};
|
||||
|
||||
/** Double ended buffer combining vector and stream-like interfaces.
|
||||
*
|
||||
* >> and << read and write unformatted data using the above serialization templates.
|
||||
* Fills with data in linear time; some stringstream implementations take N^2 time.
|
||||
*/
|
||||
class CDataStream
|
||||
{
|
||||
protected:
|
||||
typedef CSerializeData vector_type;
|
||||
vector_type vch;
|
||||
unsigned int nReadPos;
|
||||
|
||||
int nType;
|
||||
int nVersion;
|
||||
public:
|
||||
|
||||
typedef vector_type::allocator_type allocator_type;
|
||||
typedef vector_type::size_type size_type;
|
||||
typedef vector_type::difference_type difference_type;
|
||||
typedef vector_type::reference reference;
|
||||
typedef vector_type::const_reference const_reference;
|
||||
typedef vector_type::value_type value_type;
|
||||
typedef vector_type::iterator iterator;
|
||||
typedef vector_type::const_iterator const_iterator;
|
||||
typedef vector_type::reverse_iterator reverse_iterator;
|
||||
|
||||
explicit CDataStream(int nTypeIn, int nVersionIn)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
::SerializeMany(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void Init(int nTypeIn, int nVersionIn)
|
||||
{
|
||||
nReadPos = 0;
|
||||
nType = nTypeIn;
|
||||
nVersion = nVersionIn;
|
||||
}
|
||||
|
||||
CDataStream& operator+=(const CDataStream& b)
|
||||
{
|
||||
vch.insert(vch.end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
|
||||
{
|
||||
CDataStream ret = a;
|
||||
ret += b;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
return (std::string(begin(), end()));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Vector subset
|
||||
//
|
||||
const_iterator begin() const { return vch.begin() + nReadPos; }
|
||||
iterator begin() { return vch.begin() + nReadPos; }
|
||||
const_iterator end() const { return vch.end(); }
|
||||
iterator end() { return vch.end(); }
|
||||
size_type size() const { return vch.size() - nReadPos; }
|
||||
bool empty() const { return vch.size() == nReadPos; }
|
||||
void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
|
||||
void reserve(size_type n) { vch.reserve(n + nReadPos); }
|
||||
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
|
||||
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
|
||||
void clear() { vch.clear(); nReadPos = 0; }
|
||||
iterator insert(iterator it, const char x=char()) { return vch.insert(it, x); }
|
||||
void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
|
||||
value_type* data() { return vch.data() + nReadPos; }
|
||||
const value_type* data() const { return vch.data() + nReadPos; }
|
||||
|
||||
void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
|
||||
{
|
||||
if (last == first) return;
|
||||
assert(last - first > 0);
|
||||
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
|
||||
{
|
||||
// special case for inserting at the front when there's room
|
||||
nReadPos -= (last - first);
|
||||
memcpy(&vch[nReadPos], &first[0], last - first);
|
||||
}
|
||||
else
|
||||
vch.insert(it, first, last);
|
||||
}
|
||||
|
||||
void insert(iterator it, const char* first, const char* last)
|
||||
{
|
||||
if (last == first) return;
|
||||
assert(last - first > 0);
|
||||
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
|
||||
{
|
||||
// special case for inserting at the front when there's room
|
||||
nReadPos -= (last - first);
|
||||
memcpy(&vch[nReadPos], &first[0], last - first);
|
||||
}
|
||||
else
|
||||
vch.insert(it, first, last);
|
||||
}
|
||||
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
if (it == vch.begin() + nReadPos)
|
||||
{
|
||||
// special case for erasing from the front
|
||||
if (++nReadPos >= vch.size())
|
||||
{
|
||||
// whenever we reach the end, we take the opportunity to clear the buffer
|
||||
nReadPos = 0;
|
||||
return vch.erase(vch.begin(), vch.end());
|
||||
}
|
||||
return vch.begin() + nReadPos;
|
||||
}
|
||||
else
|
||||
return vch.erase(it);
|
||||
}
|
||||
|
||||
iterator erase(iterator first, iterator last)
|
||||
{
|
||||
if (first == vch.begin() + nReadPos)
|
||||
{
|
||||
// special case for erasing from the front
|
||||
if (last == vch.end())
|
||||
{
|
||||
nReadPos = 0;
|
||||
return vch.erase(vch.begin(), vch.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
nReadPos = (last - vch.begin());
|
||||
return last;
|
||||
}
|
||||
}
|
||||
else
|
||||
return vch.erase(first, last);
|
||||
}
|
||||
|
||||
inline void Compact()
|
||||
{
|
||||
vch.erase(vch.begin(), vch.begin() + nReadPos);
|
||||
nReadPos = 0;
|
||||
}
|
||||
|
||||
bool Rewind(size_type n)
|
||||
{
|
||||
// Rewind by n characters if the buffer hasn't been compacted yet
|
||||
if (n > nReadPos)
|
||||
return false;
|
||||
nReadPos -= n;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Stream subset
|
||||
//
|
||||
bool eof() const { return size() == 0; }
|
||||
CDataStream* rdbuf() { return this; }
|
||||
int in_avail() const { return size(); }
|
||||
|
||||
void SetType(int n) { nType = n; }
|
||||
int GetType() const { return nType; }
|
||||
void SetVersion(int n) { nVersion = n; }
|
||||
int GetVersion() const { return nVersion; }
|
||||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
if (nSize == 0) return;
|
||||
|
||||
// Read from the beginning of the buffer
|
||||
unsigned int nReadPosNext = nReadPos + nSize;
|
||||
if (nReadPosNext > vch.size()) {
|
||||
throw std::ios_base::failure("CDataStream::read(): end of data");
|
||||
}
|
||||
memcpy(pch, &vch[nReadPos], nSize);
|
||||
if (nReadPosNext == vch.size())
|
||||
{
|
||||
nReadPos = 0;
|
||||
vch.clear();
|
||||
return;
|
||||
}
|
||||
nReadPos = nReadPosNext;
|
||||
}
|
||||
|
||||
void ignore(int nSize)
|
||||
{
|
||||
// Ignore from the beginning of the buffer
|
||||
if (nSize < 0) {
|
||||
throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
|
||||
}
|
||||
unsigned int nReadPosNext = nReadPos + nSize;
|
||||
if (nReadPosNext >= vch.size())
|
||||
{
|
||||
if (nReadPosNext > vch.size())
|
||||
throw std::ios_base::failure("CDataStream::ignore(): end of data");
|
||||
nReadPos = 0;
|
||||
vch.clear();
|
||||
return;
|
||||
}
|
||||
nReadPos = nReadPosNext;
|
||||
}
|
||||
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
// Write to the end of the buffer
|
||||
vch.insert(vch.end(), pch, pch + nSize);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
// Special case: stream << stream concatenates like stream += stream
|
||||
if (!vch.empty())
|
||||
s.write((char*)vch.data(), vch.size() * sizeof(value_type));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CDataStream& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CDataStream& operator>>(T&& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void GetAndClear(CSerializeData &d) {
|
||||
d.insert(d.end(), begin(), end());
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* XOR the contents of this stream with a certain key.
|
||||
*
|
||||
* @param[in] key The key used to XOR the data in this stream.
|
||||
*/
|
||||
void Xor(const std::vector<unsigned char>& key)
|
||||
{
|
||||
if (key.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_type i = 0, j = 0; i != size(); i++) {
|
||||
vch[i] ^= key[j++];
|
||||
|
||||
// This potentially acts on very many bytes of data, so it's
|
||||
// important that we calculate `j`, i.e. the `key` index in this
|
||||
// way instead of doing a %, which would effectively be a division
|
||||
// for each byte Xor'd -- much slower than need be.
|
||||
if (j == key.size())
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename IStream>
|
||||
class BitStreamReader
|
||||
{
|
||||
private:
|
||||
IStream& m_istream;
|
||||
|
||||
/// Buffered byte read in from the input stream. A new byte is read into the
|
||||
/// buffer when m_offset reaches 8.
|
||||
uint8_t m_buffer{0};
|
||||
|
||||
/// Number of high order bits in m_buffer already returned by previous
|
||||
/// Read() calls. The next bit to be returned is at this offset from the
|
||||
/// most significant bit position.
|
||||
int m_offset{8};
|
||||
|
||||
public:
|
||||
explicit BitStreamReader(IStream& istream) : m_istream(istream) {}
|
||||
|
||||
/** Read the specified number of bits from the stream. The data is returned
|
||||
* in the nbits least significant bits of a 64-bit uint.
|
||||
*/
|
||||
uint64_t Read(int nbits) {
|
||||
if (nbits < 0 || nbits > 64) {
|
||||
throw std::out_of_range("nbits must be between 0 and 64");
|
||||
}
|
||||
|
||||
uint64_t data = 0;
|
||||
while (nbits > 0) {
|
||||
if (m_offset == 8) {
|
||||
m_istream >> m_buffer;
|
||||
m_offset = 0;
|
||||
}
|
||||
|
||||
int bits = std::min(8 - m_offset, nbits);
|
||||
data <<= bits;
|
||||
data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
|
||||
m_offset += bits;
|
||||
nbits -= bits;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OStream>
|
||||
class BitStreamWriter
|
||||
{
|
||||
private:
|
||||
OStream& m_ostream;
|
||||
|
||||
/// Buffered byte waiting to be written to the output stream. The byte is
|
||||
/// written buffer when m_offset reaches 8 or Flush() is called.
|
||||
uint8_t m_buffer{0};
|
||||
|
||||
/// Number of high order bits in m_buffer already written by previous
|
||||
/// Write() calls and not yet flushed to the stream. The next bit to be
|
||||
/// written to is at this offset from the most significant bit position.
|
||||
int m_offset{0};
|
||||
|
||||
public:
|
||||
explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
|
||||
|
||||
~BitStreamWriter()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
/** Write the nbits least significant bits of a 64-bit int to the output
|
||||
* stream. Data is buffered until it completes an octet.
|
||||
*/
|
||||
void Write(uint64_t data, int nbits) {
|
||||
if (nbits < 0 || nbits > 64) {
|
||||
throw std::out_of_range("nbits must be between 0 and 64");
|
||||
}
|
||||
|
||||
while (nbits > 0) {
|
||||
int bits = std::min(8 - m_offset, nbits);
|
||||
m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
|
||||
m_offset += bits;
|
||||
nbits -= bits;
|
||||
|
||||
if (m_offset == 8) {
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Flush any unwritten bits to the output stream, padding with 0's to the
|
||||
* next byte boundary.
|
||||
*/
|
||||
void Flush() {
|
||||
if (m_offset == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ostream << m_buffer;
|
||||
m_buffer = 0;
|
||||
m_offset = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Non-refcounted RAII wrapper for FILE*
|
||||
*
|
||||
* Will automatically close the file when it goes out of scope if not null.
|
||||
* If you're returning the file pointer, return file.release().
|
||||
* If you need to close the file early, use file.fclose() instead of fclose(file).
|
||||
*/
|
||||
class CAutoFile
|
||||
{
|
||||
private:
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
|
||||
FILE* file;
|
||||
|
||||
public:
|
||||
CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
|
||||
{
|
||||
file = filenew;
|
||||
}
|
||||
|
||||
~CAutoFile()
|
||||
{
|
||||
fclose();
|
||||
}
|
||||
|
||||
// Disallow copies
|
||||
CAutoFile(const CAutoFile&) = delete;
|
||||
CAutoFile& operator=(const CAutoFile&) = delete;
|
||||
|
||||
void fclose()
|
||||
{
|
||||
if (file) {
|
||||
::fclose(file);
|
||||
file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get wrapped FILE* with transfer of ownership.
|
||||
* @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
|
||||
* of this function to clean up the returned FILE*.
|
||||
*/
|
||||
FILE* release() { FILE* ret = file; file = nullptr; return ret; }
|
||||
|
||||
/** Get wrapped FILE* without transfer of ownership.
|
||||
* @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
|
||||
* CAutoFile outlives use of the passed pointer.
|
||||
*/
|
||||
FILE* Get() const { return file; }
|
||||
|
||||
/** Return true if the wrapped FILE* is nullptr, false otherwise.
|
||||
*/
|
||||
bool IsNull() const { return (file == nullptr); }
|
||||
|
||||
//
|
||||
// Stream subset
|
||||
//
|
||||
int GetType() const { return nType; }
|
||||
int GetVersion() const { return nVersion; }
|
||||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
if (!file)
|
||||
throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
|
||||
if (fread(pch, 1, nSize, file) != nSize)
|
||||
throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
|
||||
}
|
||||
|
||||
void ignore(size_t nSize)
|
||||
{
|
||||
if (!file)
|
||||
throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
|
||||
unsigned char data[4096];
|
||||
while (nSize > 0) {
|
||||
size_t nNow = std::min<size_t>(nSize, sizeof(data));
|
||||
if (fread(data, 1, nNow, file) != nNow)
|
||||
throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
|
||||
nSize -= nNow;
|
||||
}
|
||||
}
|
||||
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
if (!file)
|
||||
throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
|
||||
if (fwrite(pch, 1, nSize, file) != nSize)
|
||||
throw std::ios_base::failure("CAutoFile::write: write failed");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CAutoFile& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
if (!file)
|
||||
throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
|
||||
::Serialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CAutoFile& operator>>(T&& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
if (!file)
|
||||
throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
|
||||
* deserialize from. It guarantees the ability to rewind a given number of bytes.
|
||||
*
|
||||
* Will automatically close the file when it goes out of scope if not null.
|
||||
* If you need to close the file early, use file.fclose() instead of fclose(file).
|
||||
*/
|
||||
class CBufferedFile
|
||||
{
|
||||
private:
|
||||
const int nType;
|
||||
const int nVersion;
|
||||
|
||||
FILE *src; //!< source file
|
||||
uint64_t nSrcPos; //!< how many bytes have been read from source
|
||||
uint64_t nReadPos; //!< how many bytes have been read from this
|
||||
uint64_t nReadLimit; //!< up to which position we're allowed to read
|
||||
uint64_t nRewind; //!< how many bytes we guarantee to rewind
|
||||
std::vector<char> vchBuf; //!< the buffer
|
||||
|
||||
protected:
|
||||
//! read data from the source to fill the buffer
|
||||
bool Fill() {
|
||||
unsigned int pos = nSrcPos % vchBuf.size();
|
||||
unsigned int readNow = vchBuf.size() - pos;
|
||||
unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
|
||||
if (nAvail < readNow)
|
||||
readNow = nAvail;
|
||||
if (readNow == 0)
|
||||
return false;
|
||||
size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
|
||||
if (nBytes == 0) {
|
||||
throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
|
||||
} else {
|
||||
nSrcPos += nBytes;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
|
||||
nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0)
|
||||
{
|
||||
src = fileIn;
|
||||
}
|
||||
|
||||
~CBufferedFile()
|
||||
{
|
||||
fclose();
|
||||
}
|
||||
|
||||
// Disallow copies
|
||||
CBufferedFile(const CBufferedFile&) = delete;
|
||||
CBufferedFile& operator=(const CBufferedFile&) = delete;
|
||||
|
||||
int GetVersion() const { return nVersion; }
|
||||
int GetType() const { return nType; }
|
||||
|
||||
void fclose()
|
||||
{
|
||||
if (src) {
|
||||
::fclose(src);
|
||||
src = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//! check whether we're at the end of the source file
|
||||
bool eof() const {
|
||||
return nReadPos == nSrcPos && feof(src);
|
||||
}
|
||||
|
||||
//! read a number of bytes
|
||||
void read(char *pch, size_t nSize) {
|
||||
if (nSize + nReadPos > nReadLimit)
|
||||
throw std::ios_base::failure("Read attempted past buffer limit");
|
||||
if (nSize + nRewind > vchBuf.size())
|
||||
throw std::ios_base::failure("Read larger than buffer size");
|
||||
while (nSize > 0) {
|
||||
if (nReadPos == nSrcPos)
|
||||
Fill();
|
||||
unsigned int pos = nReadPos % vchBuf.size();
|
||||
size_t nNow = nSize;
|
||||
if (nNow + pos > vchBuf.size())
|
||||
nNow = vchBuf.size() - pos;
|
||||
if (nNow + nReadPos > nSrcPos)
|
||||
nNow = nSrcPos - nReadPos;
|
||||
memcpy(pch, &vchBuf[pos], nNow);
|
||||
nReadPos += nNow;
|
||||
pch += nNow;
|
||||
nSize -= nNow;
|
||||
}
|
||||
}
|
||||
|
||||
//! return the current reading position
|
||||
uint64_t GetPos() const {
|
||||
return nReadPos;
|
||||
}
|
||||
|
||||
//! rewind to a given reading position
|
||||
bool SetPos(uint64_t nPos) {
|
||||
nReadPos = nPos;
|
||||
if (nReadPos + nRewind < nSrcPos) {
|
||||
nReadPos = nSrcPos - nRewind;
|
||||
return false;
|
||||
} else if (nReadPos > nSrcPos) {
|
||||
nReadPos = nSrcPos;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Seek(uint64_t nPos) {
|
||||
long nLongPos = nPos;
|
||||
if (nPos != (uint64_t)nLongPos)
|
||||
return false;
|
||||
if (fseek(src, nLongPos, SEEK_SET))
|
||||
return false;
|
||||
nLongPos = ftell(src);
|
||||
nSrcPos = nLongPos;
|
||||
nReadPos = nLongPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! prevent reading beyond a certain position
|
||||
//! no argument removes the limit
|
||||
bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
|
||||
if (nPos < nReadPos)
|
||||
return false;
|
||||
nReadLimit = nPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CBufferedFile& operator>>(T&& obj) {
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//! search for a given byte in the stream, and remain positioned on it
|
||||
void FindByte(char ch) {
|
||||
while (true) {
|
||||
if (nReadPos == nSrcPos)
|
||||
Fill();
|
||||
if (vchBuf[nReadPos % vchBuf.size()] == ch)
|
||||
break;
|
||||
nReadPos++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_STREAMS_H
|
62
lib/bip158/src/support/allocators/secure.h
Normal file
62
lib/bip158/src/support/allocators/secure.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
|
||||
#define BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
|
||||
|
||||
#include <support/lockedpool.h>
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
//
|
||||
// Allocator that locks its contents from being paged
|
||||
// out of memory and clears its contents before deletion.
|
||||
//
|
||||
template <typename T>
|
||||
struct secure_allocator : public std::allocator<T> {
|
||||
// MSVC8 default copy constructor is broken
|
||||
typedef std::allocator<T> base;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::pointer pointer;
|
||||
typedef typename base::const_pointer const_pointer;
|
||||
typedef typename base::reference reference;
|
||||
typedef typename base::const_reference const_reference;
|
||||
typedef typename base::value_type value_type;
|
||||
secure_allocator() noexcept {}
|
||||
secure_allocator(const secure_allocator& a) noexcept : base(a) {}
|
||||
template <typename U>
|
||||
secure_allocator(const secure_allocator<U>& a) noexcept : base(a)
|
||||
{
|
||||
}
|
||||
~secure_allocator() noexcept {}
|
||||
template <typename _Other>
|
||||
struct rebind {
|
||||
typedef secure_allocator<_Other> other;
|
||||
};
|
||||
|
||||
T* allocate(std::size_t n, const void* hint = 0)
|
||||
{
|
||||
T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
|
||||
if (!allocation) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
if (p != nullptr) {
|
||||
memory_cleanse(p, sizeof(T) * n);
|
||||
}
|
||||
LockedPoolManager::Instance().free(p);
|
||||
}
|
||||
};
|
||||
|
||||
// This is exactly like std::string, but with a custom allocator.
|
||||
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
|
||||
|
||||
#endif // BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
|
48
lib/bip158/src/support/allocators/zeroafterfree.h
Normal file
48
lib/bip158/src/support/allocators/zeroafterfree.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
|
||||
#define BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
|
||||
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
struct zero_after_free_allocator : public std::allocator<T> {
|
||||
// MSVC8 default copy constructor is broken
|
||||
typedef std::allocator<T> base;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::pointer pointer;
|
||||
typedef typename base::const_pointer const_pointer;
|
||||
typedef typename base::reference reference;
|
||||
typedef typename base::const_reference const_reference;
|
||||
typedef typename base::value_type value_type;
|
||||
zero_after_free_allocator() noexcept {}
|
||||
zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
|
||||
template <typename U>
|
||||
zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
|
||||
{
|
||||
}
|
||||
~zero_after_free_allocator() noexcept {}
|
||||
template <typename _Other>
|
||||
struct rebind {
|
||||
typedef zero_after_free_allocator<_Other> other;
|
||||
};
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
if (p != nullptr)
|
||||
memory_cleanse(p, sizeof(T) * n);
|
||||
std::allocator<T>::deallocate(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
// Byte-vector that clears its contents before deletion.
|
||||
typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
|
||||
|
||||
#endif // BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
|
35
lib/bip158/src/support/cleanse.cpp
Normal file
35
lib/bip158/src/support/cleanse.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <Windows.h> // For SecureZeroMemory.
|
||||
#endif
|
||||
|
||||
void memory_cleanse(void *ptr, size_t len)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
#else
|
||||
std::memset(ptr, 0, len);
|
||||
|
||||
/* Memory barrier that scares the compiler away from optimizing out the memset.
|
||||
*
|
||||
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* in BoringSSL (ISC License):
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
|
||||
* is pretty efficient because the compiler can still implement the memset() efficiently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#endif
|
||||
}
|
15
lib/bip158/src/support/cleanse.h
Normal file
15
lib/bip158/src/support/cleanse.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SUPPORT_CLEANSE_H
|
||||
#define BITCOIN_SUPPORT_CLEANSE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/** Secure overwrite a buffer (possibly containing secret data) with zero-bytes. The write
|
||||
* operation will not be optimized out by the compiler. */
|
||||
void memory_cleanse(void *ptr, size_t len);
|
||||
|
||||
#endif // BITCOIN_SUPPORT_CLEANSE_H
|
404
lib/bip158/src/support/lockedpool.cpp
Normal file
404
lib/bip158/src/support/lockedpool.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
// Copyright (c) 2016-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <support/lockedpool.h>
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h> // for mmap
|
||||
#include <sys/resource.h> // for getrlimit
|
||||
#include <limits.h> // for PAGESIZE
|
||||
#include <unistd.h> // for sysconf
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
LockedPoolManager* LockedPoolManager::_instance = nullptr;
|
||||
std::once_flag LockedPoolManager::init_flag;
|
||||
|
||||
/*******************************************************************************/
|
||||
// Utilities
|
||||
//
|
||||
/** Align up to power of 2 */
|
||||
static inline size_t align_up(size_t x, size_t align)
|
||||
{
|
||||
return (x + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
// Implementation: Arena
|
||||
|
||||
Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
|
||||
base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
|
||||
{
|
||||
// Start with one free chunk that covers the entire arena
|
||||
auto it = size_to_free_chunk.emplace(size_in, base);
|
||||
chunks_free.emplace(base, it);
|
||||
chunks_free_end.emplace(base + size_in, it);
|
||||
}
|
||||
|
||||
Arena::~Arena()
|
||||
{
|
||||
}
|
||||
|
||||
void* Arena::alloc(size_t size)
|
||||
{
|
||||
// Round to next multiple of alignment
|
||||
size = align_up(size, alignment);
|
||||
|
||||
// Don't handle zero-sized chunks
|
||||
if (size == 0)
|
||||
return nullptr;
|
||||
|
||||
// Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
|
||||
// This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
|
||||
// Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
|
||||
// policies seem to work well in practice.
|
||||
auto size_ptr_it = size_to_free_chunk.lower_bound(size);
|
||||
if (size_ptr_it == size_to_free_chunk.end())
|
||||
return nullptr;
|
||||
|
||||
// Create the used-chunk, taking its space from the end of the free-chunk
|
||||
const size_t size_remaining = size_ptr_it->first - size;
|
||||
auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
|
||||
chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
|
||||
if (size_ptr_it->first == size) {
|
||||
// whole chunk is used up
|
||||
chunks_free.erase(size_ptr_it->second);
|
||||
} else {
|
||||
// still some memory left in the chunk
|
||||
auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
|
||||
chunks_free[size_ptr_it->second] = it_remaining;
|
||||
chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
|
||||
}
|
||||
size_to_free_chunk.erase(size_ptr_it);
|
||||
|
||||
return reinterpret_cast<void*>(allocated->first);
|
||||
}
|
||||
|
||||
void Arena::free(void *ptr)
|
||||
{
|
||||
// Freeing the nullptr pointer is OK.
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove chunk from used map
|
||||
auto i = chunks_used.find(static_cast<char*>(ptr));
|
||||
if (i == chunks_used.end()) {
|
||||
throw std::runtime_error("Arena: invalid or double free");
|
||||
}
|
||||
std::pair<char*, size_t> freed = *i;
|
||||
chunks_used.erase(i);
|
||||
|
||||
// coalesce freed with previous chunk
|
||||
auto prev = chunks_free_end.find(freed.first);
|
||||
if (prev != chunks_free_end.end()) {
|
||||
freed.first -= prev->second->first;
|
||||
freed.second += prev->second->first;
|
||||
size_to_free_chunk.erase(prev->second);
|
||||
chunks_free_end.erase(prev);
|
||||
}
|
||||
|
||||
// coalesce freed with chunk after freed
|
||||
auto next = chunks_free.find(freed.first + freed.second);
|
||||
if (next != chunks_free.end()) {
|
||||
freed.second += next->second->first;
|
||||
size_to_free_chunk.erase(next->second);
|
||||
chunks_free.erase(next);
|
||||
}
|
||||
|
||||
// Add/set space with coalesced free chunk
|
||||
auto it = size_to_free_chunk.emplace(freed.second, freed.first);
|
||||
chunks_free[freed.first] = it;
|
||||
chunks_free_end[freed.first + freed.second] = it;
|
||||
}
|
||||
|
||||
Arena::Stats Arena::stats() const
|
||||
{
|
||||
Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
|
||||
for (const auto& chunk: chunks_used)
|
||||
r.used += chunk.second;
|
||||
for (const auto& chunk: chunks_free)
|
||||
r.free += chunk.second->first;
|
||||
r.total = r.used + r.free;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef ARENA_DEBUG
|
||||
static void printchunk(char* base, size_t sz, bool used) {
|
||||
std::cout <<
|
||||
"0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
|
||||
" 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
|
||||
" 0x" << used << std::endl;
|
||||
}
|
||||
void Arena::walk() const
|
||||
{
|
||||
for (const auto& chunk: chunks_used)
|
||||
printchunk(chunk.first, chunk.second, true);
|
||||
std::cout << std::endl;
|
||||
for (const auto& chunk: chunks_free)
|
||||
printchunk(chunk.first, chunk.second, false);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************/
|
||||
// Implementation: Win32LockedPageAllocator
|
||||
|
||||
#ifdef WIN32
|
||||
/** LockedPageAllocator specialized for Windows.
|
||||
*/
|
||||
class Win32LockedPageAllocator: public LockedPageAllocator
|
||||
{
|
||||
public:
|
||||
Win32LockedPageAllocator();
|
||||
void* AllocateLocked(size_t len, bool *lockingSuccess) override;
|
||||
void FreeLocked(void* addr, size_t len) override;
|
||||
size_t GetLimit() override;
|
||||
private:
|
||||
size_t page_size;
|
||||
};
|
||||
|
||||
Win32LockedPageAllocator::Win32LockedPageAllocator()
|
||||
{
|
||||
// Determine system page size in bytes
|
||||
SYSTEM_INFO sSysInfo;
|
||||
GetSystemInfo(&sSysInfo);
|
||||
page_size = sSysInfo.dwPageSize;
|
||||
}
|
||||
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
|
||||
{
|
||||
len = align_up(len, page_size);
|
||||
void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (addr) {
|
||||
// VirtualLock is used to attempt to keep keying material out of swap. Note
|
||||
// that it does not provide this as a guarantee, but, in practice, memory
|
||||
// that has been VirtualLock'd almost never gets written to the pagefile
|
||||
// except in rare circumstances where memory is extremely low.
|
||||
*lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
|
||||
{
|
||||
len = align_up(len, page_size);
|
||||
memory_cleanse(addr, len);
|
||||
VirtualUnlock(const_cast<void*>(addr), len);
|
||||
}
|
||||
|
||||
size_t Win32LockedPageAllocator::GetLimit()
|
||||
{
|
||||
// TODO is there a limit on Windows, how to get it?
|
||||
return std::numeric_limits<size_t>::max();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************/
|
||||
// Implementation: PosixLockedPageAllocator
|
||||
|
||||
#ifndef WIN32
|
||||
/** LockedPageAllocator specialized for OSes that don't try to be
|
||||
* special snowflakes.
|
||||
*/
|
||||
class PosixLockedPageAllocator: public LockedPageAllocator
|
||||
{
|
||||
public:
|
||||
PosixLockedPageAllocator();
|
||||
void* AllocateLocked(size_t len, bool *lockingSuccess) override;
|
||||
void FreeLocked(void* addr, size_t len) override;
|
||||
size_t GetLimit() override;
|
||||
private:
|
||||
size_t page_size;
|
||||
};
|
||||
|
||||
PosixLockedPageAllocator::PosixLockedPageAllocator()
|
||||
{
|
||||
// Determine system page size in bytes
|
||||
#if defined(PAGESIZE) // defined in limits.h
|
||||
page_size = PAGESIZE;
|
||||
#else // assume some POSIX OS
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
|
||||
// MAP_ANON which is deprecated
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
|
||||
{
|
||||
void *addr;
|
||||
len = align_up(len, page_size);
|
||||
addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
return nullptr;
|
||||
}
|
||||
if (addr) {
|
||||
*lockingSuccess = mlock(addr, len) == 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
|
||||
{
|
||||
len = align_up(len, page_size);
|
||||
memory_cleanse(addr, len);
|
||||
munlock(addr, len);
|
||||
munmap(addr, len);
|
||||
}
|
||||
size_t PosixLockedPageAllocator::GetLimit()
|
||||
{
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
struct rlimit rlim;
|
||||
if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
|
||||
if (rlim.rlim_cur != RLIM_INFINITY) {
|
||||
return rlim.rlim_cur;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return std::numeric_limits<size_t>::max();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************/
|
||||
// Implementation: LockedPool
|
||||
|
||||
LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
|
||||
allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
|
||||
{
|
||||
}
|
||||
|
||||
LockedPool::~LockedPool()
|
||||
{
|
||||
}
|
||||
void* LockedPool::alloc(size_t size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
// Don't handle impossible sizes
|
||||
if (size == 0 || size > ARENA_SIZE)
|
||||
return nullptr;
|
||||
|
||||
// Try allocating from each current arena
|
||||
for (auto &arena: arenas) {
|
||||
void *addr = arena.alloc(size);
|
||||
if (addr) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
// If that fails, create a new one
|
||||
if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
|
||||
return arenas.back().alloc(size);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LockedPool::free(void *ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
// TODO we can do better than this linear search by keeping a map of arena
|
||||
// extents to arena, and looking up the address.
|
||||
for (auto &arena: arenas) {
|
||||
if (arena.addressInArena(ptr)) {
|
||||
arena.free(ptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
|
||||
}
|
||||
|
||||
LockedPool::Stats LockedPool::stats() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
|
||||
for (const auto &arena: arenas) {
|
||||
Arena::Stats i = arena.stats();
|
||||
r.used += i.used;
|
||||
r.free += i.free;
|
||||
r.total += i.total;
|
||||
r.chunks_used += i.chunks_used;
|
||||
r.chunks_free += i.chunks_free;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool LockedPool::new_arena(size_t size, size_t align)
|
||||
{
|
||||
bool locked;
|
||||
// If this is the first arena, handle this specially: Cap the upper size
|
||||
// by the process limit. This makes sure that the first arena will at least
|
||||
// be locked. An exception to this is if the process limit is 0:
|
||||
// in this case no memory can be locked at all so we'll skip past this logic.
|
||||
if (arenas.empty()) {
|
||||
size_t limit = allocator->GetLimit();
|
||||
if (limit > 0) {
|
||||
size = std::min(size, limit);
|
||||
}
|
||||
}
|
||||
void *addr = allocator->AllocateLocked(size, &locked);
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
if (locked) {
|
||||
cumulative_bytes_locked += size;
|
||||
} else if (lf_cb) { // Call the locking-failed callback if locking failed
|
||||
if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
|
||||
allocator->FreeLocked(addr, size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
arenas.emplace_back(allocator.get(), addr, size, align);
|
||||
return true;
|
||||
}
|
||||
|
||||
LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
|
||||
Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
|
||||
{
|
||||
}
|
||||
LockedPool::LockedPageArena::~LockedPageArena()
|
||||
{
|
||||
allocator->FreeLocked(base, size);
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
// Implementation: LockedPoolManager
|
||||
//
|
||||
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
|
||||
LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
|
||||
{
|
||||
}
|
||||
|
||||
bool LockedPoolManager::LockingFailed()
|
||||
{
|
||||
// TODO: log something but how? without including util.h
|
||||
return true;
|
||||
}
|
||||
|
||||
void LockedPoolManager::CreateInstance()
|
||||
{
|
||||
// Using a local static instance guarantees that the object is initialized
|
||||
// when it's first needed and also deinitialized after all objects that use
|
||||
// it are done with it. I can think of one unlikely scenario where we may
|
||||
// have a static deinitialization order/problem, but the check in
|
||||
// LockedPoolManagerBase's destructor helps us detect if that ever happens.
|
||||
#ifdef WIN32
|
||||
std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
|
||||
#else
|
||||
std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
|
||||
#endif
|
||||
static LockedPoolManager instance(std::move(allocator));
|
||||
LockedPoolManager::_instance = &instance;
|
||||
}
|
240
lib/bip158/src/support/lockedpool.h
Normal file
240
lib/bip158/src/support/lockedpool.h
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright (c) 2016-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SUPPORT_LOCKEDPOOL_H
|
||||
#define BITCOIN_SUPPORT_LOCKEDPOOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* OS-dependent allocation and deallocation of locked/pinned memory pages.
|
||||
* Abstract base class.
|
||||
*/
|
||||
class LockedPageAllocator
|
||||
{
|
||||
public:
|
||||
virtual ~LockedPageAllocator() {}
|
||||
/** Allocate and lock memory pages.
|
||||
* If len is not a multiple of the system page size, it is rounded up.
|
||||
* Returns nullptr in case of allocation failure.
|
||||
*
|
||||
* If locking the memory pages could not be accomplished it will still
|
||||
* return the memory, however the lockingSuccess flag will be false.
|
||||
* lockingSuccess is undefined if the allocation fails.
|
||||
*/
|
||||
virtual void* AllocateLocked(size_t len, bool *lockingSuccess) = 0;
|
||||
|
||||
/** Unlock and free memory pages.
|
||||
* Clear the memory before unlocking.
|
||||
*/
|
||||
virtual void FreeLocked(void* addr, size_t len) = 0;
|
||||
|
||||
/** Get the total limit on the amount of memory that may be locked by this
|
||||
* process, in bytes. Return size_t max if there is no limit or the limit
|
||||
* is unknown. Return 0 if no memory can be locked at all.
|
||||
*/
|
||||
virtual size_t GetLimit() = 0;
|
||||
};
|
||||
|
||||
/* An arena manages a contiguous region of memory by dividing it into
|
||||
* chunks.
|
||||
*/
|
||||
class Arena
|
||||
{
|
||||
public:
|
||||
Arena(void *base, size_t size, size_t alignment);
|
||||
virtual ~Arena();
|
||||
|
||||
Arena(const Arena& other) = delete; // non construction-copyable
|
||||
Arena& operator=(const Arena&) = delete; // non copyable
|
||||
|
||||
/** Memory statistics. */
|
||||
struct Stats
|
||||
{
|
||||
size_t used;
|
||||
size_t free;
|
||||
size_t total;
|
||||
size_t chunks_used;
|
||||
size_t chunks_free;
|
||||
};
|
||||
|
||||
/** Allocate size bytes from this arena.
|
||||
* Returns pointer on success, or 0 if memory is full or
|
||||
* the application tried to allocate 0 bytes.
|
||||
*/
|
||||
void* alloc(size_t size);
|
||||
|
||||
/** Free a previously allocated chunk of memory.
|
||||
* Freeing the zero pointer has no effect.
|
||||
* Raises std::runtime_error in case of error.
|
||||
*/
|
||||
void free(void *ptr);
|
||||
|
||||
/** Get arena usage statistics */
|
||||
Stats stats() const;
|
||||
|
||||
#ifdef ARENA_DEBUG
|
||||
void walk() const;
|
||||
#endif
|
||||
|
||||
/** Return whether a pointer points inside this arena.
|
||||
* This returns base <= ptr < (base+size) so only use it for (inclusive)
|
||||
* chunk starting addresses.
|
||||
*/
|
||||
bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }
|
||||
private:
|
||||
typedef std::multimap<size_t, char*> SizeToChunkSortedMap;
|
||||
/** Map to enable O(log(n)) best-fit allocation, as it's sorted by size */
|
||||
SizeToChunkSortedMap size_to_free_chunk;
|
||||
|
||||
typedef std::unordered_map<char*, SizeToChunkSortedMap::const_iterator> ChunkToSizeMap;
|
||||
/** Map from begin of free chunk to its node in size_to_free_chunk */
|
||||
ChunkToSizeMap chunks_free;
|
||||
/** Map from end of free chunk to its node in size_to_free_chunk */
|
||||
ChunkToSizeMap chunks_free_end;
|
||||
|
||||
/** Map from begin of used chunk to its size */
|
||||
std::unordered_map<char*, size_t> chunks_used;
|
||||
|
||||
/** Base address of arena */
|
||||
char* base;
|
||||
/** End address of arena */
|
||||
char* end;
|
||||
/** Minimum chunk alignment */
|
||||
size_t alignment;
|
||||
};
|
||||
|
||||
/** Pool for locked memory chunks.
|
||||
*
|
||||
* To avoid sensitive key data from being swapped to disk, the memory in this pool
|
||||
* is locked/pinned.
|
||||
*
|
||||
* An arena manages a contiguous region of memory. The pool starts out with one arena
|
||||
* but can grow to multiple arenas if the need arises.
|
||||
*
|
||||
* Unlike a normal C heap, the administrative structures are separate from the managed
|
||||
* memory. This has been done as the sizes and bases of objects are not in themselves sensitive
|
||||
* information, as to conserve precious locked memory. In some operating systems
|
||||
* the amount of memory that can be locked is small.
|
||||
*/
|
||||
class LockedPool
|
||||
{
|
||||
public:
|
||||
/** Size of one arena of locked memory. This is a compromise.
|
||||
* Do not set this too low, as managing many arenas will increase
|
||||
* allocation and deallocation overhead. Setting it too high allocates
|
||||
* more locked memory from the OS than strictly necessary.
|
||||
*/
|
||||
static const size_t ARENA_SIZE = 256*1024;
|
||||
/** Chunk alignment. Another compromise. Setting this too high will waste
|
||||
* memory, setting it too low will facilitate fragmentation.
|
||||
*/
|
||||
static const size_t ARENA_ALIGN = 16;
|
||||
|
||||
/** Callback when allocation succeeds but locking fails.
|
||||
*/
|
||||
typedef bool (*LockingFailed_Callback)();
|
||||
|
||||
/** Memory statistics. */
|
||||
struct Stats
|
||||
{
|
||||
size_t used;
|
||||
size_t free;
|
||||
size_t total;
|
||||
size_t locked;
|
||||
size_t chunks_used;
|
||||
size_t chunks_free;
|
||||
};
|
||||
|
||||
/** Create a new LockedPool. This takes ownership of the MemoryPageLocker,
|
||||
* you can only instantiate this with LockedPool(std::move(...)).
|
||||
*
|
||||
* The second argument is an optional callback when locking a newly allocated arena failed.
|
||||
* If this callback is provided and returns false, the allocation fails (hard fail), if
|
||||
* it returns true the allocation proceeds, but it could warn.
|
||||
*/
|
||||
explicit LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);
|
||||
~LockedPool();
|
||||
|
||||
LockedPool(const LockedPool& other) = delete; // non construction-copyable
|
||||
LockedPool& operator=(const LockedPool&) = delete; // non copyable
|
||||
|
||||
/** Allocate size bytes from this arena.
|
||||
* Returns pointer on success, or 0 if memory is full or
|
||||
* the application tried to allocate 0 bytes.
|
||||
*/
|
||||
void* alloc(size_t size);
|
||||
|
||||
/** Free a previously allocated chunk of memory.
|
||||
* Freeing the zero pointer has no effect.
|
||||
* Raises std::runtime_error in case of error.
|
||||
*/
|
||||
void free(void *ptr);
|
||||
|
||||
/** Get pool usage statistics */
|
||||
Stats stats() const;
|
||||
private:
|
||||
std::unique_ptr<LockedPageAllocator> allocator;
|
||||
|
||||
/** Create an arena from locked pages */
|
||||
class LockedPageArena: public Arena
|
||||
{
|
||||
public:
|
||||
LockedPageArena(LockedPageAllocator *alloc_in, void *base_in, size_t size, size_t align);
|
||||
~LockedPageArena();
|
||||
private:
|
||||
void *base;
|
||||
size_t size;
|
||||
LockedPageAllocator *allocator;
|
||||
};
|
||||
|
||||
bool new_arena(size_t size, size_t align);
|
||||
|
||||
std::list<LockedPageArena> arenas;
|
||||
LockingFailed_Callback lf_cb;
|
||||
size_t cumulative_bytes_locked;
|
||||
/** Mutex protects access to this pool's data structures, including arenas.
|
||||
*/
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton class to keep track of locked (ie, non-swappable) memory, for use in
|
||||
* std::allocator templates.
|
||||
*
|
||||
* Some implementations of the STL allocate memory in some constructors (i.e., see
|
||||
* MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)
|
||||
* Due to the unpredictable order of static initializers, we have to make sure the
|
||||
* LockedPoolManager instance exists before any other STL-based objects that use
|
||||
* secure_allocator are created. So instead of having LockedPoolManager also be
|
||||
* static-initialized, it is created on demand.
|
||||
*/
|
||||
class LockedPoolManager : public LockedPool
|
||||
{
|
||||
public:
|
||||
/** Return the current instance, or create it once */
|
||||
static LockedPoolManager& Instance()
|
||||
{
|
||||
std::call_once(LockedPoolManager::init_flag, LockedPoolManager::CreateInstance);
|
||||
return *LockedPoolManager::_instance;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
|
||||
|
||||
/** Create a new LockedPoolManager specialized to the OS */
|
||||
static void CreateInstance();
|
||||
/** Called when locking fails, warn the user here */
|
||||
static bool LockingFailed();
|
||||
|
||||
static LockedPoolManager* _instance;
|
||||
static std::once_flag init_flag;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SUPPORT_LOCKEDPOOL_H
|
321
lib/bip158/src/sync.h
Normal file
321
lib/bip158/src/sync.h
Normal file
@ -0,0 +1,321 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SYNC_H
|
||||
#define BITCOIN_SYNC_H
|
||||
|
||||
#include <threadsafety.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// //
|
||||
// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
|
||||
// //
|
||||
////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
RecursiveMutex mutex;
|
||||
std::recursive_mutex mutex;
|
||||
|
||||
LOCK(mutex);
|
||||
std::unique_lock<std::recursive_mutex> criticalblock(mutex);
|
||||
|
||||
LOCK2(mutex1, mutex2);
|
||||
std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
|
||||
std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
|
||||
|
||||
TRY_LOCK(mutex, name);
|
||||
std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
|
||||
|
||||
ENTER_CRITICAL_SECTION(mutex); // no RAII
|
||||
mutex.lock();
|
||||
|
||||
LEAVE_CRITICAL_SECTION(mutex); // no RAII
|
||||
mutex.unlock();
|
||||
*/
|
||||
|
||||
///////////////////////////////
|
||||
// //
|
||||
// THE ACTUAL IMPLEMENTATION //
|
||||
// //
|
||||
///////////////////////////////
|
||||
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
|
||||
void LeaveCritical();
|
||||
std::string LocksHeld();
|
||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs);
|
||||
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
|
||||
void DeleteLock(void* cs);
|
||||
|
||||
/**
|
||||
* Call abort() if a potential lock order deadlock bug is detected, instead of
|
||||
* just logging information and throwing a logic_error. Defaults to true, and
|
||||
* set to false in DEBUG_LOCKORDER unit tests.
|
||||
*/
|
||||
extern bool g_debug_lockorder_abort;
|
||||
#else
|
||||
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
|
||||
void static inline LeaveCritical() {}
|
||||
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
|
||||
void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
|
||||
void static inline DeleteLock(void* cs) {}
|
||||
#endif
|
||||
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
|
||||
#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
|
||||
|
||||
/**
|
||||
* Template mixin that adds -Wthread-safety locking annotations and lock order
|
||||
* checking to a subset of the mutex API.
|
||||
*/
|
||||
template <typename PARENT>
|
||||
class LOCKABLE AnnotatedMixin : public PARENT
|
||||
{
|
||||
public:
|
||||
~AnnotatedMixin() {
|
||||
DeleteLock((void*)this);
|
||||
}
|
||||
|
||||
void lock() EXCLUSIVE_LOCK_FUNCTION()
|
||||
{
|
||||
PARENT::lock();
|
||||
}
|
||||
|
||||
void unlock() UNLOCK_FUNCTION()
|
||||
{
|
||||
PARENT::unlock();
|
||||
}
|
||||
|
||||
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
|
||||
{
|
||||
return PARENT::try_lock();
|
||||
}
|
||||
|
||||
using UniqueLock = std::unique_lock<PARENT>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapped mutex: supports recursive locking, but no waiting
|
||||
* TODO: We should move away from using the recursive lock by default.
|
||||
*/
|
||||
using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
|
||||
typedef AnnotatedMixin<std::recursive_mutex> CCriticalSection;
|
||||
|
||||
/** Wrapped mutex: supports waiting but not recursive locking */
|
||||
typedef AnnotatedMixin<std::mutex> Mutex;
|
||||
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
|
||||
#endif
|
||||
|
||||
/** Wrapper around std::unique_lock style lock for Mutex. */
|
||||
template <typename Mutex, typename Base = typename Mutex::UniqueLock>
|
||||
class SCOPED_LOCKABLE UniqueLock : public Base
|
||||
{
|
||||
private:
|
||||
void Enter(const char* pszName, const char* pszFile, int nLine)
|
||||
{
|
||||
EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
if (!Base::try_lock()) {
|
||||
PrintLockContention(pszName, pszFile, nLine);
|
||||
#endif
|
||||
Base::lock();
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TryEnter(const char* pszName, const char* pszFile, int nLine)
|
||||
{
|
||||
EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
|
||||
Base::try_lock();
|
||||
if (!Base::owns_lock())
|
||||
LeaveCritical();
|
||||
return Base::owns_lock();
|
||||
}
|
||||
|
||||
public:
|
||||
UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
|
||||
{
|
||||
if (fTry)
|
||||
TryEnter(pszName, pszFile, nLine);
|
||||
else
|
||||
Enter(pszName, pszFile, nLine);
|
||||
}
|
||||
|
||||
UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
|
||||
{
|
||||
if (!pmutexIn) return;
|
||||
|
||||
*static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
|
||||
if (fTry)
|
||||
TryEnter(pszName, pszFile, nLine);
|
||||
else
|
||||
Enter(pszName, pszFile, nLine);
|
||||
}
|
||||
|
||||
~UniqueLock() UNLOCK_FUNCTION()
|
||||
{
|
||||
if (Base::owns_lock())
|
||||
LeaveCritical();
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return Base::owns_lock();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MutexArg>
|
||||
using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
|
||||
|
||||
#define PASTE(x, y) x ## y
|
||||
#define PASTE2(x, y) PASTE(x, y)
|
||||
|
||||
#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
|
||||
#define LOCK2(cs1, cs2) \
|
||||
DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
|
||||
DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
|
||||
#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
|
||||
#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
|
||||
|
||||
#define ENTER_CRITICAL_SECTION(cs) \
|
||||
{ \
|
||||
EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
|
||||
(cs).lock(); \
|
||||
}
|
||||
|
||||
#define LEAVE_CRITICAL_SECTION(cs) \
|
||||
{ \
|
||||
(cs).unlock(); \
|
||||
LeaveCritical(); \
|
||||
}
|
||||
|
||||
//! Run code while locking a mutex.
|
||||
//!
|
||||
//! Examples:
|
||||
//!
|
||||
//! WITH_LOCK(cs, shared_val = shared_val + 1);
|
||||
//!
|
||||
//! int val = WITH_LOCK(cs, return shared_val);
|
||||
//!
|
||||
#define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
|
||||
|
||||
class CSemaphore
|
||||
{
|
||||
private:
|
||||
std::condition_variable condition;
|
||||
std::mutex mutex;
|
||||
int value;
|
||||
|
||||
public:
|
||||
explicit CSemaphore(int init) : value(init) {}
|
||||
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
condition.wait(lock, [&]() { return value >= 1; });
|
||||
value--;
|
||||
}
|
||||
|
||||
bool try_wait()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (value < 1)
|
||||
return false;
|
||||
value--;
|
||||
return true;
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
value++;
|
||||
}
|
||||
condition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
/** RAII-style semaphore lock */
|
||||
class CSemaphoreGrant
|
||||
{
|
||||
private:
|
||||
CSemaphore* sem;
|
||||
bool fHaveGrant;
|
||||
|
||||
public:
|
||||
void Acquire()
|
||||
{
|
||||
if (fHaveGrant)
|
||||
return;
|
||||
sem->wait();
|
||||
fHaveGrant = true;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if (!fHaveGrant)
|
||||
return;
|
||||
sem->post();
|
||||
fHaveGrant = false;
|
||||
}
|
||||
|
||||
bool TryAcquire()
|
||||
{
|
||||
if (!fHaveGrant && sem->try_wait())
|
||||
fHaveGrant = true;
|
||||
return fHaveGrant;
|
||||
}
|
||||
|
||||
void MoveTo(CSemaphoreGrant& grant)
|
||||
{
|
||||
grant.Release();
|
||||
grant.sem = sem;
|
||||
grant.fHaveGrant = fHaveGrant;
|
||||
fHaveGrant = false;
|
||||
}
|
||||
|
||||
CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
|
||||
|
||||
explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
|
||||
{
|
||||
if (fTry)
|
||||
TryAcquire();
|
||||
else
|
||||
Acquire();
|
||||
}
|
||||
|
||||
~CSemaphoreGrant()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return fHaveGrant;
|
||||
}
|
||||
};
|
||||
|
||||
// Utility class for indicating to compiler thread analysis that a mutex is
|
||||
// locked (when it couldn't be determined otherwise).
|
||||
struct SCOPED_LOCKABLE LockAssertion
|
||||
{
|
||||
template <typename Mutex>
|
||||
explicit LockAssertion(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
|
||||
{
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
AssertLockHeld(mutex);
|
||||
#endif
|
||||
}
|
||||
~LockAssertion() UNLOCK_FUNCTION() {}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SYNC_H
|
57
lib/bip158/src/threadsafety.h
Normal file
57
lib/bip158/src/threadsafety.h
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_THREADSAFETY_H
|
||||
#define BITCOIN_THREADSAFETY_H
|
||||
|
||||
#ifdef __clang__
|
||||
// TL;DR Add GUARDED_BY(mutex) to member variables. The others are
|
||||
// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo);
|
||||
//
|
||||
// See https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
|
||||
// for documentation. The clang compiler can do advanced static analysis
|
||||
// of locking when given the -Wthread-safety option.
|
||||
#define LOCKABLE __attribute__((lockable))
|
||||
#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
|
||||
#define GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||
#define GUARDED_VAR __attribute__((guarded_var))
|
||||
#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
|
||||
#define PT_GUARDED_VAR __attribute__((pt_guarded_var))
|
||||
#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||
#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
|
||||
#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
|
||||
#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
|
||||
#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
|
||||
#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
|
||||
#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
|
||||
#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
|
||||
#define ASSERT_EXCLUSIVE_LOCK(...) __attribute((assert_exclusive_lock(__VA_ARGS__)))
|
||||
#else
|
||||
#define LOCKABLE
|
||||
#define SCOPED_LOCKABLE
|
||||
#define GUARDED_BY(x)
|
||||
#define GUARDED_VAR
|
||||
#define PT_GUARDED_BY(x)
|
||||
#define PT_GUARDED_VAR
|
||||
#define ACQUIRED_AFTER(...)
|
||||
#define ACQUIRED_BEFORE(...)
|
||||
#define EXCLUSIVE_LOCK_FUNCTION(...)
|
||||
#define SHARED_LOCK_FUNCTION(...)
|
||||
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
|
||||
#define SHARED_TRYLOCK_FUNCTION(...)
|
||||
#define UNLOCK_FUNCTION(...)
|
||||
#define LOCK_RETURNED(x)
|
||||
#define LOCKS_EXCLUDED(...)
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(...)
|
||||
#define SHARED_LOCKS_REQUIRED(...)
|
||||
#define NO_THREAD_SAFETY_ANALYSIS
|
||||
#define ASSERT_EXCLUSIVE_LOCK(...)
|
||||
#endif // __GNUC__
|
||||
|
||||
#endif // BITCOIN_THREADSAFETY_H
|
1069
lib/bip158/src/tinyformat.h
Normal file
1069
lib/bip158/src/tinyformat.h
Normal file
File diff suppressed because it is too large
Load Diff
78
lib/bip158/src/uint256.cpp
Normal file
78
lib/bip158/src/uint256.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <uint256.h>
|
||||
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
assert(vch.size() == sizeof(data));
|
||||
memcpy(data, vch.data(), sizeof(data));
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
std::string base_blob<BITS>::GetHex() const
|
||||
{
|
||||
return HexStr(std::reverse_iterator<const uint8_t*>(data + sizeof(data)), std::reverse_iterator<const uint8_t*>(data));
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
void base_blob<BITS>::SetHex(const char* psz)
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
// skip leading spaces
|
||||
while (IsSpace(*psz))
|
||||
psz++;
|
||||
|
||||
// skip 0x
|
||||
if (psz[0] == '0' && ToLower(psz[1]) == 'x')
|
||||
psz += 2;
|
||||
|
||||
// hex string to uint
|
||||
size_t digits = 0;
|
||||
while (::HexDigit(psz[digits]) != -1)
|
||||
digits++;
|
||||
unsigned char* p1 = (unsigned char*)data;
|
||||
unsigned char* pend = p1 + WIDTH;
|
||||
while (digits > 0 && p1 < pend) {
|
||||
*p1 = ::HexDigit(psz[--digits]);
|
||||
if (digits > 0) {
|
||||
*p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4);
|
||||
p1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
void base_blob<BITS>::SetHex(const std::string& str)
|
||||
{
|
||||
SetHex(str.c_str());
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
std::string base_blob<BITS>::ToString() const
|
||||
{
|
||||
return (GetHex());
|
||||
}
|
||||
|
||||
// Explicit instantiations for base_blob<160>
|
||||
template base_blob<160>::base_blob(const std::vector<unsigned char>&);
|
||||
template std::string base_blob<160>::GetHex() const;
|
||||
template std::string base_blob<160>::ToString() const;
|
||||
template void base_blob<160>::SetHex(const char*);
|
||||
template void base_blob<160>::SetHex(const std::string&);
|
||||
|
||||
// Explicit instantiations for base_blob<256>
|
||||
template base_blob<256>::base_blob(const std::vector<unsigned char>&);
|
||||
template std::string base_blob<256>::GetHex() const;
|
||||
template std::string base_blob<256>::ToString() const;
|
||||
template void base_blob<256>::SetHex(const char*);
|
||||
template void base_blob<256>::SetHex(const std::string&);
|
148
lib/bip158/src/uint256.h
Normal file
148
lib/bip158/src/uint256.h
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UINT256_H
|
||||
#define BITCOIN_UINT256_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** Template base class for fixed-sized opaque blobs. */
|
||||
template<unsigned int BITS>
|
||||
class base_blob
|
||||
{
|
||||
protected:
|
||||
static constexpr int WIDTH = BITS / 8;
|
||||
uint8_t data[WIDTH];
|
||||
public:
|
||||
base_blob()
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
explicit base_blob(const std::vector<unsigned char>& vch);
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
if (data[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); }
|
||||
|
||||
friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
|
||||
friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
|
||||
friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
|
||||
|
||||
std::string GetHex() const;
|
||||
void SetHex(const char* psz);
|
||||
void SetHex(const std::string& str);
|
||||
std::string ToString() const;
|
||||
|
||||
unsigned char* begin()
|
||||
{
|
||||
return &data[0];
|
||||
}
|
||||
|
||||
unsigned char* end()
|
||||
{
|
||||
return &data[WIDTH];
|
||||
}
|
||||
|
||||
const unsigned char* begin() const
|
||||
{
|
||||
return &data[0];
|
||||
}
|
||||
|
||||
const unsigned char* end() const
|
||||
{
|
||||
return &data[WIDTH];
|
||||
}
|
||||
|
||||
unsigned int size() const
|
||||
{
|
||||
return sizeof(data);
|
||||
}
|
||||
|
||||
uint64_t GetUint64(int pos) const
|
||||
{
|
||||
const uint8_t* ptr = data + pos * 8;
|
||||
return ((uint64_t)ptr[0]) | \
|
||||
((uint64_t)ptr[1]) << 8 | \
|
||||
((uint64_t)ptr[2]) << 16 | \
|
||||
((uint64_t)ptr[3]) << 24 | \
|
||||
((uint64_t)ptr[4]) << 32 | \
|
||||
((uint64_t)ptr[5]) << 40 | \
|
||||
((uint64_t)ptr[6]) << 48 | \
|
||||
((uint64_t)ptr[7]) << 56;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
s.write((char*)data, sizeof(data));
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s)
|
||||
{
|
||||
s.read((char*)data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
/** 160-bit opaque blob.
|
||||
* @note This type is called uint160 for historical reasons only. It is an opaque
|
||||
* blob of 160 bits and has no integer operations.
|
||||
*/
|
||||
class uint160 : public base_blob<160> {
|
||||
public:
|
||||
uint160() {}
|
||||
explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
|
||||
};
|
||||
|
||||
/** 256-bit opaque blob.
|
||||
* @note This type is called uint256 for historical reasons only. It is an
|
||||
* opaque blob of 256 bits and has no integer operations. Use arith_uint256 if
|
||||
* those are required.
|
||||
*/
|
||||
class uint256 : public base_blob<256> {
|
||||
public:
|
||||
uint256() {}
|
||||
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
|
||||
};
|
||||
|
||||
/* uint256 from const char *.
|
||||
* This is a separate function because the constructor uint256(const char*) can result
|
||||
* in dangerously catching uint256(0).
|
||||
*/
|
||||
inline uint256 uint256S(const char *str)
|
||||
{
|
||||
uint256 rv;
|
||||
rv.SetHex(str);
|
||||
return rv;
|
||||
}
|
||||
/* uint256 from std::string.
|
||||
* This is a separate function because the constructor uint256(const std::string &str) can result
|
||||
* in dangerously catching uint256(0) via std::string(const char*).
|
||||
*/
|
||||
inline uint256 uint256S(const std::string& str)
|
||||
{
|
||||
uint256 rv;
|
||||
rv.SetHex(str);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_UINT256_H
|
114
lib/bip158/src/undo.h
Normal file
114
lib/bip158/src/undo.h
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UNDO_H
|
||||
#define BITCOIN_UNDO_H
|
||||
|
||||
#include <coins.h>
|
||||
#include <compressor.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <version.h>
|
||||
|
||||
/** Undo information for a CTxIn
|
||||
*
|
||||
* Contains the prevout's CTxOut being spent, and its metadata as well
|
||||
* (coinbase or not, height). The serialization contains a dummy value of
|
||||
* zero. This is compatible with older versions which expect to see
|
||||
* the transaction version there.
|
||||
*/
|
||||
class TxInUndoSerializer
|
||||
{
|
||||
const Coin* txout;
|
||||
|
||||
public:
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1u : 0u)));
|
||||
if (txout->nHeight > 0) {
|
||||
// Required to maintain compatibility with older undo format.
|
||||
::Serialize(s, (unsigned char)0);
|
||||
}
|
||||
::Serialize(s, CTxOutCompressor(REF(txout->out)));
|
||||
}
|
||||
|
||||
explicit TxInUndoSerializer(const Coin* coin) : txout(coin) {}
|
||||
};
|
||||
|
||||
class TxInUndoDeserializer
|
||||
{
|
||||
Coin* txout;
|
||||
|
||||
public:
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s) {
|
||||
unsigned int nCode = 0;
|
||||
::Unserialize(s, VARINT(nCode));
|
||||
txout->nHeight = nCode / 2;
|
||||
txout->fCoinBase = nCode & 1;
|
||||
if (txout->nHeight > 0) {
|
||||
// Old versions stored the version number for the last spend of
|
||||
// a transaction's outputs. Non-final spends were indicated with
|
||||
// height = 0.
|
||||
unsigned int nVersionDummy;
|
||||
::Unserialize(s, VARINT(nVersionDummy));
|
||||
}
|
||||
::Unserialize(s, CTxOutCompressor(REF(txout->out)));
|
||||
}
|
||||
|
||||
explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {}
|
||||
};
|
||||
|
||||
static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), PROTOCOL_VERSION);
|
||||
static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_INPUT_WEIGHT;
|
||||
|
||||
/** Undo information for a CTransaction */
|
||||
class CTxUndo
|
||||
{
|
||||
public:
|
||||
// undo information for all txins
|
||||
std::vector<Coin> vprevout;
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
// TODO: avoid reimplementing vector serializer
|
||||
uint64_t count = vprevout.size();
|
||||
::Serialize(s, COMPACTSIZE(REF(count)));
|
||||
for (const auto& prevout : vprevout) {
|
||||
::Serialize(s, TxInUndoSerializer(&prevout));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
// TODO: avoid reimplementing vector deserializer
|
||||
uint64_t count = 0;
|
||||
::Unserialize(s, COMPACTSIZE(count));
|
||||
if (count > MAX_INPUTS_PER_BLOCK) {
|
||||
throw std::ios_base::failure("Too many input undo records");
|
||||
}
|
||||
vprevout.resize(count);
|
||||
for (auto& prevout : vprevout) {
|
||||
::Unserialize(s, TxInUndoDeserializer(&prevout));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Undo information for a CBlock */
|
||||
class CBlockUndo
|
||||
{
|
||||
public:
|
||||
std::vector<CTxUndo> vtxundo; // for all but the coinbase
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(vtxundo);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_UNDO_H
|
18
lib/bip158/src/util/bytevectorhash.cpp
Normal file
18
lib/bip158/src/util/bytevectorhash.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/siphash.h>
|
||||
#include <random.h>
|
||||
#include <util/bytevectorhash.h>
|
||||
|
||||
ByteVectorHash::ByteVectorHash()
|
||||
{
|
||||
GetRandBytes(reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0));
|
||||
GetRandBytes(reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1));
|
||||
}
|
||||
|
||||
size_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const
|
||||
{
|
||||
return CSipHasher(m_k0, m_k1).Write(input.data(), input.size()).Finalize();
|
||||
}
|
26
lib/bip158/src/util/bytevectorhash.h
Normal file
26
lib/bip158/src/util/bytevectorhash.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_BYTEVECTORHASH_H
|
||||
#define BITCOIN_UTIL_BYTEVECTORHASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Implementation of Hash named requirement for types that internally store a byte array. This may
|
||||
* be used as the hash function in std::unordered_set or std::unordered_map over such types.
|
||||
* Internally, this uses a random instance of SipHash-2-4.
|
||||
*/
|
||||
class ByteVectorHash final
|
||||
{
|
||||
private:
|
||||
uint64_t m_k0, m_k1;
|
||||
|
||||
public:
|
||||
ByteVectorHash();
|
||||
size_t operator()(const std::vector<unsigned char>& input) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_UTIL_BYTEVECTORHASH_H
|
559
lib/bip158/src/util/strencodings.cpp
Normal file
559
lib/bip158/src/util/strencodings.cpp
Normal file
@ -0,0 +1,559 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <limits>
|
||||
|
||||
static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
static const std::string SAFE_CHARS[] =
|
||||
{
|
||||
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
|
||||
CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
|
||||
CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
|
||||
CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
|
||||
};
|
||||
|
||||
std::string SanitizeString(const std::string& str, int rule)
|
||||
{
|
||||
std::string strResult;
|
||||
for (std::string::size_type i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
|
||||
strResult.push_back(str[i]);
|
||||
}
|
||||
return strResult;
|
||||
}
|
||||
|
||||
const signed char p_util_hexdigit[256] =
|
||||
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
|
||||
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
|
||||
|
||||
signed char HexDigit(char c)
|
||||
{
|
||||
return p_util_hexdigit[(unsigned char)c];
|
||||
}
|
||||
|
||||
bool IsHex(const std::string& str)
|
||||
{
|
||||
for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)
|
||||
{
|
||||
if (HexDigit(*it) < 0)
|
||||
return false;
|
||||
}
|
||||
return (str.size() > 0) && (str.size()%2 == 0);
|
||||
}
|
||||
|
||||
bool IsHexNumber(const std::string& str)
|
||||
{
|
||||
size_t starting_location = 0;
|
||||
if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') {
|
||||
starting_location = 2;
|
||||
}
|
||||
for (const char c : str.substr(starting_location)) {
|
||||
if (HexDigit(c) < 0) return false;
|
||||
}
|
||||
// Return false for empty string or "0x".
|
||||
return (str.size() > starting_location);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ParseHex(const char* psz)
|
||||
{
|
||||
// convert hex dump to vector
|
||||
std::vector<unsigned char> vch;
|
||||
while (true)
|
||||
{
|
||||
while (IsSpace(*psz))
|
||||
psz++;
|
||||
signed char c = HexDigit(*psz++);
|
||||
if (c == (signed char)-1)
|
||||
break;
|
||||
unsigned char n = (c << 4);
|
||||
c = HexDigit(*psz++);
|
||||
if (c == (signed char)-1)
|
||||
break;
|
||||
n |= c;
|
||||
vch.push_back(n);
|
||||
}
|
||||
return vch;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ParseHex(const std::string& str)
|
||||
{
|
||||
return ParseHex(str.c_str());
|
||||
}
|
||||
|
||||
void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
|
||||
size_t colon = in.find_last_of(':');
|
||||
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
|
||||
bool fHaveColon = colon != in.npos;
|
||||
bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
|
||||
bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
|
||||
if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
|
||||
int32_t n;
|
||||
if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
|
||||
in = in.substr(0, colon);
|
||||
portOut = n;
|
||||
}
|
||||
}
|
||||
if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
|
||||
hostOut = in.substr(1, in.size()-2);
|
||||
else
|
||||
hostOut = in;
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const unsigned char* pch, size_t len)
|
||||
{
|
||||
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string str;
|
||||
str.reserve(((len + 2) / 3) * 4);
|
||||
ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len);
|
||||
while (str.size() % 4) str += '=';
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const std::string& str)
|
||||
{
|
||||
return EncodeBase64((const unsigned char*)str.c_str(), str.size());
|
||||
}
|
||||
|
||||
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
|
||||
{
|
||||
static const int decode64_table[256] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
|
||||
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
|
||||
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
const char* e = p;
|
||||
std::vector<uint8_t> val;
|
||||
val.reserve(strlen(p));
|
||||
while (*p != 0) {
|
||||
int x = decode64_table[(unsigned char)*p];
|
||||
if (x == -1) break;
|
||||
val.push_back(x);
|
||||
++p;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ret;
|
||||
ret.reserve((val.size() * 3) / 4);
|
||||
bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
|
||||
|
||||
const char* q = p;
|
||||
while (valid && *p != 0) {
|
||||
if (*p != '=') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
valid = valid && (p - e) % 4 == 0 && p - q < 4;
|
||||
if (pf_invalid) *pf_invalid = !valid;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DecodeBase64(const std::string& str, bool* pf_invalid)
|
||||
{
|
||||
std::vector<unsigned char> vchRet = DecodeBase64(str.c_str(), pf_invalid);
|
||||
return std::string((const char*)vchRet.data(), vchRet.size());
|
||||
}
|
||||
|
||||
std::string EncodeBase32(const unsigned char* pch, size_t len)
|
||||
{
|
||||
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
|
||||
|
||||
std::string str;
|
||||
str.reserve(((len + 4) / 5) * 8);
|
||||
ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len);
|
||||
while (str.size() % 8) str += '=';
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string EncodeBase32(const std::string& str)
|
||||
{
|
||||
return EncodeBase32((const unsigned char*)str.c_str(), str.size());
|
||||
}
|
||||
|
||||
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
|
||||
{
|
||||
static const int decode32_table[256] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2,
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
const char* e = p;
|
||||
std::vector<uint8_t> val;
|
||||
val.reserve(strlen(p));
|
||||
while (*p != 0) {
|
||||
int x = decode32_table[(unsigned char)*p];
|
||||
if (x == -1) break;
|
||||
val.push_back(x);
|
||||
++p;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ret;
|
||||
ret.reserve((val.size() * 5) / 8);
|
||||
bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
|
||||
|
||||
const char* q = p;
|
||||
while (valid && *p != 0) {
|
||||
if (*p != '=') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
valid = valid && (p - e) % 8 == 0 && p - q < 8;
|
||||
if (pf_invalid) *pf_invalid = !valid;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DecodeBase32(const std::string& str, bool* pf_invalid)
|
||||
{
|
||||
std::vector<unsigned char> vchRet = DecodeBase32(str.c_str(), pf_invalid);
|
||||
return std::string((const char*)vchRet.data(), vchRet.size());
|
||||
}
|
||||
|
||||
NODISCARD static bool ParsePrechecks(const std::string& str)
|
||||
{
|
||||
if (str.empty()) // No empty string allowed
|
||||
return false;
|
||||
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size()-1]))) // No padding allowed
|
||||
return false;
|
||||
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseInt32(const std::string& str, int32_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = nullptr;
|
||||
errno = 0; // strtol will not set errno if valid
|
||||
long int n = strtol(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int32_t)n;
|
||||
// Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||
// platforms the size of these types may be different.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int32_t>::min() &&
|
||||
n <= std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
|
||||
bool ParseInt64(const std::string& str, int64_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = nullptr;
|
||||
errno = 0; // strtoll will not set errno if valid
|
||||
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int64_t)n;
|
||||
// Note that strtoll returns a *long long int*, so even if strtol doesn't report an over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int64_t>::min() &&
|
||||
n <= std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
|
||||
bool ParseUInt32(const std::string& str, uint32_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
|
||||
return false;
|
||||
char *endp = nullptr;
|
||||
errno = 0; // strtoul will not set errno if valid
|
||||
unsigned long int n = strtoul(str.c_str(), &endp, 10);
|
||||
if(out) *out = (uint32_t)n;
|
||||
// Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
|
||||
// we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
|
||||
// platforms the size of these types may be different.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n <= std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
bool ParseUInt64(const std::string& str, uint64_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range
|
||||
return false;
|
||||
char *endp = nullptr;
|
||||
errno = 0; // strtoull will not set errno if valid
|
||||
unsigned long long int n = strtoull(str.c_str(), &endp, 10);
|
||||
if(out) *out = (uint64_t)n;
|
||||
// Note that strtoull returns a *unsigned long long int*, so even if it doesn't report an over/underflow
|
||||
// we still have to check that the returned value is within the range of an *uint64_t*.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n <= std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
|
||||
bool ParseDouble(const std::string& str, double *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||
return false;
|
||||
std::istringstream text(str);
|
||||
text.imbue(std::locale::classic());
|
||||
double result;
|
||||
text >> result;
|
||||
if(out) *out = result;
|
||||
return text.eof() && !text.fail();
|
||||
}
|
||||
|
||||
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
|
||||
{
|
||||
std::stringstream out;
|
||||
size_t ptr = 0;
|
||||
size_t indented = 0;
|
||||
while (ptr < in.size())
|
||||
{
|
||||
size_t lineend = in.find_first_of('\n', ptr);
|
||||
if (lineend == std::string::npos) {
|
||||
lineend = in.size();
|
||||
}
|
||||
const size_t linelen = lineend - ptr;
|
||||
const size_t rem_width = width - indented;
|
||||
if (linelen <= rem_width) {
|
||||
out << in.substr(ptr, linelen + 1);
|
||||
ptr = lineend + 1;
|
||||
indented = 0;
|
||||
} else {
|
||||
size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
|
||||
if (finalspace == std::string::npos || finalspace < ptr) {
|
||||
// No place to break; just include the entire word and move on
|
||||
finalspace = in.find_first_of("\n ", ptr);
|
||||
if (finalspace == std::string::npos) {
|
||||
// End of the string, just add it and break
|
||||
out << in.substr(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
out << in.substr(ptr, finalspace - ptr) << "\n";
|
||||
if (in[finalspace] == '\n') {
|
||||
indented = 0;
|
||||
} else if (indent) {
|
||||
out << std::string(indent, ' ');
|
||||
indented = indent;
|
||||
}
|
||||
ptr = finalspace + 1;
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string i64tostr(int64_t n)
|
||||
{
|
||||
return strprintf("%d", n);
|
||||
}
|
||||
|
||||
std::string itostr(int n)
|
||||
{
|
||||
return strprintf("%d", n);
|
||||
}
|
||||
|
||||
int64_t atoi64(const char* psz)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _atoi64(psz);
|
||||
#else
|
||||
return strtoll(psz, nullptr, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t atoi64(const std::string& str)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _atoi64(str.c_str());
|
||||
#else
|
||||
return strtoll(str.c_str(), nullptr, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
int atoi(const std::string& str)
|
||||
{
|
||||
return atoi(str.c_str());
|
||||
}
|
||||
|
||||
/** Upper bound for mantissa.
|
||||
* 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
|
||||
* Larger integers cannot consist of arbitrary combinations of 0-9:
|
||||
*
|
||||
* 999999999999999999 1^18-1
|
||||
* 9223372036854775807 (1<<63)-1 (max int64_t)
|
||||
* 9999999999999999999 1^19-1 (would overflow)
|
||||
*/
|
||||
static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
|
||||
|
||||
/** Helper function for ParseFixedPoint */
|
||||
static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
|
||||
{
|
||||
if(ch == '0')
|
||||
++mantissa_tzeros;
|
||||
else {
|
||||
for (int i=0; i<=mantissa_tzeros; ++i) {
|
||||
if (mantissa > (UPPER_BOUND / 10LL))
|
||||
return false; /* overflow */
|
||||
mantissa *= 10;
|
||||
}
|
||||
mantissa += ch - '0';
|
||||
mantissa_tzeros = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
|
||||
{
|
||||
int64_t mantissa = 0;
|
||||
int64_t exponent = 0;
|
||||
int mantissa_tzeros = 0;
|
||||
bool mantissa_sign = false;
|
||||
bool exponent_sign = false;
|
||||
int ptr = 0;
|
||||
int end = val.size();
|
||||
int point_ofs = 0;
|
||||
|
||||
if (ptr < end && val[ptr] == '-') {
|
||||
mantissa_sign = true;
|
||||
++ptr;
|
||||
}
|
||||
if (ptr < end)
|
||||
{
|
||||
if (val[ptr] == '0') {
|
||||
/* pass single 0 */
|
||||
++ptr;
|
||||
} else if (val[ptr] >= '1' && val[ptr] <= '9') {
|
||||
while (ptr < end && IsDigit(val[ptr])) {
|
||||
if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
|
||||
return false; /* overflow */
|
||||
++ptr;
|
||||
}
|
||||
} else return false; /* missing expected digit */
|
||||
} else return false; /* empty string or loose '-' */
|
||||
if (ptr < end && val[ptr] == '.')
|
||||
{
|
||||
++ptr;
|
||||
if (ptr < end && IsDigit(val[ptr]))
|
||||
{
|
||||
while (ptr < end && IsDigit(val[ptr])) {
|
||||
if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
|
||||
return false; /* overflow */
|
||||
++ptr;
|
||||
++point_ofs;
|
||||
}
|
||||
} else return false; /* missing expected digit */
|
||||
}
|
||||
if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
|
||||
{
|
||||
++ptr;
|
||||
if (ptr < end && val[ptr] == '+')
|
||||
++ptr;
|
||||
else if (ptr < end && val[ptr] == '-') {
|
||||
exponent_sign = true;
|
||||
++ptr;
|
||||
}
|
||||
if (ptr < end && IsDigit(val[ptr])) {
|
||||
while (ptr < end && IsDigit(val[ptr])) {
|
||||
if (exponent > (UPPER_BOUND / 10LL))
|
||||
return false; /* overflow */
|
||||
exponent = exponent * 10 + val[ptr] - '0';
|
||||
++ptr;
|
||||
}
|
||||
} else return false; /* missing expected digit */
|
||||
}
|
||||
if (ptr != end)
|
||||
return false; /* trailing garbage */
|
||||
|
||||
/* finalize exponent */
|
||||
if (exponent_sign)
|
||||
exponent = -exponent;
|
||||
exponent = exponent - point_ofs + mantissa_tzeros;
|
||||
|
||||
/* finalize mantissa */
|
||||
if (mantissa_sign)
|
||||
mantissa = -mantissa;
|
||||
|
||||
/* convert to one 64-bit fixed-point value */
|
||||
exponent += decimals;
|
||||
if (exponent < 0)
|
||||
return false; /* cannot represent values smaller than 10^-decimals */
|
||||
if (exponent >= 18)
|
||||
return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
|
||||
|
||||
for (int i=0; i < exponent; ++i) {
|
||||
if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
|
||||
return false; /* overflow */
|
||||
mantissa *= 10;
|
||||
}
|
||||
if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
|
||||
return false; /* overflow */
|
||||
|
||||
if (amount_out)
|
||||
*amount_out = mantissa;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Downcase(std::string& str)
|
||||
{
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](char c){return ToLower(c);});
|
||||
}
|
||||
|
||||
std::string Capitalize(std::string str)
|
||||
{
|
||||
if (str.empty()) return str;
|
||||
str[0] = ToUpper(str.front());
|
||||
return str;
|
||||
}
|
242
lib/bip158/src/util/strencodings.h
Normal file
242
lib/bip158/src/util/strencodings.h
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
/**
|
||||
* Utilities for converting data from/to strings.
|
||||
*/
|
||||
#ifndef BITCOIN_UTIL_STRENCODINGS_H
|
||||
#define BITCOIN_UTIL_STRENCODINGS_H
|
||||
|
||||
#include <attributes.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
|
||||
|
||||
/** Used by SanitizeString() */
|
||||
enum SafeChars
|
||||
{
|
||||
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
|
||||
SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
|
||||
SAFE_CHARS_FILENAME, //!< Chars allowed in filenames
|
||||
SAFE_CHARS_URI, //!< Chars allowed in URIs (RFC 3986)
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
|
||||
* addresses, but avoid anything even possibly remotely dangerous like & or >
|
||||
* @param[in] str The string to sanitize
|
||||
* @param[in] rule The set of safe chars to choose (default: least restrictive)
|
||||
* @return A new string without unsafe chars
|
||||
*/
|
||||
std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);
|
||||
std::vector<unsigned char> ParseHex(const char* psz);
|
||||
std::vector<unsigned char> ParseHex(const std::string& str);
|
||||
signed char HexDigit(char c);
|
||||
/* Returns true if each character in str is a hex character, and has an even
|
||||
* number of hex digits.*/
|
||||
bool IsHex(const std::string& str);
|
||||
/**
|
||||
* Return true if the string is a hex number, optionally prefixed with "0x"
|
||||
*/
|
||||
bool IsHexNumber(const std::string& str);
|
||||
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
|
||||
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
|
||||
std::string EncodeBase64(const unsigned char* pch, size_t len);
|
||||
std::string EncodeBase64(const std::string& str);
|
||||
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
|
||||
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
|
||||
std::string EncodeBase32(const unsigned char* pch, size_t len);
|
||||
std::string EncodeBase32(const std::string& str);
|
||||
|
||||
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
|
||||
std::string i64tostr(int64_t n);
|
||||
std::string itostr(int n);
|
||||
int64_t atoi64(const char* psz);
|
||||
int64_t atoi64(const std::string& str);
|
||||
int atoi(const std::string& str);
|
||||
|
||||
/**
|
||||
* Tests if the given character is a decimal digit.
|
||||
* @param[in] c character to test
|
||||
* @return true if the argument is a decimal digit; otherwise false.
|
||||
*/
|
||||
constexpr bool IsDigit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the given character is a whitespace character. The whitespace characters
|
||||
* are: space, form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
|
||||
* tab ('\t'), and vertical tab ('\v').
|
||||
*
|
||||
* This function is locale independent. Under the C locale this function gives the
|
||||
* same result as std::isspace.
|
||||
*
|
||||
* @param[in] c character to test
|
||||
* @return true if the argument is a whitespace character; otherwise false
|
||||
*/
|
||||
constexpr inline bool IsSpace(char c) noexcept {
|
||||
return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to signed 32-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
NODISCARD bool ParseInt32(const std::string& str, int32_t *out);
|
||||
|
||||
/**
|
||||
* Convert string to signed 64-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
NODISCARD bool ParseInt64(const std::string& str, int64_t *out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
NODISCARD bool ParseUInt32(const std::string& str, uint32_t *out);
|
||||
|
||||
/**
|
||||
* Convert decimal string to unsigned 64-bit integer with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid integer,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
NODISCARD bool ParseUInt64(const std::string& str, uint64_t *out);
|
||||
|
||||
/**
|
||||
* Convert string to double with strict parse error feedback.
|
||||
* @returns true if the entire string could be parsed as valid double,
|
||||
* false if not the entire string could be parsed or when overflow or underflow occurred.
|
||||
*/
|
||||
NODISCARD bool ParseDouble(const std::string& str, double *out);
|
||||
|
||||
template<typename T>
|
||||
std::string HexStr(const T itbegin, const T itend)
|
||||
{
|
||||
std::string rv;
|
||||
static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
rv.reserve(std::distance(itbegin, itend) * 2);
|
||||
for(T it = itbegin; it < itend; ++it)
|
||||
{
|
||||
unsigned char val = (unsigned char)(*it);
|
||||
rv.push_back(hexmap[val>>4]);
|
||||
rv.push_back(hexmap[val&15]);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::string HexStr(const T& vch)
|
||||
{
|
||||
return HexStr(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a paragraph of text to a fixed width, adding spaces for
|
||||
* indentation to any added line.
|
||||
*/
|
||||
std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0);
|
||||
|
||||
/**
|
||||
* Timing-attack-resistant comparison.
|
||||
* Takes time proportional to length
|
||||
* of first argument.
|
||||
*/
|
||||
template <typename T>
|
||||
bool TimingResistantEqual(const T& a, const T& b)
|
||||
{
|
||||
if (b.size() == 0) return a.size() == 0;
|
||||
size_t accumulator = a.size() ^ b.size();
|
||||
for (size_t i = 0; i < a.size(); i++)
|
||||
accumulator |= a[i] ^ b[i%b.size()];
|
||||
return accumulator == 0;
|
||||
}
|
||||
|
||||
/** Parse number as fixed point according to JSON number syntax.
|
||||
* See http://json.org/number.gif
|
||||
* @returns true on success, false on error.
|
||||
* @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
|
||||
*/
|
||||
NODISCARD bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
|
||||
|
||||
/** Convert from one power-of-2 number base to another. */
|
||||
template<int frombits, int tobits, bool pad, typename O, typename I>
|
||||
bool ConvertBits(const O& outfn, I it, I end) {
|
||||
size_t acc = 0;
|
||||
size_t bits = 0;
|
||||
constexpr size_t maxv = (1 << tobits) - 1;
|
||||
constexpr size_t max_acc = (1 << (frombits + tobits - 1)) - 1;
|
||||
while (it != end) {
|
||||
acc = ((acc << frombits) | *it) & max_acc;
|
||||
bits += frombits;
|
||||
while (bits >= tobits) {
|
||||
bits -= tobits;
|
||||
outfn((acc >> bits) & maxv);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (pad) {
|
||||
if (bits) outfn((acc << (tobits - bits)) & maxv);
|
||||
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given character to its lowercase equivalent.
|
||||
* This function is locale independent. It only converts uppercase
|
||||
* characters in the standard 7-bit ASCII range.
|
||||
* @param[in] c the character to convert to lowercase.
|
||||
* @return the lowercase equivalent of c; or the argument
|
||||
* if no conversion is possible.
|
||||
*/
|
||||
constexpr char ToLower(char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given string to its lowercase equivalent.
|
||||
* This function is locale independent. It only converts uppercase
|
||||
* characters in the standard 7-bit ASCII range.
|
||||
* @param[in,out] str the string to convert to lowercase.
|
||||
*/
|
||||
void Downcase(std::string& str);
|
||||
|
||||
/**
|
||||
* Converts the given character to its uppercase equivalent.
|
||||
* This function is locale independent. It only converts lowercase
|
||||
* characters in the standard 7-bit ASCII range.
|
||||
* @param[in] c the character to convert to uppercase.
|
||||
* @return the uppercase equivalent of c; or the argument
|
||||
* if no conversion is possible.
|
||||
*/
|
||||
constexpr char ToUpper(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes the first character of the given string.
|
||||
* This function is locale independent. It only capitalizes the
|
||||
* first character of the argument if it has an uppercase equivalent
|
||||
* in the standard 7-bit ASCII range.
|
||||
* @param[in] str the string to capitalize.
|
||||
* @return string with the first letter capitalized.
|
||||
*/
|
||||
std::string Capitalize(std::string str);
|
||||
|
||||
#endif // BITCOIN_UTIL_STRENCODINGS_H
|
62
lib/bip158/src/util/threadnames.cpp
Normal file
62
lib/bip158/src/util/threadnames.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#include <util/threadnames.h>
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h> // For prctl, PR_SET_NAME, PR_GET_NAME
|
||||
#endif
|
||||
|
||||
//! Set the thread's name at the process level. Does not affect the
|
||||
//! internal name.
|
||||
static void SetThreadName(const char* name)
|
||||
{
|
||||
#if defined(PR_SET_NAME)
|
||||
// Only the first 15 characters are used (16 - NUL terminator)
|
||||
::prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif defined(MAC_OSX)
|
||||
pthread_setname_np(name);
|
||||
#else
|
||||
// Prevent warnings for unused parameters...
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
|
||||
// If we have thread_local, just keep thread ID and name in a thread_local
|
||||
// global.
|
||||
#if defined(HAVE_THREAD_LOCAL)
|
||||
|
||||
static thread_local std::string g_thread_name;
|
||||
const std::string& util::ThreadGetInternalName() { return g_thread_name; }
|
||||
//! Set the in-memory internal name for this thread. Does not affect the process
|
||||
//! name.
|
||||
static void SetInternalName(std::string name) { g_thread_name = std::move(name); }
|
||||
|
||||
// Without thread_local available, don't handle internal name at all.
|
||||
#else
|
||||
|
||||
static const std::string empty_string;
|
||||
const std::string& util::ThreadGetInternalName() { return empty_string; }
|
||||
static void SetInternalName(std::string name) { }
|
||||
#endif
|
||||
|
||||
void util::ThreadRename(std::string&& name)
|
||||
{
|
||||
SetThreadName(("bitcoin-" + name).c_str());
|
||||
SetInternalName(std::move(name));
|
||||
}
|
21
lib/bip158/src/util/threadnames.h
Normal file
21
lib/bip158/src/util/threadnames.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_THREADNAMES_H
|
||||
#define BITCOIN_UTIL_THREADNAMES_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace util {
|
||||
//! Rename a thread both in terms of an internal (in-memory) name as well
|
||||
//! as its system thread name.
|
||||
void ThreadRename(std::string&&);
|
||||
|
||||
//! Get the thread's internal (in-memory) name; used e.g. for identification in
|
||||
//! logging.
|
||||
const std::string& ThreadGetInternalName();
|
||||
|
||||
} // namespace util
|
||||
|
||||
#endif // BITCOIN_UTIL_THREADNAMES_H
|
113
lib/bip158/src/util/time.cpp
Normal file
113
lib/bip158/src/util/time.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
|
||||
#include <util/time.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <ctime>
|
||||
#include <tinyformat.h>
|
||||
|
||||
static std::atomic<int64_t> nMockTime(0); //!< For unit testing
|
||||
|
||||
int64_t GetTime()
|
||||
{
|
||||
int64_t mocktime = nMockTime.load(std::memory_order_relaxed);
|
||||
if (mocktime) return mocktime;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
assert(now > 0);
|
||||
return now;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetTime()
|
||||
{
|
||||
const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};
|
||||
|
||||
return std::chrono::duration_cast<T>(
|
||||
mocktime.count() ?
|
||||
mocktime :
|
||||
std::chrono::microseconds{GetTimeMicros()});
|
||||
}
|
||||
template std::chrono::seconds GetTime();
|
||||
template std::chrono::milliseconds GetTime();
|
||||
template std::chrono::microseconds GetTime();
|
||||
|
||||
void SetMockTime(int64_t nMockTimeIn)
|
||||
{
|
||||
nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
int64_t GetMockTime()
|
||||
{
|
||||
return nMockTime.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
int64_t GetTimeMillis()
|
||||
{
|
||||
int64_t now = (boost::posix_time::microsec_clock::universal_time() -
|
||||
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
|
||||
assert(now > 0);
|
||||
return now;
|
||||
}
|
||||
|
||||
int64_t GetTimeMicros()
|
||||
{
|
||||
int64_t now = (boost::posix_time::microsec_clock::universal_time() -
|
||||
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
|
||||
assert(now > 0);
|
||||
return now;
|
||||
}
|
||||
|
||||
int64_t GetSystemTimeInSeconds()
|
||||
{
|
||||
return GetTimeMicros()/1000000;
|
||||
}
|
||||
|
||||
void MilliSleep(int64_t n)
|
||||
{
|
||||
|
||||
/**
|
||||
* Boost's sleep_for was uninterruptible when backed by nanosleep from 1.50
|
||||
* until fixed in 1.52. Use the deprecated sleep method for the broken case.
|
||||
* See: https://svn.boost.org/trac/boost/ticket/7238
|
||||
*/
|
||||
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
|
||||
#elif defined(HAVE_WORKING_BOOST_SLEEP)
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(n));
|
||||
#else
|
||||
//should never get here
|
||||
#error missing boost sleep implementation
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FormatISO8601DateTime(int64_t nTime) {
|
||||
struct tm ts;
|
||||
time_t time_val = nTime;
|
||||
#ifdef _MSC_VER
|
||||
gmtime_s(&ts, &time_val);
|
||||
#else
|
||||
gmtime_r(&time_val, &ts);
|
||||
#endif
|
||||
return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
||||
}
|
||||
|
||||
std::string FormatISO8601Date(int64_t nTime) {
|
||||
struct tm ts;
|
||||
time_t time_val = nTime;
|
||||
#ifdef _MSC_VER
|
||||
gmtime_s(&ts, &time_val);
|
||||
#else
|
||||
gmtime_r(&time_val, &ts);
|
||||
#endif
|
||||
return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
|
||||
}
|
44
lib/bip158/src/util/time.h
Normal file
44
lib/bip158/src/util/time.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_TIME_H
|
||||
#define BITCOIN_UTIL_TIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
* Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
|
||||
*/
|
||||
int64_t GetTime();
|
||||
|
||||
/** Returns the system time (not mockable) */
|
||||
int64_t GetTimeMillis();
|
||||
/** Returns the system time (not mockable) */
|
||||
int64_t GetTimeMicros();
|
||||
/** Returns the system time (not mockable) */
|
||||
int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable
|
||||
|
||||
/** For testing. Set e.g. with the setmocktime rpc, or -mocktime argument */
|
||||
void SetMockTime(int64_t nMockTimeIn);
|
||||
/** For testing */
|
||||
int64_t GetMockTime();
|
||||
|
||||
void MilliSleep(int64_t n);
|
||||
|
||||
/** Return system time (or mocked time, if set) */
|
||||
template <typename T>
|
||||
T GetTime();
|
||||
|
||||
/**
|
||||
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}
|
||||
* helper functions if possible.
|
||||
*/
|
||||
std::string FormatISO8601DateTime(int64_t nTime);
|
||||
std::string FormatISO8601Date(int64_t nTime);
|
||||
|
||||
#endif // BITCOIN_UTIL_TIME_H
|
45
lib/bip158/src/version.h
Normal file
45
lib/bip158/src/version.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2012-2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_VERSION_H
|
||||
#define BITCOIN_VERSION_H
|
||||
|
||||
/**
|
||||
* network protocol versioning
|
||||
*/
|
||||
|
||||
static const int PROTOCOL_VERSION = 70015;
|
||||
|
||||
//! initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
|
||||
//! In this version, 'getheaders' was introduced.
|
||||
static const int GETHEADERS_VERSION = 31800;
|
||||
|
||||
//! disconnect from peers older than this proto version
|
||||
static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION;
|
||||
|
||||
//! nTime field added to CAddress, starting with this version;
|
||||
//! if possible, avoid requesting addresses nodes older than this
|
||||
static const int CADDR_TIME_VERSION = 31402;
|
||||
|
||||
//! BIP 0031, pong message, is enabled for all versions AFTER this one
|
||||
static const int BIP0031_VERSION = 60000;
|
||||
|
||||
//! "filter*" commands are disabled without NODE_BLOOM after and including this version
|
||||
static const int NO_BLOOM_VERSION = 70011;
|
||||
|
||||
//! "sendheaders" command and announcing blocks with headers starts with this version
|
||||
static const int SENDHEADERS_VERSION = 70012;
|
||||
|
||||
//! "feefilter" tells peers to filter invs to you by fee starts with this version
|
||||
static const int FEEFILTER_VERSION = 70013;
|
||||
|
||||
//! short-id-based block download starts with this version
|
||||
static const int SHORT_IDS_BLOCKS_VERSION = 70014;
|
||||
|
||||
//! not banning for invalid compact blocks starts with this version
|
||||
static const int INVALID_CB_NO_BAN_VERSION = 70015;
|
||||
|
||||
#endif // BITCOIN_VERSION_H
|
Loading…
Reference in New Issue
Block a user