From bafe2ee379ec1f396257015e31b7e9909e0fa498 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 07:40:22 +0100 Subject: [PATCH 01/27] Block Version Increase/CheckLockTimeVerify/Warning Fix/[WIP]ENUM for dDNS/net.cpp & netbase.cpp updates/min fee send fix for Silk-Qt --- .travis.yml | 6 +- Makefile.am | 2 + configure.ac | 6 +- contrib/gitian-descriptors/gitian-linux.yml | 1 + contrib/gitian-descriptors/gitian-osx.yml | 1 + contrib/gitian-descriptors/gitian-win.yml | 1 + depends/builders/darwin.mk | 2 +- depends/builders/linux.mk | 3 +- depends/config.guess | 2 +- depends/packages/miniupnpc.mk | 4 +- depends/packages/openssl.mk | 2 +- doc/Doxyfile | 2 +- qa/pull-tester/rpc-tests.sh | 5 - qa/rpc-tests/bip65-cltv-p2p.py | 175 ++++++++++ qa/rpc-tests/bip65-cltv.py | 89 +++++ src/addrman.h | 2 +- src/chainparams.cpp | 4 +- src/chainparams.h | 2 + src/checkpoints.cpp | 3 +- src/clientversion.h | 2 +- src/compat.h | 9 + src/dns/slkdns.cpp | 368 ++++++++++++++++++-- src/dns/slkdns.h | 41 ++- src/init.cpp | 18 +- src/leveldbwrapper.cpp | 2 +- src/main.cpp | 55 ++- src/main.h | 5 +- src/merkleblock.cpp | 2 +- src/net.cpp | 57 +-- src/netbase.cpp | 12 +- src/primitives/block.h | 2 +- src/qt/silk.cpp | 2 +- src/qt/walletmodel.cpp | 2 +- src/rpc/rpcregister.h | 5 +- src/script/interpreter.cpp | 80 ++++- src/script/interpreter.h | 12 +- src/script/script.h | 10 +- src/script/script_error.cpp | 4 + src/script/script_error.h | 4 + src/script/silkconsensus.h | 1 + src/script/standard.h | 4 +- src/silk-cli.cpp | 2 +- src/silk-tx.cpp | 2 +- src/silkd.cpp | 2 +- src/test/data/tx_invalid.json | 73 ++++ src/test/data/tx_valid.json | 41 +++ src/test/transaction_tests.cpp | 1 + src/uint256hm.h | 2 +- src/wallet/db.cpp | 2 +- 49 files changed, 1024 insertions(+), 110 deletions(-) create mode 100644 qa/rpc-tests/bip65-cltv-p2p.py create mode 100644 qa/rpc-tests/bip65-cltv.py diff --git a/.travis.yml b/.travis.yml index 17a3c93a..312af5a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,12 @@ language: cpp compiler: gcc + os: linux + sudo: required -dist: trusty +dist: precise +group: legacy + install: - sudo apt-get -qq update - sudo apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev libcrypto++-dev diff --git a/Makefile.am b/Makefile.am index 81f87e43..055686dd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -190,6 +190,8 @@ check-local: @qa/pull-tester/run-silkd-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) 2>&1 endif +dist_noinst_SCRIPTS = autogen.sh + EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/pull-tester/run-silk-cli qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) CLEANFILES = $(OSX_DMG) $(SILK_WIN_INSTALLER) diff --git a/configure.ac b/configure.ac index bc306208..2d749d76 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 1) -define(_CLIENT_VERSION_BUILD, 2) +define(_CLIENT_VERSION_BUILD, 3) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2017) AC_INIT([Silk Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[silk]) @@ -399,8 +399,8 @@ if test x$use_lcov = xyes; then [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) fi -dnl Check for endianness -AC_C_BIGENDIAN +dnl Require little endian +### ??? AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")]) dnl Check for pthread compile/link requirements AX_PTHREAD diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index a6e9f341..d313ba4c 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -6,6 +6,7 @@ suites: architectures: - "amd64" packages: +- "curl" - "g++-multilib" - "git-core" - "pkg-config" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 51d4dcd4..b35a9739 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -7,6 +7,7 @@ architectures: - "amd64" packages: - "g++-multilib" +- "curl" - "git-core" - "pkg-config" - "autoconf" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 3e53ae3a..01fef9d3 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -6,6 +6,7 @@ suites: architectures: - "amd64" packages: +- "curl" - "g++" - "git-core" - "pkg-config" diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index b366460e..200d6ed2 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index 98d0e9de..50931106 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,3 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = wget --timeout=$(DOWNLOAD_CONNECT_TIMEOUT) --tries=$(DOWNLOAD_RETRIES) -nv -O +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o +View diff --git a/depends/config.guess b/depends/config.guess index 1f5c50c0..55373193 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1099,7 +1099,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 00101f1b..77bae10c 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,8 +1,8 @@ package=miniupnpc -$(package)_version=1.9.20140701 +$(package)_version=1.9.20151008 $(package)_download_path=http://miniupnp.free.fr/files $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=26f3985bad7768b8483b793448ae49414cdc4451d0ec83e7c1944367e15f9f07 +$(package)_sha256_hash=e444ac3b587ce82709c4d0cfca1fe71f44f9fc433e9f946b12b9e1bfe667a633 define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index eb477941..492994b7 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -10,7 +10,7 @@ $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/o $(package)_config_opts+=no-krb5 no-camellia no-capieng no-cast no-cms no-dtls1 no-gost no-gmp no-heartbeats no-idea no-jpake no-md2 $(package)_config_opts+=no-mdc2 no-rc5 no-rdrand no-rfc3779 no-rsax no-sctp no-seed no-sha0 no-static_engine no-whirlpool no-rc2 no-rc4 no-ssl2 no-ssl3 $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) -$(package)_config_opts_linux=-fPIC +$(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32 diff --git a/doc/Doxyfile b/doc/Doxyfile index 1ca0751a..ca81a093 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -34,7 +34,7 @@ PROJECT_NAME = Silk # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.0.0.0 +PROJECT_NUMBER = 1.0.1.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index bf5a0023..cfbe902e 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -8,11 +8,6 @@ CURDIR=$(cd $(dirname "$0"); pwd) export SILKCLI=${BUILDDIR}/qa/pull-tester/run-silk-cli export SILKD=${REAL_SILKD} -if [ "x${EXEEXT}" = "x.exe" ]; then - echo "Win tests currently disabled" - exit 0 -fi - #Run the tests if [ "x${ENABLE_SILKD}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py new file mode 100644 index 00000000..ee100373 --- /dev/null +++ b/qa/rpc-tests/bip65-cltv-p2p.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python2 +# +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block +from test_framework.comptool import TestInstance, TestManager +from test_framework.script import CScript, OP_1NEGATE, OP_NOP2, OP_DROP +from binascii import hexlify, unhexlify +import cStringIO +import time + +def cltv_invalidate(tx): + '''Modify the signature in vin 0 of the tx to fail CLTV + + Prepends -1 CLTV DROP in the scriptSig itself. + ''' + tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP2, OP_DROP] + + list(CScript(tx.vin[0].scriptSig))) + +''' +This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY) +Connect to a single node. +Mine 2 (version 3) blocks (save the coinbases for later). +Generate 98 more version 3 blocks, verify the node accepts. +Mine 749 version 4 blocks, verify the node accepts. +Check that the new CLTV rules are not enforced on the 750th version 4 block. +Check that the new CLTV rules are enforced on the 751st version 4 block. +Mine 199 new version blocks. +Mine 1 old-version block. +Mine 1 new version block. +Mine 1 old version block, see that the node rejects. +''' + +class BIP65Test(ComparisonTestFramework): + + def __init__(self): + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']], + binary=[self.options.testbinary]) + + def run_test(self): + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + test.run() + + def create_transaction(self, node, coinbase, to_address, amount): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = cStringIO.StringIO(unhexlify(signresult['hex'])) + tx.deserialize(f) + return tx + + def get_tests(self): + + self.coinbase_blocks = self.nodes[0].setgenerate(True, 2) + self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) + self.nodeaddress = self.nodes[0].getnewaddress() + self.last_block_time = time.time() + + ''' 98 more version 3 blocks ''' + test_blocks = [] + for i in xrange(98): + block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 749 version 4 blocks ''' + test_blocks = [] + for i in xrange(749): + block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' + Check that the new CLTV rules are not enforced in the 750th + version 3 block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance([[block, True]]) + + ''' + Check that the new CLTV rules are enforced in the 751st version 4 + block. + ''' + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[1], self.nodeaddress, 1.0) + cltv_invalidate(spendtx) + spendtx.rehash() + + block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1) + block.nVersion = 4 + block.vtx.append(spendtx) + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + + ''' Mine 199 new version blocks on last valid tip ''' + test_blocks = [] + for i in xrange(199): + block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + test_blocks.append([block, True]) + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance(test_blocks, sync_every_block=False) + + ''' Mine 1 old version block ''' + block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance([[block, True]]) + + ''' Mine 1 new version block ''' + block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1) + block.nVersion = 4 + block.rehash() + block.solve() + self.last_block_time += 1 + self.tip = block.sha256 + yield TestInstance([[block, True]]) + + ''' Mine 1 old version block, should be invalid ''' + block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1) + block.nVersion = 3 + block.rehash() + block.solve() + self.last_block_time += 1 + yield TestInstance([[block, False]]) + +if __name__ == '__main__': + BIP65Test().main() \ No newline at end of file diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py new file mode 100644 index 00000000..e18dac6c --- /dev/null +++ b/qa/rpc-tests/bip65-cltv.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic +# + +from test_framework.test_framework import SilkTestFramework +from test_framework.util import * +import os +import shutil + +class BIP65Test(SilkTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, [])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"])) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some old-version blocks + self.nodes[1].setgenerate(True, 100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + raise AssertionError("Failed to mine 100 version=3 blocks") + + # Mine 750 new-version blocks + for i in xrange(15): + self.nodes[2].setgenerate(True, 50) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 850): + raise AssertionError("Failed to mine 750 version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced + + # Mine 1 new-version block + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 851): + raise AssertionFailure("Failed to mine a version=4 blocks") + + # TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced + + # Mine 198 new-version blocks + for i in xrange(2): + self.nodes[2].setgenerate(True, 99) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1049): + raise AssertionError("Failed to mine 198 version=4 blocks") + + # Mine 1 old-version block + self.nodes[1].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1050): + raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Failed to mine a version=4 block") + + # Mine 1 old-version blocks + try: + self.nodes[1].setgenerate(True, 1) + raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks") + except JSONRPCException: + pass + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Accepted a version=3 block after 950 version=4 blocks") + + # Mine 1 new-version blocks + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1052): + raise AssertionError("Failed to mine a version=4 block") + +if __name__ == '__main__': + BIP65Test().main() \ No newline at end of file diff --git a/src/addrman.h b/src/addrman.h index 286cc5ee..32423bd8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -268,7 +268,7 @@ class CAddrMan * Notice that vvTried, mapAddr and vVector are never encoded explicitly; * they are instead reconstructed from the other information. * - * vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change, + * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change, * otherwise it is reconstructed as well. * * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b26773e4..01b64a32 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -209,6 +209,7 @@ class CMainParams : public CChainParams { nStakeMaxAge = std::numeric_limits::max(); // Unlimited stake age nModifierInterval = 15 * 60; // 15 minutes to elapse before new modifier is computed nLastPOWBlock = 10000; // Proof of Work finishes on block 10000 + nMaxTipAge = 24 * 60 * 60; genesis = CreateGenesisBlock(1473949500, 37239843, bnProofOfWorkLimit.GetCompact(), 1, (0 * COIN)); @@ -272,6 +273,7 @@ class CTestNetParams : public CMainParams { nStakeMinAge = 30 * 60; // 30 minute minimum stake age nModifierInterval = 15 * 60; // 15 minutes to elapse before new modifier is computed nLastPOWBlock = 100000; // Proof of Work finishes on block 300000 + nMaxTipAge = 24 * 60 * 60; //bool startNewChain = true; genesis = CreateTestNetGenesisBlock(1478107000, 82131309, bnProofOfWorkLimit.GetCompact(), 1, (0 * COIN)); @@ -327,7 +329,7 @@ class CRegTestParams : public CTestNetParams { bnProofOfWorkLimit = ~uint256(0) >> 22; bnProofOfStakeLimit = ~uint256(0) >> 22; nLastPOWBlock = 100; // Proof of Work finishes on block 100 - + nMaxTipAge = 24 * 60 * 60; genesis = CreateGenesisBlock(1473949500, 1427578, 0x1e00ffff, 1, (0 * COIN)); diff --git a/src/chainparams.h b/src/chainparams.h index b817c233..9855ca22 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -81,6 +81,7 @@ class CChainParams int64_t StakeMaxAge() const { return nStakeMaxAge; } int64_t ModifierInterval() const { return nModifierInterval; } int LastPOWBlock() const { return nLastPOWBlock; } + int64_t MaxTipAge() const { return nMaxTipAge; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } @@ -109,6 +110,7 @@ class CChainParams int nRejectBlockOutdatedMajority; int nToCheckBlockUpgradeMajority; int nMinerThreads; + long nMaxTipAge; int64_t nTargetSpacingMax; int64_t nPoWTargetSpacing; int64_t nPoSTargetSpacing; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index e5c7109f..d1233c13 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -182,8 +182,7 @@ bool WriteSyncCheckpoint(const uint256& hashCheckpoint) { return error("WriteSyncCheckpoint(): failed to write to txdb sync checkpoint %s", hashCheckpoint.ToString()); } - if (!pblocktree->Sync()) - return error("WriteSyncCheckpoint(): failed to commit to txdb sync checkpoint %s", hashCheckpoint.ToString()); + FlushStateToDisk(); hashSyncCheckpoint = hashCheckpoint; return true; diff --git a/src/clientversion.h b/src/clientversion.h index 48d17ed7..7b77eac9 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -19,7 +19,7 @@ #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 1 -#define CLIENT_VERSION_BUILD 2 +#define CLIENT_VERSION_BUILD 3 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/compat.h b/src/compat.h index d6246fa2..5865f8c5 100644 --- a/src/compat.h +++ b/src/compat.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -91,4 +92,12 @@ typedef u_int SOCKET; size_t strnlen_int( const char *start, size_t max_len); +bool static inline IsSelectableSocket(SOCKET s) { +#ifdef WIN32 + return true; +#else + return (s < FD_SETSIZE); +#endif +} + #endif // SILK_COMPAT_H diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index 68a08440..8aa956b5 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -52,12 +52,15 @@ #define BUF_SIZE (512 + 512) #define MAX_OUT 512 // Old DNS restricts UDP to 512 bytes #define MAX_TOK 64 // Maximal TokenQty in the vsl_list, like A=IP1,..,IPn -#define MAX_DOM 10 // Maximal domain level +#define MAX_DOM 20 // Maximal domain level; min 10 is needed for NAPTR E164 #define VAL_SIZE (MAX_VALUE_LENGTH + 16) #define DNS_PREFIX "dns" #define REDEF_SYM '~' +// HT offset contains it for ENUM SPFUN +#define ENUM_FLAG (1 << 14) + /*---------------------------------------------------*/ #ifdef WIN32 @@ -89,11 +92,11 @@ int inet_pton(int af, const char *src, void *dst) /*---------------------------------------------------*/ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, - const char *gw_suffix, const char *allowed_suff, const char *local_fname, uint8_t verbose) - : m_status(0), m_thread(StatRun, this) { + const char *gw_suffix, const char *allowed_suff, const char *local_fname, const char *enums, uint8_t verbose) + : m_status(-1), m_thread(StatRun, this) { - // Set object to a new state - memset(this, 0, sizeof(SlkDns)); // Clear previous state + // Clear vars [m_hdr..m_verbose) + memset(&m_hdr, 0, &m_verbose - (uint8_t *)&m_hdr); // Clear previous state m_verbose = verbose; // Create and socket @@ -160,6 +163,19 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, if(m_value == NULL) throw runtime_error("SlkDns::SlkDns: Cannot allocate buffer"); + // Temporary use m_value for parse enum-verifiers, if exists + if(enums && *enums) { + char *str = strcpy(m_value, enums); + Verifier empty_ver; + while(char *p_tok = strsep(&str, "|,")) + if(*p_tok) { + if(m_verbose > 5) + LogPrintf("\tEmcDns::EmcDns: enumtrust=%s\n", p_tok); + m_verifiers[string(p_tok)] = empty_ver; + } + } // ENUMs completed + + // Assign data buffers inside m_value hyper-array m_buf = (uint8_t *)(m_value + VAL_SIZE); m_bufend = m_buf + MAX_OUT; char *varbufs = m_value + VAL_SIZE + BUF_SIZE + 2; @@ -177,18 +193,28 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, *p = pos = step = 0; continue; } - if(c == '.') { + if(c == '.' || c == '$') { + *p = 64; if(p[1] > 040) { // if allowed domain is not empty - save it into ht step |= 1; - if(m_verbose > 3) - LogPrintf("\tSlkDns::SlkDns: Insert TLD=%s: pos=%u step=%u\n", p + 1, pos, step); do pos += step; while(m_ht_offset[pos] != 0); m_ht_offset[pos] = p + 1 - m_allowed_base; + const char *dnstype = "DNS"; + if(c == '$') { + m_ht_offset[pos] |= ENUM_FLAG; + char *pp = p; // ref to $ + while(--pp >= m_allowed_base && *pp >= '0' && *pp <= '9'); + if(++pp < p) + *p = atoi(pp); + dnstype = "ENUM"; + } m_allowed_qty++; + if(m_verbose > 3) + LogPrintf("\tSlkDns::EmcDns: Insert %s TLD=%s:%u\n", dnstype, p + 1, *p); } - *p = pos = step = 0; + pos = step = 0; continue; } pos = ((pos >> 7) | (pos << 1)) + c; @@ -226,7 +252,7 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, m_address.sin_addr.s_addr == INADDR_ANY? "INADDR_ANY" : bind_ip, port_no, m_allowed_qty, local_qty); - m_status = 1; // Active + m_status = 1; // Active, and maybe download } // SlkDns::SlkDns /*---------------------------------------------------*/ @@ -258,8 +284,8 @@ void SlkDns::StatRun(void *p) { void SlkDns::Run() { if(m_verbose > 2) LogPrintf("SlkDns::Run: started\n"); - while(m_status == 0) - MilliSleep(133); + while(m_status < 0) // not initied yet + MilliSleep(133); for( ; ; ) { m_addrLen = sizeof(m_clientAddress); @@ -329,13 +355,16 @@ void SlkDns::HandlePacket() { break; } - if(IsInitialBlockDownload()) { - m_hdr->Bits |= 2; // Server failure - not available valud nameindex DB yet +// if(IsInitialBlockDownload()) { + if(m_status && (m_status = IsInitialBlockDownload())) { + m_hdr->Bits |= 2; // Server failure - not available valid nameindex DB yet break; } // Handle questions here - for(uint16_t qno = 0; qno < m_hdr->QDCount && m_snd < m_bufend; qno--) { + for(uint16_t qno = 0; qno < m_hdr->QDCount && m_snd < m_bufend; qno++) { + if(m_verbose > 5) + LogPrintf("\tSlkDns::HandlePacket: qno=%u m_hdr->QDCount=%u\n", qno, m_hdr->QDCount); uint16_t rc = HandleQuery(); if(rc) { m_hdr->Bits |= rc; @@ -371,7 +400,7 @@ uint16_t SlkDns::HandleQuery() { uint8_t key[BUF_SIZE]; // Key, transformed to dot-separated LC uint8_t *key_end = key; uint8_t *domain_ndx[MAX_DOM]; // indexes to domains - uint8_t **domain_ndx_p = domain_ndx; // Ptr to end + uint8_t **domain_ndx_p = domain_ndx; // Ptr to the end // m_rcv is pointer to QNAME // Set reference to domain label @@ -386,10 +415,10 @@ uint16_t SlkDns::HandleQuery() { return 1; // Invalid request *domain_ndx_p++ = key_end; do { - *key_end++ = tolower(*m_rcv++); + *key_end++ = 040 | *m_rcv++; } while(--dom_len); *key_end++ = '.'; // Set DOT at domain end - } + } // while(dom_len) *--key_end = 0; // Remove last dot, set EOLN if(m_verbose > 3) @@ -404,9 +433,9 @@ uint16_t SlkDns::HandleQuery() { if(qclass != 1) return 4; // Not implemented - support INET only - // If thid is puplic gateway, gw-suffix can be specified, like + // If thid is public gateway, gw-suffix can be specified, like // slkdnssuffix=.xyz.com - // Followind block cuts this suffix, if exist. + // Followind block cuts this suffix, if exists. // If received domain name "xyz.com" only, keyp is empty string if(m_gw_suf_len) { // suffix defined [public DNS], need to cut @@ -468,7 +497,12 @@ uint16_t SlkDns::HandleQuery() { LogPrintf("SlkDns::HandleQuery: TLD-suffix=[.%s] in given key=%s is not allowed; return NXDOMAIN\n", p, key); return 3; // Reached EndOfList, so NXDOMAIN } - } while(m_ht_offset[pos] < 0 || strcmp((const char *)p, m_allowed_base + m_ht_offset[pos]) != 0); + } while(m_ht_offset[pos] < 0 || strcmp((const char *)p, m_allowed_base + (m_ht_offset[pos] & ~ENUM_FLAG)) != 0); + + // ENUM SPFUN works only if TLD-filter is active + if(m_ht_offset[pos] & ENUM_FLAG) + return SpfunENUM(m_allowed_base[(m_ht_offset[pos] & ~ENUM_FLAG) - 1], domain_ndx, domain_ndx_p); + } // if(m_allowed_qty) uint8_t **cur_ndx_p, **prev_ndx_p = domain_ndx_p - 2; @@ -611,7 +645,7 @@ void SlkDns::Answer_ALL(uint16_t qtype, char *buf) { case 16 : key = "TXT"; break; case 28 : key = "AAAA"; break; default: return; - } // swithc + } // switch char *tokens[MAX_TOK]; int tokQty = Tokenize(key, ",", tokens, buf); @@ -760,3 +794,293 @@ DNSAP *SlkDns::CheckDAP(uint32_t ip_addr) { return (dap->ed_size <= SLKDNS_DAPTRESHOLD)? dap : NULL; } // SlkDns::CheckDAP + +/*---------------------------------------------------*/ +// Handle Special function - phone number in the E.164 format +// to support ENUM service +int SlkDns::SpfunENUM(uint8_t len, uint8_t **domain_start, uint8_t **domain_end) { + int dom_length = domain_end - domain_start; + const char *tld = (const char*)domain_end[-1]; + + if(m_verbose > 3) + LogPrintf("\tSlkDns::SpfunENUM: Domain=[%s] N=%u TLD=[%s] Len=%u\n", + (const char*)*domain_start, dom_length, tld, len); + + do { + if(dom_length < 2) + break; // no domains for phone number - NXDOMAIN + + if(m_verifiers.empty()) + break; // no verifier - all ENUMs untrusted + + char itut_num[68], *pitut = itut_num, *pitutend = itut_num + len; + for(const uint8_t *p = domain_end[-1]; --p >= *domain_start; ) + if(*p >= '0' && *p <= '9') { + *pitut++ = *p; + if(pitut >= pitutend) + break; + } + *pitut = 0; // EOLN at phone number end + + if(pitut == itut_num) + break; // Empty phone number - NXDOMAIN + + if(m_verbose > 3) + LogPrintf("\tSlkDns::SpfunENUM: ITU-T num=[%s]\n", itut_num); + + // Itrrate all available ENUM-records, and build joined answer from them + for(int16_t qno = 0; qno >= 0; qno++) { + char q_str[100]; + sprintf(q_str, "%s:%s:%u", tld, itut_num, qno); + if(m_verbose > 1) + LogPrintf("\tSlkDns::SpfunENUM Search(%s)\n", q_str); + + string value; + if(!hooks->getNameValue(string(q_str), value)) + return m_hdr->ANCount? 0 : 3; + + strcpy(m_value, value.c_str()); + Answer_ENUM(q_str); + } // for + + } while(false); + + return 3; // NXDOMAIN +} // SlkDns::SpfunENUM + +/*---------------------------------------------------*/ + +#define ENC3(a, b, c) (a | (b << 8) | (c << 16)) + +/*---------------------------------------------------*/ +// Generate answewr for found EMUM NVS record +void SlkDns::Answer_ENUM(const char *q_str) { + char *str_val = m_value; + const char *pttl; + char *e2u[VAL_SIZE / 4]; // 20kb max input, and min 4 bytes per token + uint16_t e2uN = 0; + bool sigOK = false; + + m_ttl = 24 * 3600; // 24h by default + + // Tokenize lines in the NVS-value. + // There can be prefixes SIG=, TTL=, E2U + while(char *tok = strsep(&str_val, "\n\r")) + switch(*(uint32_t*)tok & 0xffffff | 0x202020) { + case ENC3('e', '2', 'u'): + e2u[e2uN++] = tok; + continue; + + case ENC3('t', 't', 'l'): + pttl = strchr(tok + 3, '='); + if(pttl) + m_ttl = atoi(pttl + 1); + continue; + + case ENC3('s', 'i', 'g'): + if(!sigOK) + sigOK = CheckEnumSig(q_str, strchr(tok + 3, '=')); + continue; + + default: + continue; + } // while + switch + + if(!sigOK) + return; // This ENUM-record does not contain a valid signature + + // Generate ENUM-answers here + for(uint16_t e2undx = 0; e2undx < e2uN; e2undx++) + if(m_snd < m_bufend - 24) + HandleE2U(e2u[e2undx]); + +} // EmcDns::Answer_ENUM + +/*---------------------------------------------------*/ +void SlkDns::OutS(const char *p) { + int len = strlen(strcpy((char *)m_snd + 1, p)); + *m_snd = len; + m_snd += len + 1; +} // SlkDns::OutS + +/*---------------------------------------------------*/ + // Generate ENUM-answers for a single E2U entry + // E2U+sip=100|10|!^(.*)$!sip:17771234567@in.callcentric.com! +void SlkDns::HandleE2U(char *e2u) { + char *data = strchr(e2u, '='), *p = data; + if(data == NULL) + return; + + // Cleanum sufix for service; Service started from E2U + for(char *p = data; *--p <= 040; *p = 0) {} + + unsigned int ord, pref; + char re[VAL_SIZE]; + + *data++ = 0; // Remove '=' + + if(sscanf(data, "%u | %u | %s", &ord, &pref, re) != 3) + return; + + if(m_verbose > 3) + LogPrintf("\tEmcDns::HandleE2U: Parsed: %u %u %s %s\n", ord, pref, e2u, re); + + if(m_snd + strlen(re) + strlen(e2u) + 24 >= m_bufend) + return; + + Out2(m_label_ref); + Out2(0x23); // NAPTR record + Out2(1); // INET + Out4(m_ttl); + uint8_t *snd0 = m_snd; m_snd += 2; + Out2(ord); + Out2(pref); + OutS("u"); + OutS(e2u); + OutS(re); + *m_snd++ = 0; + + uint16_t len = m_snd - snd0 - 2; + *snd0++ = len >> 8; + *snd0++ = len; + + m_hdr->ANCount++; +} // SlkDns::HandleE2U + +/*---------------------------------------------------*/ +bool SlkDns::CheckEnumSig(const char *q_str, char *sig_str) { + if(sig_str == NULL) + return false; + + // skip SP/TABs in signature + while(*++sig_str <= ' '); + + char *signature = strchr(sig_str, '|'); + if(signature == NULL) + return false; + + for(char *p = signature; *--p <= 040; *p = 0) {} + *signature++ = 0; + + map::iterator it = m_verifiers.find(sig_str); + if(it == m_verifiers.end()) + return false; // Unknown verifier - do not trust it + + Verifier &ver = it->second; + + if(ver.mask < 0) { + if(ver.mask == VERMASK_BLOCKED) + return false; // Already unable to fetch + + do { + NameTxInfo nti; + CNameRecord nameRec; + CTransaction tx; + LOCK(cs_main); + CNameDB dbName("r"); + if(!dbName.ReadName(CNameVal(it->first.c_str(), it->first.c_str() + it->first.size()), nameRec)) + break; // failed to read from name DB + if(nameRec.vtxPos.size() < 1) + break; // no result returned + if(!tx.ReadFromDisk(nameRec.vtxPos.back().txPos)) + break; // failed to read from from disk + if(!DecodeNameTx(tx, nti, true)) + break; // failed to decode name + CSilkAddress addr(nti.strAddress); + if(!addr.IsValid()) + break; // Invalid address + if(!addr.GetKeyID(ver.keyID)) + break; // Address does not refer to key + + // Verifier has been read successfully, configure SRL if exist + char valbuf[VAL_SIZE], *str_val = valbuf; + memcpy(valbuf, &nti.value[0], nti.value.size()); + valbuf[nti.value.size()] = 0; + + // Proces SRL-line like + // SRL=5|srl:hello-%02x + ver.mask = VERMASK_NOSRL; + while(char *tok = strsep(&str_val, "\n\r")) + if((*(uint32_t*)tok & 0xffffff | 0x202020) == ENC3('s', 'r', 'l') && (tok = strchr(tok + 3, '='))) { + unsigned nbits = atoi(++tok); + if(nbits > 30) nbits = 30; + ///mask = (1 << mask) - 1; + tok = strchr(tok, '|'); + if(tok != NULL) { + do { + if(*++tok == 0) + break; // empty SRL, thus keep VERMASK_NOSRL + char *pp = strchr(tok, '%'); + if(pp != NULL) { + if(*++pp == '0') + do ++pp; while(*pp >= '0' && *pp <= '9'); + if(strchr("diouXx", *pp) == NULL) + break; // Invalid char in the template + if(strchr(pp, '%')) + break; // Not allowed 2nd % symbol + } else + nbits = 0; // Don't needed nbits/mask for no-bucket srl_tpl + + ver.srl_tpl.assign(tok); + ver.mask = (1 << nbits) - 1; + } while(false); + } // if(tok != NULL) + if(ver.mask != VERMASK_NOSRL) + break; // Mask found + } // while + if + + } while(false); + if(ver.mask < 0) { + ver.mask = VERMASK_BLOCKED; // Unable to read - block next read + return false; + } // if(ver.mask < 0) - after try-fill verifiyer + + } // if(ver.mask < 0) - main + + while(*signature <= 040 && *signature) + signature++; + + bool fInvalid = false; + vector vchSig(DecodeBase64(signature, &fInvalid)); + + if(fInvalid) + return false; + + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << string(q_str); + + CPubKey pubkey; + if(!pubkey.RecoverCompact(ss.GetHash(), vchSig)) + return false; + + if(pubkey.GetID() != ver.keyID) + return false; // Signature check did not passed + + if(ver.mask == VERMASK_NOSRL) + return true; // This verifiyer does not have active SRL + + // TODO - check SRL here + + char valbuf[VAL_SIZE]; + // Compute a simple hash from q_str like enum:17771234567:0 + // This hasu must be used by verifiyers for build buckets + unsigned h = 0x5555; + for(const char *p = q_str; *p; p++) + h += (h << 5) + *p; + sprintf(valbuf, ver.srl_tpl.c_str(), h & ver.mask); + + string value; + if(!hooks->getNameValue(string(valbuf), value)) + return true; // Unable fetch SRL - as same as SRL does not exist + + return !value.find(q_str); +#if 0 + char *valstr = strcpy(valbuf, value.c_str()); + while(char *tok = strsep(&valstr, "|, \r\n\t")) + if(strcmp(tok, q_str) == 0) + reurn false; + + return true; +#endif +} // SlkDns::CheckEnumSig diff --git a/src/dns/slkdns.h b/src/dns/slkdns.h index 58751856..3d258826 100644 --- a/src/dns/slkdns.h +++ b/src/dns/slkdns.h @@ -8,11 +8,21 @@ #ifndef SLKDNS_H #define SLKDNS_H +#include +#include +using namespace std; + #include +#include "pubkey.h" + #define SLKDNS_DAPSIZE (8 * 1024) #define SLKDNS_DAPTRESHOLD 300 // 20K/min limit answer +#define VERMASK_NEW -1 +#define VERMASK_BLOCKED -2 +#define VERMASK_NOSRL (1 << 24) + struct DNSHeader { static const uint32_t QR_MASK = 0x8000; static const uint32_t OPCODE_MASK = 0x7800; // shr 11 @@ -41,10 +51,17 @@ struct DNSAP { // DNS Amplifier Protector ExpDecay structure uint16_t ed_size; // ExpDecay output size in 64-byte units } __attribute__((packed)); +struct Verifier { + Verifier() : mask(VERMASK_NEW) {} // -1 == uninited, neg != -1 == cant fetch + int32_t mask; // Signature Revocation List mask + string srl_tpl; // Signature Revocation List template + CKeyID keyID; // Key for verify message +}; // 72 bytes = 18 words + class SlkDns { public: SlkDns(const char *bind_ip, uint16_t port_no, - const char *gw_suffix, const char *allowed_suff, const char *local_fname, uint8_t verbose); + const char *gw_suffix, const char *allowed_suff, const char *local_fname, const char *enums, uint8_t verbose); ~SlkDns(); void Run(); @@ -61,13 +78,22 @@ class SlkDns { void Fill_RD_DName(char *txt, uint8_t mxsz, int8_t txtcor); int TryMakeref(uint16_t label_ref); + // Handle Special function - phone number in the E.164 format + // to support ENUM service + int SpfunENUM(uint8_t len, uint8_t **domain_start, uint8_t **domain_end); + // Generate answewr for found EMUM NVS record + void Answer_ENUM(const char *q_str); + void HandleE2U(char *e2u); + bool CheckEnumSig(const char *q_str, char *sig_str); + // Returns x = hash index to update size; x==NULL = disable; DNSAP *CheckDAP(uint32_t ip_addr); inline void Out2(uint16_t x) { x = htons(x); memcpy(m_snd, &x, 2); m_snd += 2; } inline void Out4(uint32_t x) { x = htonl(x); memcpy(m_snd, &x, 4); m_snd += 4; } + void OutS(const char *p); - DNSHeader *m_hdr; + DNSHeader *m_hdr; // 1st bzero element DNSAP *m_dap_ht; // Hashtable for DAP; index is hash(IP) char *m_value; const char *m_gw_suffix; @@ -78,18 +104,19 @@ class SlkDns { uint32_t m_ttl; uint16_t m_label_ref; uint16_t m_gw_suf_len; - uint8_t m_gw_suf_dots; - uint8_t m_verbose; - uint8_t m_allowed_qty; - uint8_t m_status; char *m_allowed_base; char *m_local_base; int16_t m_ht_offset[0x100]; // Hashtable for allowed TLD-suffixes(>0) and local names(<0) struct sockaddr_in m_clientAddress; struct sockaddr_in m_address; socklen_t m_addrLen; - + uint8_t m_gw_suf_dots; + uint8_t m_allowed_qty; + uint8_t m_verbose; // LAST bzero element + + int8_t m_status; boost::thread m_thread; + map m_verifiers; }; // class SlkDns #endif // SLKDNS_H diff --git a/src/init.cpp b/src/init.cpp index 86187965..0277f068 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -279,6 +279,7 @@ std::string HelpMessage(HelpMessageMode mode) string strUsage = _("Options:") + "\n"; strUsage += " -? " + _("This help message") + "\n"; strUsage += " -alertnotify= " + _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)") + "\n"; + strUsage += " -alerts " + strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS); strUsage += " -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n"; strUsage += " -checkblocks= " + strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288) + "\n"; strUsage += " -checklevel= " + strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3) + "\n"; @@ -640,7 +641,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (SoftSetBoolArg("-listen", true)) - LogPrintf("AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1\n"); + LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); + // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1 + // to listen locally, so don't rely on this happening through -listen below. + if (SoftSetBoolArg("-upnp", false)) + LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); } if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { @@ -745,12 +750,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (nConnectTimeout <= 0) nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; - // Continue to put "/P2SH/" in the coinbase to monitor - // BIP16 support. - // This can be removed eventually... - const char* pszP2SH = "/P2SH/"; - COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); - // Fee-per-kilobyte amount considered the same as "free" // If you are mining, be careful setting this: // if you set it to zero then @@ -825,6 +824,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0; nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); + fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Sanity check @@ -1423,8 +1424,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) string bind_ip = GetArg("-slkdnsbindip", ""); string allowed = GetArg("-slkdnsallowed", ""); string localcf = GetArg("-slkdnslocalcf", ""); + string enums = GetArg("-enumtrust", ""); slkdns = new SlkDns(bind_ip.c_str(), port, - suffix.c_str(), allowed.c_str(), localcf.c_str(), verbose); + suffix.c_str(), allowed.c_str(), localcf.c_str(), enums.c_str(), verbose); LogPrintf("DNS server started\n"); } diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index 37da1f1b..e75050c7 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -61,7 +61,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa } else { if (fWipe) { LogPrintf("Wiping LevelDB in %s\n", path.string()); - leveldb::DestroyDB(path.string(), options); + leveldb::Status result = leveldb::DestroyDB(path.string(), options); } TryCreateDirectory(path); LogPrintf("Opening LevelDB in %s\n", path.string()); diff --git a/src/main.cpp b/src/main.cpp index 64675cde..87b5660a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,6 +63,7 @@ bool fTxIndex = true; bool fIsBareMultisigStd = true; bool fCheckBlockIndex = false; size_t nCoinCacheUsage = 5000 * 300; +bool fAlerts = DEFAULT_ALERTS; // ppcoin values string strMintWarning; @@ -1288,6 +1289,31 @@ CAmount GetProofOfStakeReward() bool IsInitialBlockDownload() { + static bool rc = true; // Default - we're in the Initial Download + do { + if(rc == false) + break; // ret false + + const CChainParams& chainParams = Params(); + LOCK(cs_main); + + if (fImporting || fReindex) + break; // ret true + + unsigned int cah = chainActive.Height(); + + if(cah < Checkpoints::GetTotalBlocksEstimate() || cah < pindexBestHeader->nHeight - 24 * 6) + break; // ret true + + rc = pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge(); + + } while(false); + + return rc; +} + +#if 0 +const CChainParams& chainParams = Params(); LOCK(cs_main); if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) return true; @@ -1295,11 +1321,11 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - 24 * 60 * 60); + pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); if (!state) lockIBDState = true; return state; -} +#endif bool fLargeWorkForkFound = false; bool fLargeWorkInvalidChainFound = false; @@ -1838,6 +1864,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; flags |= SCRIPT_VERIFY_DERSIG; + // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 + // blocks, when 75% of the network has upgraded: + if (block.nVersion >= 2 && CBlockIndex::IsSuperMajority(2, pindex->pprev, Params().EnforceBlockUpgradeMajority())) { + flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + } + CBlockUndo blockundo; CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); @@ -2868,7 +2900,15 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, bool fProofOfStake, C CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); if (pcheckpoint && nHeight < pcheckpoint->nHeight) return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); - + + // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: + if (block.nVersion < 2 && + CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) + { + return state.Invalid(error("%s : rejected nVersion=1 block", __func__), + REJECT_OBSOLETE, "bad-version"); + } + return true; } @@ -3168,7 +3208,7 @@ bool AbortNode(const std::string &strMessage, const std::string &userMessage) { strMiscWarning = strMessage; LogPrintf("*** %s\n", strMessage); uiInterface.ThreadSafeMessageBox( - userMessage.empty() ? _("Error: A fatal internal error occured, see debug.log for details") : userMessage, + userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; @@ -3509,9 +3549,8 @@ bool InitBlockIndex() { // write checkpoint master key to db if (!pblocktree->WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey)) return error("LoadBlockIndex() : failed to write new checkpoint master key to db"); - if (!pblocktree->Sync()) - return error("LoadBlockIndex() : failed to commit new checkpoint master key to db"); - if ((Params().NetworkIDString() == "main") && !CheckpointsSync::ResetSyncCheckpoint()) + FlushStateToDisk(); + if (!CheckpointsSync::ResetSyncCheckpoint()) return error("LoadBlockIndex() : failed to reset sync-checkpoint"); } }*/ @@ -4717,7 +4756,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "alert") + else if (fAlerts && strCommand == "alert") { CAlert alert; vRecv >> alert; diff --git a/src/main.h b/src/main.h index a68fd854..48f61199 100644 --- a/src/main.h +++ b/src/main.h @@ -57,6 +57,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 3145728; //3MB (75% of MAX_BL static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 200000; +/** Default for accepting alerts from the P2P network. */ +static const bool DEFAULT_ALERTS = true; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 400000; /** The maximum allowed number of signature check operations in a block (network rule) */ @@ -81,8 +83,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB -/** 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 number of script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 16; /** -par default (number of script-checking threads, 0 = auto) */ @@ -141,6 +141,7 @@ extern bool fIsBareMultisigStd; extern bool fCheckBlockIndex; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; +extern bool fAlerts; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index d5eced1a..8b467694 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -140,7 +140,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch) { // traverse the partial tree unsigned int nBitsUsed = 0, nHashUsed = 0; uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch); - // verify that no problems occured during the tree traversal + // verify that no problems occurred during the tree traversal if (fBad) return 0; // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence) diff --git a/src/net.cpp b/src/net.cpp index f7051460..6e053040 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -415,24 +415,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed)) { - if (pszDest && addrConnect.IsValid()) { - // It is possible that we already have a connection to the IP/port pszDest resolved to. - // In that case, drop the connection that was just created, and return the existing CNode instead. - // Also store the name we used to connect in that CNode, so that future FindNode() calls to that - // name catch this early. - CNode* pnode = FindNode((CService)addrConnect); - if (pnode) - { - pnode->AddRef(); - { - LOCK(cs_vNodes); - if (pnode->addrName.empty()) { - pnode->addrName = std::string(pszDest); - } - } - CloseSocket(hSocket); - return pnode; - } + if (!IsSelectableSocket(hSocket)) { + LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); + CloseSocket(hSocket); + return NULL; } addrman.Attempt(addrConnect); @@ -607,7 +593,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) return false; if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) { - LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId()); + LogPrint("net", "Oversized message from peer=%i, disconnecting\n", GetId()); return false; } @@ -903,8 +889,14 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK) LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); } + else if (!IsSelectableSocket(hSocket)) + { + LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); + CloseSocket(hSocket); + } else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) { + LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); CloseSocket(hSocket); } else if (CNode::IsBanned(addr) && !whitelisted) @@ -914,6 +906,14 @@ void ThreadSocketHandler() } else { + // According to the internet TCP_NODELAY is not carried into accepted sockets + // on all platforms. Set it again here just to be sure. + int set = 1; +#ifdef WIN32 + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); +#else + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); +#endif CNode* pnode = new CNode(hSocket, addr, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -1499,11 +1499,6 @@ void ThreadMessageHandler() } } - - - - - bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted) { strError = ""; @@ -1527,14 +1522,26 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste return false; } + if (!IsSelectableSocket(hListenSocket)) + { + strError = "Error: Couldn't create a listenable socket for incoming connections"; + LogPrintf("%s\n", strError); + return false; + } + #ifndef WIN32 #ifdef SO_NOSIGPIPE // Different way of disabling SIGPIPE on BSD setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); #endif // Allow binding if the port is still in TIME_WAIT state after - // the program was closed and restarted. Not an issue on windows! + // the program was closed and restarted. setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); + // Disable Nagle's algorithm + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int)); +#else + setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int)); + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int)); #endif // Set to non-blocking, incoming connections will also inherit this diff --git a/src/netbase.cpp b/src/netbase.cpp index 4194ce85..f3656661 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -273,6 +273,9 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock } else { // Other error or blocking int nErr = WSAGetLastError(); if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { + if (!IsSelectableSocket(hSocket)) { + return false; + } struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); fd_set fdset; FD_ZERO(&fdset); @@ -410,12 +413,19 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe if (hSocket == INVALID_SOCKET) return false; -#ifdef SO_NOSIGPIPE int set = 1; +#ifdef SO_NOSIGPIPE // Different way of disabling SIGPIPE on BSD setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); #endif + //Disable Nagle's algorithm +#ifdef WIN32 + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); +#else + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); +#endif + // Set to non-blocking if (!SetSocketNonBlocking(hSocket, true)) return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError())); diff --git a/src/primitives/block.h b/src/primitives/block.h index 80d9cd8c..0d8fafeb 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -39,7 +39,7 @@ class CBlockHeader public: // header static const int32_t NORMAL_SERIALIZE_SIZE=80; - static const int32_t CURRENT_VERSION=1; + static const int32_t CURRENT_VERSION=2; int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; diff --git a/src/qt/silk.cpp b/src/qt/silk.cpp index 8dc35544..ef17f938 100644 --- a/src/qt/silk.cpp +++ b/src/qt/silk.cpp @@ -566,7 +566,7 @@ int main(int argc, char *argv[]) // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. - if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) + if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { HelpMessageDialog help(NULL, mapArgs.count("-version")); help.showOrPrint(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 475df96d..9d0b5993 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -263,7 +263,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact { return InvalidAddress; } - if(rcp.amount <= MIN_TXOUT_AMOUNT) + if(rcp.amount < MIN_TXOUT_AMOUNT) { return InvalidAmount; } diff --git a/src/rpc/rpcregister.h b/src/rpc/rpcregister.h index f715dcbd..b80e4bc2 100644 --- a/src/rpc/rpcregister.h +++ b/src/rpc/rpcregister.h @@ -6,8 +6,9 @@ #ifndef SILK_RPCREGISTER_H #define SILK_RPCREGISTER_H -/** These are in one header file to avoid creating tons of single-function - * headers for everything under src/rpc/* */ +// These are in one header file to avoid creating tons of single-function +// headers for everything under src/rpc/* + class CRPCTable; /** Register block chain RPC commands */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index aba1d68a..516f07c2 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -341,7 +341,49 @@ bool EvalScript(vector >& stack, const CScript& script, un case OP_NOP: break; - case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: + case OP_CHECKLOCKTIMEVERIFY: + { + if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { + // not enabled; treat as a NOP2 + if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); + } + break; + } + + if (stack.size() < 1) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // Note that elsewhere numeric opcodes are limited to + // operands in the range -2**31+1 to 2**31-1, however it is + // legal for opcodes to produce results exceeding that + // range. This limitation is implemented by CScriptNum's + // default 4-byte limit. + // + // If we kept to that limit we'd have a year 2038 problem, + // even though the nLockTime field in transactions + // themselves is uint32 which only becomes meaningless + // after the year 2106. + // + // Thus as a special case we tell CScriptNum to accept up + // to 5-byte bignums, which are good until 2**39-1, well + // beyond the 2**32-1 limit of the nLockTime field itself. + const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5); + + // In the rare event that the argument may be < 0 due to + // some arithmetic being done first, you can always use + // 0 MAX CHECKLOCKTIMEVERIFY. + if (nLockTime < 0) + return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); + + // Actually compare the specified lock time with the transaction. + if (!checker.CheckLockTime(nLockTime)) + return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); + + break; + } + + case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -1089,6 +1131,42 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn return true; } +bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const +{ + // There are two times of nLockTime: lock-by-blockheight + // and lock-by-blocktime, distinguished by whether + // nLockTime < LOCKTIME_THRESHOLD. + // + // We want to compare apples to apples, so fail the script + // unless the type of nLockTime being tested is the same as + // the nLockTime in the transaction. + if (!( + (txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || + (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD) + )) + return false; + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nLockTime > (int64_t)txTo->nLockTime) + return false; + + // Finally the nLockTime feature can be disabled and thus + // CHECKLOCKTIMEVERIFY bypassed if every txin has been + // finalized by setting nSequence to maxint. The + // transaction would be allowed into the blockchain, making + // the opcode ineffective. + // + // Testing if this vin is not final is sufficient to + // prevent this condition. Alternatively we could test all + // inputs, but testing just this input minimizes the data + // required to prove correct CHECKLOCKTIMEVERIFY execution. + if (txTo->vin[nIn].IsFinal()) + return false; + + return true; +} + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool fNamecoin) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 5ae604d5..a2c8921f 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -70,8 +70,12 @@ enum // discouraged NOPs fails the script. This verification flag will never be // a mandatory flag applied to scripts in a block. NOPs that are not // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7) + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7), + // Verify CHECKLOCKTIMEVERIFY + // + // See BIP65 for details. + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -84,6 +88,11 @@ class BaseSignatureChecker return false; } + virtual bool CheckLockTime(const CScriptNum& nLockTime) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -99,6 +108,7 @@ class TransactionSignatureChecker : public BaseSignatureChecker public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; + bool CheckLockTime(const CScriptNum& nLockTime) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.h b/src/script/script.h index 042f6ede..4702d28b 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -21,6 +21,10 @@ typedef std::vector valtype; static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes +// 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 + template std::vector ToByteVector(const T& in) { @@ -153,6 +157,7 @@ enum opcodetype // expansion OP_NOP1 = 0xb0, OP_NOP2 = 0xb1, + OP_CHECKLOCKTIMEVERIFY = OP_NOP2, OP_NOP3 = 0xb2, OP_NOP4 = 0xb3, OP_NOP5 = 0xb4, @@ -203,7 +208,10 @@ class CScriptNum m_value = n; } - explicit CScriptNum(const std::vector& vch, bool fRequireMinimal) + static const size_t nDefaultMaxNumSize = 4; + + explicit CScriptNum(const std::vector& vch, bool fRequireMinimal, + const size_t nMaxNumSize = nDefaultMaxNumSize) { if (vch.size() > nMaxNumSize) { throw scriptnum_error("script number overflow"); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index f6652807..40379052 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -48,6 +48,10 @@ const char* ScriptErrorString(const ScriptError serror) return "OP_RETURN was encountered"; case SCRIPT_ERR_UNBALANCED_CONDITIONAL: return "Invalid OP_IF construction"; + case SCRIPT_ERR_NEGATIVE_LOCKTIME: + return "Negative locktime"; + case SCRIPT_ERR_UNSATISFIED_LOCKTIME: + return "Locktime requirement not satisfied"; case SCRIPT_ERR_SIG_HASHTYPE: return "Signature hash type missing or not understood"; case SCRIPT_ERR_SIG_DER: diff --git a/src/script/script_error.h b/src/script/script_error.h index 7121575b..2ffd70fe 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -36,6 +36,10 @@ typedef enum ScriptError_t SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, + /* OP_CHECKLOCKTIMEVERIFY */ + SCRIPT_ERR_NEGATIVE_LOCKTIME, + SCRIPT_ERR_UNSATISFIED_LOCKTIME, + /* BIP62 */ SCRIPT_ERR_SIG_HASHTYPE, SCRIPT_ERR_SIG_DER, diff --git a/src/script/silkconsensus.h b/src/script/silkconsensus.h index c7f3f585..1620d407 100644 --- a/src/script/silkconsensus.h +++ b/src/script/silkconsensus.h @@ -48,6 +48,7 @@ enum silkconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, silkconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts silkconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance + silkconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65) }; /// Returns 1 if the input nIn of the serialized transaction pointed to by diff --git a/src/script/standard.h b/src/script/standard.h index 1e741bda..0228f69d 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -50,7 +50,9 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_NULLDUMMY | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS; + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | + SCRIPT_VERIFY_LOW_S; /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; diff --git a/src/silk-cli.cpp b/src/silk-cli.cpp index af5d3923..63e0a8f4 100644 --- a/src/silk-cli.cpp +++ b/src/silk-cli.cpp @@ -68,7 +68,7 @@ static bool AppInitRPC(int argc, char* argv[]) // Parameters // ParseParameters(argc, argv); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) { + if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { std::string strUsage = _("Silk Core RPC client version") + " " + FormatFullVersion() + "\n"; if (!mapArgs.count("-version")) { strUsage += "\n" + _("Usage:") + "\n" + diff --git a/src/silk-tx.cpp b/src/silk-tx.cpp index 9b802e4f..220fdbe0 100644 --- a/src/silk-tx.cpp +++ b/src/silk-tx.cpp @@ -47,7 +47,7 @@ static bool AppInitRawTx(int argc, char* argv[]) fCreateBlank = GetBoolArg("-create", false); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help")) + if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help")) { // First part of help message is specific to this utility std::string strUsage = _("Silk Core silk-tx utility version") + " " + FormatFullVersion() + "\n\n" + diff --git a/src/silkd.cpp b/src/silkd.cpp index 1fd985e9..d127b1ca 100644 --- a/src/silkd.cpp +++ b/src/silkd.cpp @@ -70,7 +70,7 @@ bool AppInit(int argc, char* argv[]) ParseParameters(argc, argv); // Process help and version before taking care about datadir - if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) + if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { std::string strUsage = _("Silk Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 638a705f..7df2eaf3 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -103,5 +103,78 @@ [[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]], "01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"], +["CHECKLOCKTIMEVERIFY tests"], + +["By-height locks, with argument just beyond tx nLockTime"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument missing"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument negative with by-blockheight nLockTime=0"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument negative with by-blocktime nLockTime=500,000,000"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Input locked"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] , + ["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]], +"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument/tx height/time mismatch, both versions"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Argument 2^32 with nLockTime=2^32-1"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Same, but with nLockTime=2^31-1"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"], + +["6 byte non-minimally-encoded arguments are invalid even in their contents are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index aa8e5ca6..0fb4542e 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -177,6 +177,47 @@ ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]], "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"], +["CHECKLOCKTIMEVERIFY tests"], + +["By-height locks, with argument == 0 and == tx nLockTime"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["By-time locks, with argument just beyond tx nLockTime (but within numerical boundries)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Any non-maxint nSequence is fine"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["The argument can be calculated rather than created directly by a PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"], + +["5 byte non-minimally-encoded arguments are valid"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Valid CHECKLOCKTIMEVERIFY in scriptSig"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], + +["Valid CHECKLOCKTIMEVERIFY in redeemScript"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]], +"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 7eb30840..f4ab3645 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -40,6 +40,7 @@ static std::map mapFlagNames = boost::assign::map_list_of (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS); + (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY); unsigned int ParseScriptFlags(string strFlags) { diff --git a/src/uint256hm.h b/src/uint256hm.h index 168b385b..99293ecc 100644 --- a/src/uint256hm.h +++ b/src/uint256hm.h @@ -47,7 +47,7 @@ template if((int32_t)size < 0) m_mask = 0x80000000; else - for(m_mask = 64; m_mask < size; m_mask <<= 1); + for(m_mask = 8; m_mask < size; m_mask <<= 1); LogPrintf("uint256HashMap:Set(%u/%u) data=%u sz=%u\n", size, m_mask, (unsigned)sizeof(struct Data), (unsigned)(m_mask * sizeof(struct Data))); // allocate memory diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index ea421a9e..f39c8f4f 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -200,7 +200,7 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector Date: Fri, 27 Jan 2017 07:49:36 +0100 Subject: [PATCH 02/27] working E164 version --- src/dns/slkdns.cpp | 124 ++++++++++++++++++++++++++++++++++++--------- src/dns/slkdns.h | 19 ++++++- src/init.cpp | 3 +- 3 files changed, 120 insertions(+), 26 deletions(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index 8aa956b5..ea832c02 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -92,7 +92,7 @@ int inet_pton(int af, const char *src, void *dst) /*---------------------------------------------------*/ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, - const char *gw_suffix, const char *allowed_suff, const char *local_fname, const char *enums, uint8_t verbose) + const char *gw_suffix, const char *allowed_suff, const char *local_fname, const char *enums, const char *tollfree, uint8_t verbose) : m_status(-1), m_thread(StatRun, this) { // Clear vars [m_hdr..m_verbose) @@ -163,7 +163,7 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, if(m_value == NULL) throw runtime_error("SlkDns::SlkDns: Cannot allocate buffer"); - // Temporary use m_value for parse enum-verifiers, if exists + // Temporary use m_value for parse enum-verifiers and toll-free lists, if exist if(enums && *enums) { char *str = strcpy(m_value, enums); Verifier empty_ver; @@ -252,9 +252,43 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, m_address.sin_addr.s_addr == INADDR_ANY? "INADDR_ANY" : bind_ip, port_no, m_allowed_qty, local_qty); + // Hack - pass TF file list through m_value to HandlePacket() + + if(tollfree && *tollfree) + if(m_verbose > 3) + LogPrintf("\tSlkDns::EmcDns: Setup deferred toll-free=%s\n", tollfree); + strcpy(m_value, tollfree); + else + m_value[0] = 0; + m_status = 1; // Active, and maybe download } // SlkDns::SlkDns +/*---------------------------------------------------*/ +void SlkDns::AddTF(const char *tf_tok) { + // Skip comments and empty lines + if(tf_tok[0] < '0') + return; + + // Clear TABs and SPs at the end of the line + char *end = strchr(tf_tok, 0); + while(*--end <= 040) { + *end = 0; + if(end <= tf_tok) + return; + } + + if(tf_tok[0] == '=') { + if(tf_tok[1]) + m_tollfree.push_back(TollFree(tf_tok + 1)); + } else + if(!m_tollfree.empty()) + m_tollfree.back().e2u.push_back(string(tf_tok)); + + if(m_verbose > 3) + LogPrintf("\tSlkDns::AddTF: Added token [%s] %u:%u\n", tf_tok, m_tollfree.size(), m_tollfree.back().e2u.size()); +} // EmcDns::AddTF + /*---------------------------------------------------*/ SlkDns::~SlkDns() { @@ -355,11 +389,35 @@ void SlkDns::HandlePacket() { break; } -// if(IsInitialBlockDownload()) { - if(m_status && (m_status = IsInitialBlockDownload())) { - m_hdr->Bits |= 2; // Server failure - not available valid nameindex DB yet - break; - } + if(m_status) { + if(m_status = IsInitialBlockDownload()) { + m_hdr->Bits |= 2; // Server failure - not available valid nameindex DB yet + break; + } else { + // Fill deferred toll-free default entries + char *tf_str = m_value; + // Iterate the list of Toll-Free fnames; can be fnames and NVS records + while(char *tf_fname = strsep(&tf_str, "|")) { + if(m_verbose > 3) + LogPrintf("\tSlkDns::HandlePacket: handle deferred toll-free=%s\n", tf_fname); + if(tf_fname[0] == '@') { // this is NVS record + string value; + if(hooks->getNameValue(string(tf_fname + 1), value)) { + char *tf_val = strcpy(m_value, value.c_str()); + while(char *tf_tok = strsep(&tf_val, "\r\n")) + AddTF(tf_tok); + } + } else { // This is file + FILE *tf = fopen(tf_fname, "r"); + if(tf != NULL) { + while(fgets(m_value, VAL_SIZE, tf)) + AddTF(m_value); + fclose(tf); + } + } // if @ + } // while tf_name + } // m_status #2 + } // m_status #1 // Handle questions here for(uint16_t qno = 0; qno < m_hdr->QDCount && m_snd < m_bufend; qno++) { @@ -810,9 +868,10 @@ int SlkDns::SpfunENUM(uint8_t len, uint8_t **domain_start, uint8_t **domain_end) if(dom_length < 2) break; // no domains for phone number - NXDOMAIN - if(m_verifiers.empty()) + if(m_verifiers.empty() && m_tollfree.empty()) break; // no verifier - all ENUMs untrusted + // convert reversed domain record to ITU-T number char itut_num[68], *pitut = itut_num, *pitutend = itut_num + len; for(const uint8_t *p = domain_end[-1]; --p >= *domain_start; ) if(*p >= '0' && *p <= '9') { @@ -829,19 +888,38 @@ int SlkDns::SpfunENUM(uint8_t len, uint8_t **domain_start, uint8_t **domain_end) LogPrintf("\tSlkDns::SpfunENUM: ITU-T num=[%s]\n", itut_num); // Itrrate all available ENUM-records, and build joined answer from them - for(int16_t qno = 0; qno >= 0; qno++) { - char q_str[100]; - sprintf(q_str, "%s:%s:%u", tld, itut_num, qno); - if(m_verbose > 1) - LogPrintf("\tSlkDns::SpfunENUM Search(%s)\n", q_str); - - string value; - if(!hooks->getNameValue(string(q_str), value)) - return m_hdr->ANCount? 0 : 3; + if(!m_verifiers.empty()) + for(int16_t qno = 0; qno >= 0; qno++) { + char q_str[100]; + sprintf(q_str, "%s:%s:%u", tld, itut_num, qno); + if(m_verbose > 1) + LogPrintf("\tSlkDns::SpfunENUM Search(%s)\n", q_str); + + string value; + if(!hooks->getNameValue(string(q_str), value)) + break; + + strcpy(m_value, value.c_str()); + Answer_ENUM(q_str); + } // for + + // If notheing found in the ENUM - try to search in the Toll-Free + m_ttl = 24 * 3600; // 24h by default + boost::xpressive::smatch nameparts; + for(vector::const_iterator tf = m_tollfree.begin(); + m_hdr->ANCount == 0 && tf != m_tollfree.end(); + tf++) { + bool matched = regex_match(string(itut_num), nameparts, tf->regex); + // bool matched = regex_search(string(itut_num), nameparts, tf->regex); + if(m_verbose > 3) + LogPrintf("\tEmcDns::SpfunENUM TF-match N=[%s] RE=[%s] -> %u\n", itut_num, tf->regex_str.c_str(), matched); + if(matched) + for(vector::const_iterator e2u = tf->e2u.begin(); e2u != tf->e2u.end(); e2u++) + HandleE2U(strcpy(m_value, e2u->c_str())); + } // tf processing - strcpy(m_value, value.c_str()); - Answer_ENUM(q_str); - } // for + if(m_hdr->ANCount) + return 0; // if collected some answers - OK } while(false); @@ -1060,8 +1138,6 @@ bool SlkDns::CheckEnumSig(const char *q_str, char *sig_str) { if(ver.mask == VERMASK_NOSRL) return true; // This verifiyer does not have active SRL - // TODO - check SRL here - char valbuf[VAL_SIZE]; // Compute a simple hash from q_str like enum:17771234567:0 // This hasu must be used by verifiyers for build buckets @@ -1074,7 +1150,9 @@ bool SlkDns::CheckEnumSig(const char *q_str, char *sig_str) { if(!hooks->getNameValue(string(valbuf), value)) return true; // Unable fetch SRL - as same as SRL does not exist - return !value.find(q_str); + // Is q_str missing in the SRL + return value.find(q_str) == string::npos; + #if 0 char *valstr = strcpy(valbuf, value.c_str()); while(char *tok = strsep(&valstr, "|, \r\n\t")) diff --git a/src/dns/slkdns.h b/src/dns/slkdns.h index 3d258826..dd3cc65c 100644 --- a/src/dns/slkdns.h +++ b/src/dns/slkdns.h @@ -10,9 +10,11 @@ #include #include -using namespace std; #include +#include + +using namespace std; #include "pubkey.h" @@ -58,10 +60,21 @@ struct Verifier { CKeyID keyID; // Key for verify message }; // 72 bytes = 18 words +struct TollFree { + TollFree(const char *re) : + regex(boost::xpressive::sregex::compile(string(re))), regex_str(re) + {} + boost::xpressive::sregex regex; + string regex_str; + vector e2u; +}; + class SlkDns { public: SlkDns(const char *bind_ip, uint16_t port_no, - const char *gw_suffix, const char *allowed_suff, const char *local_fname, const char *enums, uint8_t verbose); + const char *gw_suffix, const char *allowed_suff, + const char *local_fname, const char *enums, const char *tollfree, + uint8_t verbose); ~SlkDns(); void Run(); @@ -85,6 +98,7 @@ class SlkDns { void Answer_ENUM(const char *q_str); void HandleE2U(char *e2u); bool CheckEnumSig(const char *q_str, char *sig_str); + void AddTF(const char *tf_tok); // Returns x = hash index to update size; x==NULL = disable; DNSAP *CheckDAP(uint32_t ip_addr); @@ -117,6 +131,7 @@ class SlkDns { int8_t m_status; boost::thread m_thread; map m_verifiers; + vector m_tollfree; }; // class SlkDns #endif // SLKDNS_H diff --git a/src/init.cpp b/src/init.cpp index 0277f068..06fefdb0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1425,8 +1425,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) string allowed = GetArg("-slkdnsallowed", ""); string localcf = GetArg("-slkdnslocalcf", ""); string enums = GetArg("-enumtrust", ""); + string tf = GetArg("-enumtollfree", ""); slkdns = new SlkDns(bind_ip.c_str(), port, - suffix.c_str(), allowed.c_str(), localcf.c_str(), enums.c_str(), verbose); + suffix.c_str(), allowed.c_str(), localcf.c_str(), enums.c_str(), tf.c_str(), verbose); LogPrintf("DNS server started\n"); } From d2a4406e4a6427101da3e7f97a801e2c67272b89 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 07:52:30 +0100 Subject: [PATCH 03/27] Increased DAP limit 10x, and activate DAP only when public GW --- src/dns/slkdns.cpp | 3 ++- src/dns/slkdns.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index ea832c02..b52b1eb4 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -153,8 +153,9 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, if(*p == '.') m_gw_suf_dots++; + // Activate DAP only on the public gateways, with some suffixes, like .emergate.net // If no memory, DAP inactive - this is not critical problem - m_dap_ht = (allowed_len | m_gw_suf_len)? (DNSAP*)calloc(SLKDNS_DAPSIZE, sizeof(DNSAP)) : NULL; + m_dap_ht = (allowed_len && m_gw_suf_len)? (DNSAP*)calloc(SLKDNS_DAPSIZE, sizeof(DNSAP)) : NULL; m_daprand = GetRand(0xffffffff) | 1; m_value = (char *)malloc(VAL_SIZE + BUF_SIZE + 2 + diff --git a/src/dns/slkdns.h b/src/dns/slkdns.h index dd3cc65c..de993a3a 100644 --- a/src/dns/slkdns.h +++ b/src/dns/slkdns.h @@ -19,7 +19,7 @@ using namespace std; #include "pubkey.h" #define SLKDNS_DAPSIZE (8 * 1024) -#define SLKDNS_DAPTRESHOLD 300 // 20K/min limit answer +#define SLKDNS_DAPTRESHOLD 3000 // 200K/min limit answer #define VERMASK_NEW -1 #define VERMASK_BLOCKED -2 From f958da33506d456014a423c3e8a47a543a06c8d2 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 07:54:13 +0100 Subject: [PATCH 04/27] Fix typos/format --- src/dns/slkdns.cpp | 6 +++--- src/dns/slkdns.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index b52b1eb4..43310a78 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -255,18 +255,18 @@ SlkDns::SlkDns(const char *bind_ip, uint16_t port_no, // Hack - pass TF file list through m_value to HandlePacket() - if(tollfree && *tollfree) + if(tollfree && *tollfree) { if(m_verbose > 3) LogPrintf("\tSlkDns::EmcDns: Setup deferred toll-free=%s\n", tollfree); strcpy(m_value, tollfree); - else + } else m_value[0] = 0; m_status = 1; // Active, and maybe download } // SlkDns::SlkDns /*---------------------------------------------------*/ -void SlkDns::AddTF(const char *tf_tok) { +void SlkDns::AddTF(char *tf_tok) { // Skip comments and empty lines if(tf_tok[0] < '0') return; diff --git a/src/dns/slkdns.h b/src/dns/slkdns.h index de993a3a..bf433c58 100644 --- a/src/dns/slkdns.h +++ b/src/dns/slkdns.h @@ -98,7 +98,7 @@ class SlkDns { void Answer_ENUM(const char *q_str); void HandleE2U(char *e2u); bool CheckEnumSig(const char *q_str, char *sig_str); - void AddTF(const char *tf_tok); + void AddTF(char *tf_tok); // Returns x = hash index to update size; x==NULL = disable; DNSAP *CheckDAP(uint32_t ip_addr); From d5ca882e8b86ae3fc80628f7039366d941655782 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 07:55:32 +0100 Subject: [PATCH 05/27] Bump Version --- README.md | 2 +- configure.ac | 6 +++--- silk-qt.pro | 2 +- src/clientversion.h | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 72d301f0..bc8e3328 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# **Silk-Core (SLK) v1.0.1.2** +# **Silk-Core (SLK) v1.1.0.0** [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) diff --git a/configure.ac b/configure.ac index 2d749d76..b4bbe0c0 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) -define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 1) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_MINOR, 1) +define(_CLIENT_VERSION_REVISION, 0) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2017) AC_INIT([Silk Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[silk]) diff --git a/silk-qt.pro b/silk-qt.pro index 410cb8e0..f45b805b 100644 --- a/silk-qt.pro +++ b/silk-qt.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = Silk -VERSION = 1.0.1.2 +VERSION = 1.1.0.0 # for boost 1.37, add -mt to the boost libraries # use: qmake BOOST_LIB_SUFFIX=-mt diff --git a/src/clientversion.h b/src/clientversion.h index 7b77eac9..4e027b2d 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,9 +17,9 @@ //! These need to be macros, as clientversion.cpp's and silk*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 -#define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 1 -#define CLIENT_VERSION_BUILD 3 +#define CLIENT_VERSION_MINOR 1 +#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_BUILD 0 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true From 94bb9615d8f33eeadd9f458000dc6ac6aeec9631 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 07:59:41 +0100 Subject: [PATCH 06/27] Fix Crash in GetStake --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 536af5f3..aba94a2a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1481,7 +1481,7 @@ CAmount CWallet::GetTotal() const CAmount CWallet::GetStake() const { CAmount nTotal = 0; - LOCK(cs_wallet); + LOCK(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; From 200735620a1e49ea7e15f32c6edb9658111694c2 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 08:01:07 +0100 Subject: [PATCH 07/27] [RPC]Add wallet lock info to getinfo() --- src/rpc/rpcmisc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/rpcmisc.cpp b/src/rpc/rpcmisc.cpp index 567264e6..27d49f9b 100644 --- a/src/rpc/rpcmisc.cpp +++ b/src/rpc/rpcmisc.cpp @@ -98,6 +98,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); + obj.push_back(Pair("encrypted", pwalletMain->IsCrypted())); + obj.push_back(Pair("mintonly", fWalletUnlockMintOnly)); } if (pwalletMain && pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); From d864d50df54db3d83dff7b2bc499432154d96e06 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 08:04:53 +0100 Subject: [PATCH 08/27] qt: double click on name page table will do copy all values action --- src/qt/dnspage.cpp | 1 + src/qt/dnspage.h | 4 ++++ src/qt/forms/dnspage.ui | 2 +- src/qt/walletview.cpp | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qt/dnspage.cpp b/src/qt/dnspage.cpp index 3e6211a9..9753625e 100644 --- a/src/qt/dnspage.cpp +++ b/src/qt/dnspage.cpp @@ -126,6 +126,7 @@ DNSPage::DNSPage(QWidget *parent) : connect(copyAllAction, SIGNAL(triggered()), this, SLOT(onCopyAllAction())); connect(saveValueAsBinaryAction, SIGNAL(triggered()), this, SLOT(onSaveValueAsBinaryAction())); + connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex))); connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); diff --git a/src/qt/dnspage.h b/src/qt/dnspage.h index fa3f9c75..73f49bd9 100644 --- a/src/qt/dnspage.h +++ b/src/qt/dnspage.h @@ -92,6 +92,10 @@ private slots: void on_importValueButton_clicked(); void on_registerValue_textChanged(); void on_tableView_doubleClicked(const QModelIndex& index); + +signals: + void doubleClicked(const QModelIndex&); + }; #endif // DNSPAGE_H diff --git a/src/qt/forms/dnspage.ui b/src/qt/forms/dnspage.ui index 61e19989..e9a6079a 100644 --- a/src/qt/forms/dnspage.ui +++ b/src/qt/forms/dnspage.ui @@ -346,7 +346,7 @@ color: rgb(0, 0, 0); Qt::CustomContextMenu - Double-click name to configure + Double-click name to copy all values Qt::ScrollBarAlwaysOn diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index feb124e6..6704e9bd 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -73,6 +73,9 @@ WalletView::WalletView(QWidget *parent): // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + // Double-clicking on a name on the name page copies all values + connect(manageNamesPage, SIGNAL(doubleClicked(QModelIndex)), manageNamesPage, SLOT(onCopyAllAction())); + // Clicking on "Export" allows to export the transaction list connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); From ee08d73164edc43ccf07dfbf6b84b87f3039fa2d Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 08:07:54 +0100 Subject: [PATCH 09/27] empty value in name_update will keep previous value --- src/dns/dns.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/dns/dns.cpp b/src/dns/dns.cpp index 5ec24911..7b7afe31 100644 --- a/src/dns/dns.cpp +++ b/src/dns/dns.cpp @@ -1007,6 +1007,7 @@ UniValue name_update(const UniValue& params, bool fHelp) throw runtime_error( "name_update [toaddress] [valueAsFilepath]\n" "Update name value, add days to expiration time and possibly transfer a name to diffrent address.\n" + "If is empty then previous value is left intact.\n" "If [valueAsFilepath] is non-zero it will interpret as a filepath and try to write file contents in binary format.\n" + HelpRequiringPassphrase()); @@ -1052,7 +1053,7 @@ NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, ret.err_msg = "unkown error"; ret.ok = false; - if ((op == OP_NAME_NEW || op == OP_NAME_UPDATE || op == OP_NAME_MULTISIG) && value.empty()) + if ((op == OP_NAME_NEW || op == OP_NAME_MULTISIG) && value.empty()) { ret.err_msg = "value must not be empty"; return ret; @@ -1155,12 +1156,17 @@ NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, { CNameDB dbName("r"); CTransaction prevTx; - if (!GetLastTxOfName(dbName, name, prevTx)) + CNameRecord nameRec; + if (!GetLastTxOfName(dbName, name, prevTx, nameRec)) { ret.err_msg = "could not find tx with this name"; return ret; } + // empty value == reuse old value + if (op == OP_NAME_UPDATE && value.empty()) + value = nameRec.vtxPos.back().value; + uint256 wtxInHash = prevTx.GetHash(); if (!pwalletMain->mapWallet.count(wtxInHash)) { From 5186c6199887ea8bd6537401b5f8dda833e8e06e Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 08:42:22 +0100 Subject: [PATCH 10/27] Fix Warnings/Errors --- src/qt/walletview.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 6704e9bd..820b306a 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -74,7 +74,7 @@ WalletView::WalletView(QWidget *parent): connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); // Double-clicking on a name on the name page copies all values - connect(manageNamesPage, SIGNAL(doubleClicked(QModelIndex)), manageNamesPage, SLOT(onCopyAllAction())); + connect(dnsPage, SIGNAL(doubleClicked(QModelIndex)), dnsPage, SLOT(onCopyAllAction())); // Clicking on "Export" allows to export the transaction list connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index aba94a2a..13b873b1 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1481,7 +1481,7 @@ CAmount CWallet::GetTotal() const CAmount CWallet::GetStake() const { CAmount nTotal = 0; - LOCK(cs_main, cs_wallet); + LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; From 3be5b63a636d4ce1169f582bff9de57fc5bed158 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:21:54 +0100 Subject: [PATCH 11/27] Fix Gitian Descriptor Paths and Versions --- contrib/gitian-descriptors/gitian-linux.yml | 4 ++-- contrib/gitian-descriptors/gitian-osx.yml | 4 ++-- contrib/gitian-descriptors/gitian-win.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index d313ba4c..0ff119d4 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "silk-linux-0.5" +name: "silk-linux-1.1" enable_cache: true suites: - "trusty" @@ -18,7 +18,7 @@ packages: - "binutils-gold" reference_datetime: "2016-01-01 00:00:00" remotes: -- "url": "https://github.com/Silk/silk.git" +- "url": "https://github.com/silknetwork/silk-core.git" "dir": "silk" files: [] script: | diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index b35a9739..3e96fb04 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "silk-osx-0.5" +name: "silk-osx-1.1" enable_cache: true suites: - "trusty" @@ -21,7 +21,7 @@ packages: - "libbz2-dev" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/Silk/silk.git" +- "url": "https://github.com/silknetwork/silk-core.git" "dir": "silk" files: - "MacOSX10.7.sdk.tar.gz" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 01fef9d3..cf79b34e 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "silk-win-0.5" +name: "silk-win-1.1" enable_cache: true suites: - "trusty" From c85df8aa11941ea2fff141374f117995ee058795 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:24:31 +0100 Subject: [PATCH 12/27] Update Date in Desriptor --- contrib/gitian-descriptors/gitian-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 0ff119d4..b60fc7d7 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -16,7 +16,7 @@ packages: - "faketime" - "bsdmainutils" - "binutils-gold" -reference_datetime: "2016-01-01 00:00:00" +reference_datetime: "2017-01-01 00:00:00" remotes: - "url": "https://github.com/silknetwork/silk-core.git" "dir": "silk" From 06f3d4564c5e185cb3bd1d82ca6f32a274fa8beb Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:25:56 +0100 Subject: [PATCH 13/27] [RPC]fix currency display, fix currency input to match bitcoin --- src/rpc/rpcserver.cpp | 2 +- src/utilmoneystr.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index 05e8e42c..8b35a2d4 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -110,7 +110,7 @@ UniValue ValueFromAmount(const CAmount& amount) int64_t quotient = n_abs / COIN; int64_t remainder = n_abs % COIN; return UniValue(UniValue::VNUM, - strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder)); + strprintf("%s%d.%06d", sign ? "-" : "", quotient, remainder)); } uint256 ParseHashV(const UniValue& v, string strName) diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index 29a0be81..b60141b5 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -53,7 +53,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) if (*p == '.') { p++; - int64_t nMult = CENT*10; + int64_t nMult = CENT*1000; while (isdigit(*p) && (nMult > 0)) { nUnits += nMult * (*p++ - '0'); From 540122c0c0fd3db5fb4ef24d37c411b90f3a3d0b Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:27:55 +0100 Subject: [PATCH 14/27] Revert currency input to old behaviour --- src/rpc/rpcserver.cpp | 5 +++-- src/utilmoneystr.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index 8b35a2d4..011ce3e4 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -95,9 +95,10 @@ CAmount AmountFromValue(const UniValue& value) { if (!value.isNum() && !value.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string"); - CAmount amount; - if (!ParseFixedPoint(value.getValStr(), 8, &amount)) + double dAmount = value.get_real(); + if (dAmount <= 0.0 || dAmount > MAX_MONEY) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); + CAmount amount = roundint64(dAmount * COIN); if (!MoneyRange(amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range"); return amount; diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index b60141b5..29a0be81 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -53,7 +53,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) if (*p == '.') { p++; - int64_t nMult = CENT*1000; + int64_t nMult = CENT*10; while (isdigit(*p) && (nMult > 0)) { nUnits += nMult * (*p++ - '0'); From 82fe483c18e06045f0433da7ecdc9784322038b8 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:40:26 +0100 Subject: [PATCH 15/27] Fix Prev Commit and Fix Missing Function Needed by Windows for SLKDNS --- src/dns/slkdns.cpp | 15 +++++++++++++++ src/main.cpp | 2 +- src/rpc/rpcserver.cpp | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index 43310a78..bf4fa81d 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -87,6 +87,21 @@ int inet_pton(int af, const char *src, void *dst) } return 0; } + +char *strsep(char **s, const char *ct) +{ + char *sstart = *s; + char *end; + + if (sstart == NULL) + return NULL; + + end = strpbrk(sstart, ct); + if (end) + *end++ = '\0'; + *s = end; + return sstart; +} #endif /*---------------------------------------------------*/ diff --git a/src/main.cpp b/src/main.cpp index 87b5660a..fb7d0f46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1300,7 +1300,7 @@ bool IsInitialBlockDownload() if (fImporting || fReindex) break; // ret true - unsigned int cah = chainActive.Height(); + int cah = chainActive.Height(); if(cah < Checkpoints::GetTotalBlocksEstimate() || cah < pindexBestHeader->nHeight - 24 * 6) break; // ret true diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index 011ce3e4..07ec6b92 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -91,6 +91,11 @@ void RPCTypeCheckObj(const UniValue& o, } } +static inline int64_t roundint64(double d) +{ + return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); +} + CAmount AmountFromValue(const UniValue& value) { if (!value.isNum() && !value.isStr()) From d81e76f4112c39f49691185f3b08089695d36398 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 09:42:48 +0100 Subject: [PATCH 16/27] Fix Qt link in depends --- depends/packages/qt.mk | 2 +- src/main.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 6d4206cc..fd62a77e 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,6 +1,6 @@ PACKAGE=qt $(package)_version=5.2.1 -$(package)_download_path=http://download.qt-project.org/official_releases/qt/5.2/$($(package)_version)/single +$(package)_download_path=http://download.qt.io/archive/qt/5.2/$($(package)_version)/single $(package)_file_name=$(package)-everywhere-opensource-src-$($(package)_version).tar.gz $(package)_sha256_hash=84e924181d4ad6db00239d87250cc89868484a14841f77fb85ab1f1dbdcd7da1 $(package)_dependencies=openssl diff --git a/src/main.cpp b/src/main.cpp index fb7d0f46..b1c078b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "kernel.h" #include "keystore.h" #include "dns/dns.h" +#include "rpcserver.h" #include From 2ce004f7a9c61c8072377c7595ad81f423744b06 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 10:04:52 +0100 Subject: [PATCH 17/27] Fix Warnings and include path --- src/dns/slkdns.cpp | 6 +++--- src/main.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index bf4fa81d..5a2c8c72 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -406,7 +406,7 @@ void SlkDns::HandlePacket() { } if(m_status) { - if(m_status = IsInitialBlockDownload()) { + if((m_status = IsInitialBlockDownload())) { m_hdr->Bits |= 2; // Server failure - not available valid nameindex DB yet break; } else { @@ -960,7 +960,7 @@ void SlkDns::Answer_ENUM(const char *q_str) { // Tokenize lines in the NVS-value. // There can be prefixes SIG=, TTL=, E2U while(char *tok = strsep(&str_val, "\n\r")) - switch(*(uint32_t*)tok & 0xffffff | 0x202020) { + switch((*(uint32_t*)tok & 0xffffff) | 0x202020) { case ENC3('e', '2', 'u'): e2u[e2uN++] = tok; continue; @@ -1095,7 +1095,7 @@ bool SlkDns::CheckEnumSig(const char *q_str, char *sig_str) { // SRL=5|srl:hello-%02x ver.mask = VERMASK_NOSRL; while(char *tok = strsep(&str_val, "\n\r")) - if((*(uint32_t*)tok & 0xffffff | 0x202020) == ENC3('s', 'r', 'l') && (tok = strchr(tok + 3, '='))) { + if(((*(uint32_t*)tok & 0xffffff) | 0x202020) == ENC3('s', 'r', 'l') && (tok = strchr(tok + 3, '='))) { unsigned nbits = atoi(++tok); if(nbits > 30) nbits = 30; ///mask = (1 << mask) - 1; diff --git a/src/main.cpp b/src/main.cpp index b1c078b9..b5cc0fe2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,7 @@ #include "kernel.h" #include "keystore.h" #include "dns/dns.h" -#include "rpcserver.h" +#include "rpc/rpcserver.h" #include From 02390712652f7ffc8eb68c743b514b79527783fd Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 10:35:46 +0100 Subject: [PATCH 18/27] Fix further warnings --- src/dns/slkdns.cpp | 2 +- src/qt/calcdialog.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dns/slkdns.cpp b/src/dns/slkdns.cpp index 5a2c8c72..06151360 100644 --- a/src/dns/slkdns.cpp +++ b/src/dns/slkdns.cpp @@ -1001,7 +1001,7 @@ void SlkDns::OutS(const char *p) { // Generate ENUM-answers for a single E2U entry // E2U+sip=100|10|!^(.*)$!sip:17771234567@in.callcentric.com! void SlkDns::HandleE2U(char *e2u) { - char *data = strchr(e2u, '='), *p = data; + char *data = strchr(e2u, '='); if(data == NULL) return; diff --git a/src/qt/calcdialog.cpp b/src/qt/calcdialog.cpp index 88955e5d..29578a22 100644 --- a/src/qt/calcdialog.cpp +++ b/src/qt/calcdialog.cpp @@ -41,8 +41,7 @@ void calcDialog::pushButtonClicked() float rate = 0; CWalletTx tx; CWalletTx ptx; - CWallet *wallet; - const TransactionRecord *wtx; + const TransactionRecord *wtx = nullptr; uint256 hash; QString strRewardSize = ui->stakeDaysEdit->text(); // strUserSize, blockSizeEdit From 13fc6ea36007da272ec0b43e0e90a0498107bb5c Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 10:44:23 +0100 Subject: [PATCH 19/27] Revert travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 312af5a7..97ab2478 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,7 @@ compiler: gcc os: linux sudo: required -dist: precise -group: legacy +dist: trusty install: - sudo apt-get -qq update From b3e8f1864e40c87c1b3b5a5b9fa73397a79c7038 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 11:26:40 +0100 Subject: [PATCH 20/27] Amend name_operation function --- src/dns/dns.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dns/dns.cpp b/src/dns/dns.cpp index 7b7afe31..b1831022 100644 --- a/src/dns/dns.cpp +++ b/src/dns/dns.cpp @@ -980,6 +980,7 @@ UniValue name_new(const UniValue& params, bool fHelp) "name_new [toaddress] [valueAsFilepath]\n" "Creates new key->value pair which expires after specified number of days.\n" "Cost is square root of (1% of last PoW + 1% per year of last PoW)." + "If is empty then previous value is left intact.\n" "If [valueAsFilepath] is non-zero it will interpret as a filepath and try to write file contents in binary format.\n" + HelpRequiringPassphrase()); @@ -1164,7 +1165,7 @@ NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, } // empty value == reuse old value - if (op == OP_NAME_UPDATE && value.empty()) + if ((op == OP_NAME_UPDATE || op == OP_NAME_MULTISIG) && value.empty()) value = nameRec.vtxPos.back().value; uint256 wtxInHash = prevTx.GetHash(); From fb02b98dcd36fc512e7647e8f7e9ebbae4270db2 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 12:11:32 +0100 Subject: [PATCH 21/27] [RPC]add hex and base64 input/output to name_show, name_new, name_update --- src/dns/dns.cpp | 129 ++++++++++++++++++++++++-------------- src/dns/dns.h | 2 +- src/qt/dnspage.cpp | 6 +- src/qt/multisigdialog.cpp | 3 +- src/rpc/rpcclient.cpp | 2 - 5 files changed, 89 insertions(+), 53 deletions(-) diff --git a/src/dns/dns.cpp b/src/dns/dns.cpp index b1831022..98599b80 100644 --- a/src/dns/dns.cpp +++ b/src/dns/dns.cpp @@ -506,11 +506,14 @@ UniValue name_debug(const UniValue& params, bool fHelp) UniValue name_show(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( - "name_show [filepath]\n" + "name_show [valuetype] [filepath]\n" "Show values of a name.\n" - "If filepath is specified name value will be saved in that file in binary format (file will be overwritten!).\n" + "\nArguments:\n" + "1. name (string, required).\n" + "2. valuetype (string, optional) if \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" + "3. filepath (string, optional) save name value in binary format in specified file (file will be overwritten!).\n" ); if (IsInitialBlockDownload()) @@ -518,6 +521,7 @@ UniValue name_show(const UniValue& params, bool fHelp) UniValue oName(UniValue::VOBJ); CNameVal name = nameValFromValue(params[0]); + string outputType = params.size() > 1 ? params[1].get_str() : ""; string sName = stringFromNameVal(name); NameTxInfo nti; { @@ -538,7 +542,13 @@ UniValue name_show(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "failed to decode name"); oName.push_back(Pair("name", sName)); - string value = stringFromNameVal(nti.value); + + // insert value + string value; + if (outputType == "hex") value = HexStr(nti.value); + else if (outputType == "base64") value = EncodeBase64(nti.value.data(), nti.value.size()); + else value = stringFromNameVal(nti.value); + oName.push_back(Pair("value", value)); oName.push_back(Pair("txid", tx.GetHash().GetHex())); oName.push_back(Pair("address", nti.strAddress)); @@ -552,9 +562,9 @@ UniValue name_show(const UniValue& params, bool fHelp) oName.push_back(Pair("expired", true)); } - if (params.size() > 1) + if (params.size() > 2) { - string filepath = params[1].get_str(); + string filepath = params[2].get_str(); ofstream file; file.open(filepath.c_str(), ios::out | ios::binary | ios::trunc); if (!file.is_open()) @@ -977,26 +987,28 @@ UniValue name_new(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( - "name_new [toaddress] [valueAsFilepath]\n" + "name_new [toaddress] [valuetype]\n" "Creates new key->value pair which expires after specified number of days.\n" "Cost is square root of (1% of last PoW + 1% per year of last PoW)." "If is empty then previous value is left intact.\n" - "If [valueAsFilepath] is non-zero it will interpret as a filepath and try to write file contents in binary format.\n" + "\nArguments:\n" + "1. name (string, required) Name to create.\n" + "2. value (string, required) Value to write.\n" + "3. toaddress (string, optional) Address of recipient. Empty string = transaction to yourself.\n" + "4. valuetype (string, optional) Interpretation of value string. Can be \"hex\", \"base64\" or filepath.\n" + " not specified or empty - Write value as a unicode string.\n" + " \"hex\" or \"base64\" - Decode value string as a binary data in hex or base64 string format.\n" + " otherwise - Decode value string as a filepath from which to read the data.\n" + HelpRequiringPassphrase()); // make sure the DDNS entry is all lowercase. CNameVal name = CNameValToLowerCase(nameValFromValue(params[0])); CNameVal value = nameValFromValue(params[1]); int nRentalDays = params[2].get_int(); - string strAddress = ""; - if (params.size() == 4) - strAddress = params[3].get_str(); - - bool fValueAsFilepath = false; - if (params.size() > 4) - fValueAsFilepath = (params[4].get_int() != 0); + string strAddress = params.size() > 3 ? params[3].get_str() : ""; + string strValueType = params.size() > 4 ? params[4].get_str() : ""; - NameTxReturn ret = name_operation(OP_NAME_NEW, name, value, nRentalDays, strAddress, fValueAsFilepath); + NameTxReturn ret = name_operation(OP_NAME_NEW, name, value, nRentalDays, strAddress, strValueType); if (!ret.ok) throw JSONRPCError(ret.err_code, ret.err_msg); return ret.hex.GetHex(); @@ -1006,25 +1018,27 @@ UniValue name_update(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( - "name_update [toaddress] [valueAsFilepath]\n" + "name_update [toaddress] [valuetype]\n" "Update name value, add days to expiration time and possibly transfer a name to diffrent address.\n" - "If is empty then previous value is left intact.\n" - "If [valueAsFilepath] is non-zero it will interpret as a filepath and try to write file contents in binary format.\n" + "\nArguments:\n" + "1. name (string, required) Name to update.\n" + "2. value (string, required) Value to write. Empty string = use previous value.\n" + "3. toaddress (string, optional) Address of recipient. Empty string = transaction to yourself.\n" + "4. valuetype (string, optional) Interpretation of value string. Can be \"hex\", \"base64\" or filepath.\n" + " not specified or empty - Write value as a unicode string.\n" + " \"hex\" or \"base64\" - Decode value string as a binary data in hex or base64 string format.\n" + " otherwise - Decode value string as a filepath from which to read the data.\n" + HelpRequiringPassphrase()); // make sure the DDNS entry is all lowercase. CNameVal name = CNameValToLowerCase(nameValFromValue(params[0])); CNameVal value = nameValFromValue(params[1]); int nRentalDays = params[2].get_int(); - string strAddress = ""; - if (params.size() == 4) - strAddress = params[3].get_str(); + string strAddress = params.size() > 3 ? params[3].get_str() : ""; + string strValueType = params.size() > 4 ? params[4].get_str() : ""; - bool fValueAsFilepath = false; - if (params.size() > 4) - fValueAsFilepath = (params[4].get_int() != 0); + NameTxReturn ret = name_operation(OP_NAME_UPDATE, name, value, nRentalDays, strAddress, strValueType); - NameTxReturn ret = name_operation(OP_NAME_UPDATE, name, value, nRentalDays, strAddress, fValueAsFilepath); if (!ret.ok) throw JSONRPCError(ret.err_code, ret.err_msg); return ret.hex.GetHex(); @@ -1040,14 +1054,14 @@ UniValue name_delete(const UniValue& params, bool fHelp) // make sure the DDNS entry is all lowercase. CNameVal name = CNameValToLowerCase(nameValFromValue(params[0])); - NameTxReturn ret = name_operation(OP_NAME_DELETE, name, CNameVal(), 0, ""); + NameTxReturn ret = name_operation(OP_NAME_DELETE, name, CNameVal(), 0, "", ""); if (!ret.ok) throw JSONRPCError(ret.err_code, ret.err_msg); return ret.hex.GetHex(); } -NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, const int nRentalDays, const string strAddress, bool fValueAsFilepath) +NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, const int nRentalDays, const string& strAddress, const string& strValueType) { NameTxReturn ret; ret.err_code = RPC_INTERNAL_ERROR; // default value in case of abnormal exit @@ -1067,31 +1081,54 @@ NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, return ret; } - if (fValueAsFilepath) + // decode value or leave it as is + if (!strValueType.empty() && !value.empty()) { - string filepath = stringFromNameVal(value); - std::ifstream ifs; - ifs.open(filepath.c_str(), std::ios::binary | std::ios::ate); - if (!ifs) + string strValue = stringFromNameVal(value); + if (strValueType == "hex") { - ret.err_msg = "failed to open file"; - return ret; + if (!IsHex(strValue)) + { + ret.err_msg = "failed to decode value as hex"; + return ret; + } + value = ParseHex(strValue); } - std::streampos fileSize = ifs.tellg(); - if (fileSize > MAX_VALUE_LENGTH) + else if (strValueType == "base64") { - ret.err_msg = "file is larger than maximum allowed size"; - return ret; + bool fInvalid = false; + value = DecodeBase64(strValue.c_str(), &fInvalid); + if (fInvalid) + { + ret.err_msg = "failed to decode value as base64"; + return ret; + } } + else // decode as filepath + { + std::ifstream ifs; + ifs.open(strValue.c_str(), std::ios::binary | std::ios::ate); + if (!ifs) + { + ret.err_msg = "failed to open file"; + return ret; + } + std::streampos fileSize = ifs.tellg(); + if (fileSize > MAX_VALUE_LENGTH) + { + ret.err_msg = "file is larger than maximum allowed size"; + return ret; + } - ifs.clear(); - ifs.seekg(0, std::ios::beg); + ifs.clear(); + ifs.seekg(0, std::ios::beg); - value.resize(fileSize); - if (!ifs.read(reinterpret_cast(&value[0]), fileSize)) - { - ret.err_msg = "failed to read file"; - return ret; + value.resize(fileSize); + if (!ifs.read(reinterpret_cast(&value[0]), fileSize)) + { + ret.err_msg = "failed to read file"; + return ret; + } } } diff --git a/src/dns/dns.h b/src/dns/dns.h index af121cb8..88ed25bc 100644 --- a/src/dns/dns.h +++ b/src/dns/dns.h @@ -124,7 +124,7 @@ struct NameTxReturn std::string address; uint256 hex; // Transaction hash in hex }; -NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, const int nRentalDays, const string strAddress, bool fValueAsFilepath = false); +NameTxReturn name_operation(const int op, const CNameVal& name, CNameVal value, const int nRentalDays, const string& strAddress, const string& strValueType); struct nameTempProxy diff --git a/src/qt/dnspage.cpp b/src/qt/dnspage.cpp index 9753625e..059f3521 100644 --- a/src/qt/dnspage.cpp +++ b/src/qt/dnspage.cpp @@ -333,19 +333,19 @@ void DNSPage::on_submitNameButton_clicked() { nHeight = NameTableEntry::NAME_NEW; status = CT_NEW; - res = name_operation(OP_NAME_NEW, name, value, days, newAddress.toStdString()); + res = name_operation(OP_NAME_NEW, name, value, days, newAddress.toStdString(), ""); } else if (txType == "NAME_UPDATE") { nHeight = NameTableEntry::NAME_UPDATE; status = CT_UPDATED; - res = name_operation(OP_NAME_UPDATE, name, value, days, newAddress.toStdString()); + res = name_operation(OP_NAME_UPDATE, name, value, days, newAddress.toStdString(), ""); } else if (txType == "NAME_DELETE") { nHeight = NameTableEntry::NAME_DELETE; status = CT_UPDATED; //we still want to display this name until it is deleted - res = name_operation(OP_NAME_DELETE, name, CNameVal(), 0, ""); + res = name_operation(OP_NAME_DELETE, name, CNameVal(), 0, "", ""); } importedAsBinaryFile.clear(); diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index 9b697afa..3bdad2fc 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -106,9 +106,10 @@ bool MultisigDialog::AdvertisePublicKeyForMultiSig(const std::string& address, c string strAddress = ""; CNameVal name = nameValFromString("address:" + address); CNameVal value = nameValFromString(publickey); + string strValue = stringFromNameVal(value); int nRentalDays = 35; - NameTxReturn ret = name_operation(OP_NAME_MULTISIG, name, value, nRentalDays, address); + NameTxReturn ret = name_operation(OP_NAME_MULTISIG, name, value, nRentalDays, address, strValue); if (!ret.ok) { QMessageBox::critical(this, tr("Multisig Dialog: Advertise PublicKey Error!"), tr("%1: %2").arg(ret.err_code).arg(ret.err_msg.c_str())); diff --git a/src/rpc/rpcclient.cpp b/src/rpc/rpcclient.cpp index d4181ade..7383e8db 100644 --- a/src/rpc/rpcclient.cpp +++ b/src/rpc/rpcclient.cpp @@ -103,9 +103,7 @@ static const CRPCConvertParam vRPCConvertParams[] = // Silk: { "name_new", 2 }, - { "name_new", 4 }, { "name_update", 2 }, - { "name_update", 4 }, { "name_filter", 1 }, { "name_filter", 2 }, { "name_filter", 3 }, From 6902c699e5f5c34f3e60dd7f4fcac620b8a50810 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 12:24:32 +0100 Subject: [PATCH 22/27] [RPC]add hex and base64 output to the rest on name commands --- src/dns/dns.cpp | 127 +++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 71 deletions(-) diff --git a/src/dns/dns.cpp b/src/dns/dns.cpp index 98599b80..2bebae73 100644 --- a/src/dns/dns.cpp +++ b/src/dns/dns.cpp @@ -83,6 +83,15 @@ string limitString(const string& inp, unsigned int size, string message = "") return ret; } +string encodeNameVal(const CNameVal& input, const string& format) +{ + string output; + if (format == "hex") output = HexStr(input); + else if (format == "base64") output = EncodeBase64(input.data(), input.size()); + else output = stringFromNameVal(input); + return output; +} + // Calculate at which block will expire. bool CalculateExpiresAt(CNameRecord& nameRec) { @@ -366,18 +375,20 @@ bool CNamecoinHooks::RemoveNameScriptPrefix(const CScript& scriptIn, CScript& sc UniValue name_list(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 1) + if (fHelp || params.size() > 2) throw runtime_error( - "name_list []\n" - "list my own names" - ); + "name_list [name] [valuetype]\n" + "list my own names.\n" + "\nArguments:\n" + "1. name (string, required) Restrict output to specific name.\n" + "2. valuetype (string, optional) If \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" + ); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Silk is downloading blocks..."); - CNameVal nameUniq; - if (params.size() == 1) - nameUniq = nameValFromValue(params[0]); + CNameVal nameUniq = params.size() > 0 ? nameValFromValue(params[0]) : CNameVal(); + string outputType = params.size() > 1 ? params[1].get_str() : ""; map mapNames, mapPending; GetNameList(nameUniq, mapNames, mapPending); @@ -387,7 +398,7 @@ UniValue name_list(const UniValue& params, bool fHelp) { UniValue oName(UniValue::VOBJ); oName.push_back(Pair("name", stringFromNameVal(item.second.name))); - oName.push_back(Pair("value", stringFromNameVal(item.second.value))); + oName.push_back(Pair("value", encodeNameVal(item.second.value, outputType))); if (item.second.fIsMine == false) oName.push_back(Pair("transferred", true)); oName.push_back(Pair("address", item.second.strAddress)); @@ -512,7 +523,7 @@ UniValue name_show(const UniValue& params, bool fHelp) "Show values of a name.\n" "\nArguments:\n" "1. name (string, required).\n" - "2. valuetype (string, optional) if \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" + "2. valuetype (string, optional) If \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" "3. filepath (string, optional) save name value in binary format in specified file (file will be overwritten!).\n" ); @@ -542,14 +553,7 @@ UniValue name_show(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "failed to decode name"); oName.push_back(Pair("name", sName)); - - // insert value - string value; - if (outputType == "hex") value = HexStr(nti.value); - else if (outputType == "base64") value = EncodeBase64(nti.value.data(), nti.value.size()); - else value = stringFromNameVal(nti.value); - - oName.push_back(Pair("value", value)); + oName.push_back(Pair("value", encodeNameVal(nti.value, outputType))); oName.push_back(Pair("txid", tx.GetHash().GetHex())); oName.push_back(Pair("address", nti.strAddress)); oName.push_back(Pair("expires_in", nameRec.nExpiresAt - chainActive.Height())); @@ -579,13 +583,14 @@ UniValue name_show(const UniValue& params, bool fHelp) UniValue name_history (const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw std::runtime_error ( - "name_history \"name\" ( fullhistory )\n" + "name_history [fullhistory] [valuetype]\n" "\nLook up the current and all past data for the given name.\n" "\nArguments:\n" - "1. \"name\" (string, required) the name to query for\n" - "2. \"fullhistory\" (boolean, optional) shows full history, even if name is not active\n" + "1. name (string, required) the name to query for\n" + "2. fullhistory (boolean, optional) shows full history, even if name is not active\n" + "3. valuetype (string, optional) If \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" "\nResult:\n" "[\n" " {\n" @@ -608,9 +613,8 @@ UniValue name_history (const UniValue& params, bool fHelp) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Silk is downloading blocks..."); CNameVal name = nameValFromValue(params[0]); - bool fFullHistory = false; - if (params.size() > 1) - fFullHistory = params[1].get_bool(); + bool fFullHistory = params.size() > 1 ? params[1].get_bool() : false; + string outputType = params.size() > 2 ? params[2].get_str() : ""; CNameRecord nameRec; { @@ -648,7 +652,7 @@ UniValue name_history (const UniValue& params, bool fHelp) if (nti.op == OP_NAME_UPDATE || nti.op == OP_NAME_NEW || nti.op == OP_NAME_MULTISIG) obj.push_back(Pair("days_added", nti.nRentalDays)); if (nti.op == OP_NAME_UPDATE || nti.op == OP_NAME_NEW || nti.op == OP_NAME_MULTISIG) - obj.push_back(Pair("value", stringFromNameVal(nti.value))); + obj.push_back(Pair("value", encodeNameVal(nti.value, outputType))); res.push_back(obj); } @@ -658,9 +662,11 @@ UniValue name_history (const UniValue& params, bool fHelp) UniValue name_mempool (const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 0) + if (fHelp || params.size() > 1) throw std::runtime_error ( - "name_mempool\n" + "name_mempool [valuetype]\n" + "\nArguments:\n" + "1. valuetype (string, optional) If \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" "\nList pending name transactions in mempool.\n" "\nResult:\n" "[\n" @@ -680,6 +686,8 @@ UniValue name_mempool (const UniValue& params, bool fHelp) + HelpExampleRpc ("name_mempool", "" ) ); + string outputType = params.size() > 0 ? params[0].get_str() : ""; + UniValue res(UniValue::VARR); BOOST_FOREACH(const PAIRTYPE(CNameVal, set) &pairPending, mapNamePending) { @@ -705,7 +713,7 @@ UniValue name_mempool (const UniValue& params, bool fHelp) if (nti.op == OP_NAME_UPDATE || nti.op == OP_NAME_NEW || nti.op == OP_NAME_MULTISIG) obj.push_back(Pair("days_added", nti.nRentalDays)); if (nti.op == OP_NAME_UPDATE || nti.op == OP_NAME_NEW || nti.op == OP_NAME_MULTISIG) - obj.push_back(Pair("value", stringFromNameVal(nti.value))); + obj.push_back(Pair("value", encodeNameVal(nti.value, outputType))); res.push_back(obj); } @@ -720,17 +728,19 @@ bool mycompare2 (const UniValue& lhs, const UniValue& rhs) return lhs[pos].get_int() < rhs[pos].get_int(); } + UniValue name_filter(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 5) + if (fHelp || params.size() > 6) throw runtime_error( - "name_filter [[[[[regexp] maxage=0] from=0] nb=0] stat]\n" + "name_filter [regexp] [maxage=0] [from=0] [nb=0] [stat] [valuetype]\n" "scan and filter names\n" "[regexp] : apply [regexp] on names, empty means all names\n" "[maxage] : look in last [maxage] blocks\n" "[from] : show results from number [from]\n" "[nb] : show [nb] results, 0 means all\n" - "[stats] : show some stats instead of results\n" + "[stat] : show some stats instead of results\n" + "[valuetype] : if \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" "name_filter \"\" 5 # list names updated in last 5 blocks\n" "name_filter \"^id/\" # list all names from the \"id\" namespace\n" "name_filter \"^id/\" 0 0 0 stat # display stats (number of names) on active names from the \"id\" namespace\n" @@ -739,29 +749,16 @@ UniValue name_filter(const UniValue& params, bool fHelp) if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Silk is downloading blocks..."); - string strRegexp; - int nFrom = 0; - int nNb = 0; - int nMaxAge = 0; - bool fStat = false; int nCountFrom = 0; int nCountNb = 0; - if (params.size() > 0) - strRegexp = params[0].get_str(); - - if (params.size() > 1) - nMaxAge = params[1].get_int(); - - if (params.size() > 2) - nFrom = params[2].get_int(); - - if (params.size() > 3) - nNb = params[3].get_int(); - - if (params.size() > 4) - fStat = (params[4].get_str() == "stat" ? true : false); + string strRegexp = params.size() > 0 ? params[0].get_str() : ""; + int nMaxAge = params.size() > 1 ? params[1].get_int() : 0; + int nFrom = params.size() > 2 ? params[2].get_int() : 0; + int nNb = params.size() > 3 ? params[3].get_int() : 0; + bool fStat = params.size() > 4 ? (params[4].get_str() == "stat" ? true : false) : false; + string outputType = params.size() > 5 ? params[5].get_str() : ""; CNameDB dbName("r"); vector oRes; @@ -812,9 +809,7 @@ UniValue name_filter(const UniValue& params, bool fHelp) UniValue oName(UniValue::VOBJ); if (!fStat) { oName.push_back(Pair("name", name)); - - string value = stringFromNameVal(txName.value); - oName.push_back(Pair("value", limitString(value, 300, "\n...(value too large - use name_show to see full value)"))); + oName.push_back(Pair("value", limitString(encodeNameVal(txName.value, outputType), 300, "\n...(value too large - use name_show to see full value)"))); oName.push_back(Pair("registered_at", nHeight)); // pos = 2 in comparison function (above name_filter) @@ -852,31 +847,22 @@ UniValue name_filter(const UniValue& params, bool fHelp) UniValue name_scan(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 3) + if (fHelp || params.size() > 4) throw runtime_error( - "name_scan [start-name] [max-returned] [max-value-length=-1]\n" + "name_scan [start-name] [max-returned] [max-value-length=-1] [valuetype]\n" "Scan all names, starting at start-name and returning a maximum number of entries (default 500)\n" "You can also control the length of shown value (0 = full value)\n" + "[valuetype] : if \"hex\" or \"base64\" is specified then it will print value in corresponding format instead of string.\n" ); if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Silk is downloading blocks..."); - CNameVal name; + CNameVal name = params.size() > 0 ? nameValFromValue(params[0]) : CNameVal(); string strSearchName = ""; - unsigned int nMax = 500; - unsigned int mMaxShownValue = 96; - if (params.size() > 0) - { - name = nameValFromValue(params[0]); - strSearchName = params[0].get_str(); - } - - if (params.size() > 1) - nMax = params[1].get_int(); - - if (params.size() > 2) - mMaxShownValue = params[2].get_int(); + int nMax = params.size() > 1 ? params[1].get_int() : 500; + int mMaxShownValue = params.size() > 2 ? params[2].get_int() : 0; + string outputType = params.size() > 3 ? params[3].get_str() : ""; CNameDB dbName("r"); UniValue oRes(UniValue::VARR); @@ -899,9 +885,8 @@ UniValue name_scan(const UniValue& params, bool fHelp) CNameIndex txName = pairScan.second.first; int nExpiresAt = pairScan.second.second; CNameVal value = txName.value; - string sValue = stringFromNameVal(value); - oName.push_back(Pair("value", limitString(sValue, mMaxShownValue, "\n...(value too large - use name_show to see full value)"))); + oName.push_back(Pair("value", limitString(encodeNameVal(value, outputType), mMaxShownValue, "\n...(value too large - use name_show to see full value)"))); oName.push_back(Pair("expires_in", nExpiresAt - chainActive.Height())); if (nExpiresAt - chainActive.Height() <= 0) oName.push_back(Pair("expired", true)); From 7f1a5aa1f127209081f466345760acf442447230 Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Fri, 27 Jan 2017 12:37:40 +0100 Subject: [PATCH 23/27] [RPC]add legacy json mode (enabled by default) --- src/rpc/rpcprotocol.cpp | 5 +- src/rpc/rpcserver.cpp | 6 +- src/silk-cli.cpp | 10 +- src/univalue/Makefile.am | 2 +- src/univalue/include/univalue.h | 15 +- src/univalue/lib/json_spirit_legacy.h | 211 ++++++++++++++++++++++++++ src/univalue/lib/univalue_read.cpp | 28 +++- src/univalue/lib/univalue_write.cpp | 23 +-- 8 files changed, 273 insertions(+), 27 deletions(-) create mode 100644 src/univalue/lib/json_spirit_legacy.h diff --git a/src/rpc/rpcprotocol.cpp b/src/rpc/rpcprotocol.cpp index ad45a750..3fc73370 100644 --- a/src/rpc/rpcprotocol.cpp +++ b/src/rpc/rpcprotocol.cpp @@ -263,7 +263,7 @@ string JSONRPCRequest(const string& strMethod, const UniValue& params, const Uni request.push_back(Pair("method", strMethod)); request.push_back(Pair("params", params)); request.push_back(Pair("id", id)); - return request.write() + "\n"; + return request.write(0, 0, GetBoolArg("-legacyrpc", true)) + "\n"; } UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id) @@ -281,7 +281,8 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) { UniValue reply = JSONRPCReplyObj(result, error, id); - return reply.write() + "\n"; + static bool legacy = GetBoolArg("-legacyrpc", true); + return reply.write(0, 0, legacy) + "\n"; } UniValue JSONRPCError(int code, const string& message) diff --git a/src/rpc/rpcserver.cpp b/src/rpc/rpcserver.cpp index 07ec6b92..8995e3fb 100644 --- a/src/rpc/rpcserver.cpp +++ b/src/rpc/rpcserver.cpp @@ -772,7 +772,8 @@ static string JSONRPCExecBatch(const UniValue& vReq) for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) ret.push_back(JSONRPCExecOne(vReq[reqIdx])); - return ret.write() + "\n"; + static bool legacy = GetBoolArg("-legacyrpc", true); + return ret.write(0, 0, legacy) + "\n"; } static bool HTTPReq_JSONRPC(AcceptedConnection *conn, @@ -804,7 +805,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, { // Parse request UniValue valRequest; - if (!valRequest.read(strRequest)) + static bool legacy = GetBoolArg("-legacyrpc", true); + if (!valRequest.read(strRequest, legacy ? 2 : 0)) throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); // Return immediately if in warmup diff --git a/src/silk-cli.cpp b/src/silk-cli.cpp index 63e0a8f4..c70cf1b9 100644 --- a/src/silk-cli.cpp +++ b/src/silk-cli.cpp @@ -147,9 +147,17 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) else if (strReply.empty()) throw runtime_error("no response from server"); + // silk: + // we get emercoind output (possibly binary) of .write() that either: + // 1) escapes some unicode characters (defined in univalue_escapes.h) + // 2) escapes all unicode character as in legacy json_spirit + // we must get back the same string byte by byte by invoking .read() with mode=1 or mode=2. + // finaly we "return reply" and it gets .write() in upper function + int mode = GetBoolArg("-legacyrpc", true) ? 2 : (strMethod.rfind("name_", 0) != std::string::npos ? 1 : 0); + // Parse reply UniValue valReply(UniValue::VSTR); - if (!valReply.read(strReply)) + if (!valReply.read(strReply, mode)) throw runtime_error("couldn't parse reply from server"); const UniValue& reply = valReply.get_obj(); if (reply.empty()) diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am index 6c1ec81e..4adaa1b1 100644 --- a/src/univalue/Makefile.am +++ b/src/univalue/Makefile.am @@ -3,7 +3,7 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 .INTERMEDIATE: $(GENBIN) include_HEADERS = include/univalue.h -noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h +noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h lib/json_spirit_legacy.h lib_LTLIBRARIES = libunivalue.la diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 8428b1c6..5a06c778 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -122,11 +122,12 @@ class UniValue { bool pushKVs(const UniValue& obj); std::string write(unsigned int prettyIndent = 0, - unsigned int indentLevel = 0) const; + unsigned int indentLevel = 0, + bool legacy = false) const; - bool read(const char *raw); - bool read(const std::string& rawStr) { - return read(rawStr.c_str()); + bool read(const char *raw, int mode = 0); + bool read(const std::string& rawStr, int mode = 0) { + return read(rawStr.c_str(), mode); } private: @@ -136,8 +137,8 @@ class UniValue { std::vector values; int findKey(const std::string& key) const; - void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; - void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; + void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s, bool legacy = false) const; + void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s, bool legacy = false) const; public: // Strict type-specific getters, these throw std::runtime_error if the @@ -240,7 +241,7 @@ enum jtokentype { }; extern enum jtokentype getJsonToken(std::string& tokenVal, - unsigned int& consumed, const char *raw); + unsigned int& consumed, const char *raw, int mode = 0); extern const char *uvTypeName(UniValue::VType t); static inline bool jsonTokenIsValue(enum jtokentype jtt) diff --git a/src/univalue/lib/json_spirit_legacy.h b/src/univalue/lib/json_spirit_legacy.h new file mode 100644 index 00000000..e412b33b --- /dev/null +++ b/src/univalue/lib/json_spirit_legacy.h @@ -0,0 +1,211 @@ +#ifndef JSON_SPIRIT_LEGACY_H +#define JSON_SPIRIT_LEGACY_H + + +/* ----------------------------------------------------------------------- + * -------------------------------- write -------------------------------- + * ----------------------------------------------------------------------- + */ + +template < class String_type > +String_type to_str( const char* c_str ) +{ + String_type result; + + for( const char* p = c_str; *p != 0; ++p ) + { + result += *p; + } + + return result; +} + +inline char to_hex_char( unsigned int c ) +{ + assert( c <= 0xF ); + + const char ch = static_cast< char >( c ); + + if( ch < 10 ) return '0' + ch; + + return 'A' - 10 + ch; +} + +template< class String_type > +String_type non_printable_to_string( unsigned int c ) +{ + // Silence the warning: typedef ‘Char_type’ locally defined but not used [-Wunused-local-typedefs] + // typedef typename String_type::value_type Char_type; + + String_type result( 6, '\\' ); + + result[1] = 'u'; + + result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 2 ] = to_hex_char( c & 0x000F ); + + return result; +} + +template< typename Char_type, class String_type > +bool add_esc_char( Char_type c, String_type& s ) +{ + switch( c ) + { + case '"': s += to_str< String_type >( "\\\"" ); return true; + case '\\': s += to_str< String_type >( "\\\\" ); return true; + case '\b': s += to_str< String_type >( "\\b" ); return true; + case '\f': s += to_str< String_type >( "\\f" ); return true; + case '\n': s += to_str< String_type >( "\\n" ); return true; + case '\r': s += to_str< String_type >( "\\r" ); return true; + case '\t': s += to_str< String_type >( "\\t" ); return true; + } + + return false; +} + +template< class String_type > +String_type add_esc_chars( const String_type& s ) +{ + typedef typename String_type::const_iterator Iter_type; + typedef typename String_type::value_type Char_type; + + String_type result; + + const Iter_type end( s.end() ); + + for( Iter_type i = s.begin(); i != end; ++i ) + { + const Char_type c( *i ); + + if( add_esc_char( c, result ) ) continue; + + const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); + + if( iswprint( unsigned_c ) ) + { + result += c; + } + else + { + result += non_printable_to_string< String_type >( unsigned_c ); + } + } + + return result; +} + +/* ---------------------------------------------------------------------- + * -------------------------------- read -------------------------------- + * ---------------------------------------------------------------------- + */ + +template< class Char_type > +Char_type hex_to_num( const Char_type c ) +{ + if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; + if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; + if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; + return 0; +} + +template< class Char_type, class Iter_type > +Char_type hex_str_to_char( Iter_type& begin ) +{ + const Char_type c1( *( ++begin ) ); + const Char_type c2( *( ++begin ) ); + + return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); +} + +template< class Char_type, class Iter_type > +Char_type unicode_str_to_char( Iter_type& begin ) +{ + const Char_type c1( *( ++begin ) ); + const Char_type c2( *( ++begin ) ); + const Char_type c3( *( ++begin ) ); + const Char_type c4( *( ++begin ) ); + + return ( hex_to_num( c1 ) << 12 ) + + ( hex_to_num( c2 ) << 8 ) + + ( hex_to_num( c3 ) << 4 ) + + hex_to_num( c4 ); +} + +template< class String_type > +void append_esc_char_and_incr_iter( String_type& s, + typename String_type::const_iterator& begin, + typename String_type::const_iterator end ) +{ + typedef typename String_type::value_type Char_type; + + const Char_type c2( *begin ); + + switch( c2 ) + { + case 't': s += '\t'; break; + case 'b': s += '\b'; break; + case 'f': s += '\f'; break; + case 'n': s += '\n'; break; + case 'r': s += '\r'; break; + case '\\': s += '\\'; break; + case '/': s += '/'; break; + case '"': s += '"'; break; + case 'x': + { + if( end - begin >= 3 ) // expecting "xHH..." + { + s += hex_str_to_char< Char_type >( begin ); + } + break; + } + case 'u': + { + if( end - begin >= 5 ) // expecting "uHHHH..." + { + s += unicode_str_to_char< Char_type >( begin ); + } + break; + } + } +} + +template< class String_type > +String_type substitute_esc_chars( typename String_type::const_iterator begin, + typename String_type::const_iterator end ) +{ + typedef typename String_type::const_iterator Iter_type; + + if( end - begin < 2 ) return String_type( begin, end ); + + String_type result; + + result.reserve( end - begin ); + + const Iter_type end_minus_1( end - 1 ); + + Iter_type substr_start = begin; + Iter_type i = begin; + + for( ; i < end_minus_1; ++i ) + { + if( *i == '\\' ) + { + result.append( substr_start, i ); + + ++i; // skip the '\' + + append_esc_char_and_incr_iter( result, i, end ); + + substr_start = i + 1; + } + } + + result.append( substr_start, end ); + + return result; +} + +#endif // JSON_SPIRIT_LEGACY_H \ No newline at end of file diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp index 95bac695..95fd9294 100644 --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -7,6 +7,7 @@ #include #include "univalue.h" #include "univalue_utffilter.h" +#include "json_spirit_legacy.h" using namespace std; @@ -43,7 +44,7 @@ static const char *hatoui(const char *first, const char *last, } enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, - const char *raw) + const char *raw, int mode) { tokenVal.clear(); consumed = 0; @@ -178,10 +179,13 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, JSONUTF8StringFilter writer(valStr); while (*raw) { - if ((unsigned char)*raw < 0x20) + if ((unsigned char)*raw < 0x20 && mode == 0) return JTOK_ERR; else if (*raw == '\\') { + if (mode == 2) { // write 2 bytes + valStr += *raw; raw++; valStr += *raw; raw++; + } else { raw++; // skip backslash switch (*raw) { @@ -209,6 +213,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } raw++; // skip esc'd char + } } else if (*raw == '"') { @@ -217,11 +222,19 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } else { - writer.push_back(*raw); + if (mode == 1 || mode == 2) + valStr += *raw; + else + writer.push_back(*raw); raw++; } } + if (mode == 2) // read string as json_spirit output + { + valStr = substitute_esc_chars< std::string >( valStr.begin(), valStr.end() ); + } + if (!writer.finalize()) return JTOK_ERR; tokenVal = valStr; @@ -246,7 +259,12 @@ enum expect_bits { #define setExpect(bit) (expectMask |= EXP_##bit) #define clearExpect(bit) (expectMask &= ~EXP_##bit) -bool UniValue::read(const char *raw) +// mode: +// 0 - Default univalue behavior +// 1 - Allow strings with binary data to be read without errors. +// This is needed for outputing name commands that might have binary data in their value. +// 2 - Legacy mode. Read string that was generated by json_spirit. +bool UniValue::read(const char *raw, int mode) { clear(); @@ -260,7 +278,7 @@ bool UniValue::read(const char *raw) do { last_tok = tok; - tok = getJsonToken(tokenVal, consumed, raw); + tok = getJsonToken(tokenVal, consumed, raw, mode); if (tok == JTOK_NONE || tok == JTOK_ERR) return false; raw += consumed; diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp index cfbdad32..7b1adb1f 100644 --- a/src/univalue/lib/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -7,11 +7,15 @@ #include #include "univalue.h" #include "univalue_escapes.h" +#include "json_spirit_legacy.h" using namespace std; -static string json_escape(const string& inS) +static string json_escape(const string& inS, bool legacy=false) { + if (legacy) + return add_esc_chars(inS); + string outS; outS.reserve(inS.size() * 2); @@ -29,7 +33,8 @@ static string json_escape(const string& inS) } string UniValue::write(unsigned int prettyIndent, - unsigned int indentLevel) const + unsigned int indentLevel, + bool legacy) const { string s; s.reserve(1024); @@ -43,13 +48,13 @@ string UniValue::write(unsigned int prettyIndent, s += "null"; break; case VOBJ: - writeObject(prettyIndent, modIndent, s); + writeObject(prettyIndent, modIndent, s, legacy); break; case VARR: - writeArray(prettyIndent, modIndent, s); + writeArray(prettyIndent, modIndent, s, legacy); break; case VSTR: - s += "\"" + json_escape(val) + "\""; + s += "\"" + json_escape(val, legacy) + "\""; break; case VNUM: s += val; @@ -67,7 +72,7 @@ static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, strin s.append(prettyIndent * indentLevel, ' '); } -void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s, bool legacy) const { s += "["; if (prettyIndent) @@ -76,7 +81,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s for (unsigned int i = 0; i < values.size(); i++) { if (prettyIndent) indentStr(prettyIndent, indentLevel, s); - s += values[i].write(prettyIndent, indentLevel + 1); + s += values[i].write(prettyIndent, indentLevel + 1, legacy); if (i != (values.size() - 1)) { s += ","; if (prettyIndent) @@ -91,7 +96,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s s += "]"; } -void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s, bool legacy) const { s += "{"; if (prettyIndent) @@ -103,7 +108,7 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, s += "\"" + json_escape(keys[i]) + "\":"; if (prettyIndent) s += " "; - s += values.at(i).write(prettyIndent, indentLevel + 1); + s += values.at(i).write(prettyIndent, indentLevel + 1, legacy); if (i != (values.size() - 1)) s += ","; if (prettyIndent) From e295e9a74373b52b536e7c076e85884ce69c7b76 Mon Sep 17 00:00:00 2001 From: coin-info-net Date: Fri, 27 Jan 2017 16:57:59 +0100 Subject: [PATCH 24/27] depends fix --- depends/builders/linux.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index 50931106..b03f4240 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,3 +1,2 @@ build_linux_SHA256SUM = sha256sum build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o -View From ccdcf94863d16a9c751f209b3e2e6f5ef0676be4 Mon Sep 17 00:00:00 2001 From: coin-info-net Date: Fri, 27 Jan 2017 16:59:31 +0100 Subject: [PATCH 25/27] Update Protobuf 2.5.0 -> 2.6.1 --- depends/packages/native_protobuf.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk index ed1a771f..ce50b366 100644 --- a/depends/packages/native_protobuf.mk +++ b/depends/packages/native_protobuf.mk @@ -1,8 +1,8 @@ package=native_protobuf -$(package)_version=2.5.0 -$(package)_download_path=https://protobuf.googlecode.com/files +$(package)_version=2.6.1 +$(package)_download_path=https://github.com/google/protobuf/releases/download/v$($(package)_version) $(package)_file_name=protobuf-$($(package)_version).tar.bz2 -$(package)_sha256_hash=13bfc5ae543cf3aa180ac2485c0bc89495e3ae711fc6fab4f8ffe90dfb4bb677 +$(package)_sha256_hash=ee445612d544d885ae240ffbcbf9267faa9f593b7b101f21d58beceb92661910 define $(package)_set_vars $(package)_config_opts=--disable-shared From 56a42761d8d4b063a26bd4f0bcdd8bbe17942a7b Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Sat, 28 Jan 2017 09:32:21 +0100 Subject: [PATCH 26/27] Add Checkpoints --- src/chainparams.cpp | 1 + src/kernel.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 01b64a32..f1972047 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -148,6 +148,7 @@ static Checkpoints::MapCheckpoints mapCheckpoints = ( 4000, uint256("0x00000030b6226239a0d3b809e3b076e3a75476fe8048dc41859a6138f63a7a28")) ( 10000, uint256("0x0a7589f8bdc5e49f55e4ba3ba8875b909e7ca4802a0505b94d0b42b5f55d1598")) ( 40000, uint256("0xc6b43d4102098d0babf3529ebe9fc772bec026a36319b534d94f6fde64b963d9")) + ( 160000, uint256("0x62cf48b78e93ef09d60c83da6da1c7b3dfa6602126e36d6756706124d2fb730b")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, diff --git a/src/kernel.cpp b/src/kernel.cpp index 91c38884..b8196b6a 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -32,6 +32,8 @@ static std::map mapStakeModifierCheckpoints = ( 8000, 0x481e05e4u ) ( 16000, 0xd6f5eccbu ) ( 32000, 0x7f331195u ) + ( 64000, 0xa9ee80a2u ) + ( 128000, 0xed217450u ) ; // Get time weight From 7309d94d382a5975d17f2904ecf8f6a53580cfad Mon Sep 17 00:00:00 2001 From: Spencer Lievens Date: Sat, 28 Jan 2017 10:30:31 +0100 Subject: [PATCH 27/27] Locks/Better Logging/Typos --- src/chainparams.cpp | 10 +++++----- src/net.cpp | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f1972047..32c3816c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -45,11 +45,11 @@ void MineGenesis(CBlock genesis, uint256 bnProofOfWorkLimit){ printf("New best: %s\n", newhash.GetHex().c_str()); } } - printf("Gensis Hash: %s\n", genesis.GetHash().ToString().c_str()); - printf("Gensis Hash Merkle: %s\n", genesis.hashMerkleRoot.ToString().c_str()); - printf("Gensis nTime: %u\n", genesis.nTime); - printf("Gensis nBits: %08x\n", genesis.nBits); - printf("Gensis Nonce: %u\n\n\n", genesis.nNonce); + printf("Genesis Hash: %s\n", genesis.GetHash().ToString().c_str()); + printf("Genesis Hash Merkle: %s\n", genesis.hashMerkleRoot.ToString().c_str()); + printf("Genesis nTime: %u\n", genesis.nTime); + printf("Genesis nBits: %08x\n", genesis.nBits); + printf("Genesis Nonce: %u\n\n\n", genesis.nNonce); } /** diff --git a/src/net.cpp b/src/net.cpp index 6e053040..cb5a9c73 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -242,6 +242,7 @@ void AdvertizeLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { + LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } @@ -361,6 +362,7 @@ uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; CCriticalSection CNode::cs_totalBytesSent; + CNode* FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -485,6 +487,7 @@ CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() { + LOCK(cs_setBanned); setBanned.clear(); }