diff options
-rw-r--r-- | doc/release-notes.md | 15 | ||||
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/bitcoin-tx.cpp | 10 | ||||
-rw-r--r-- | src/eccryptoverify.cpp | 68 | ||||
-rw-r--r-- | src/eccryptoverify.h | 21 | ||||
-rw-r--r-- | src/ecwrapper.cpp | 218 | ||||
-rw-r--r-- | src/ecwrapper.h | 40 | ||||
-rw-r--r-- | src/httpserver.cpp | 4 | ||||
-rw-r--r-- | src/init.cpp | 8 | ||||
-rw-r--r-- | src/main.cpp | 14 | ||||
-rw-r--r-- | src/main.h | 5 | ||||
-rw-r--r-- | src/miner.cpp | 15 | ||||
-rw-r--r-- | src/miner.h | 2 | ||||
-rw-r--r-- | src/pubkey.cpp | 260 | ||||
-rw-r--r-- | src/pubkey.h | 16 | ||||
-rw-r--r-- | src/rpcmining.cpp | 10 | ||||
-rw-r--r-- | src/rpcnet.cpp | 11 | ||||
-rw-r--r-- | src/script/bitcoinconsensus.cpp | 9 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 13 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 29 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 7 | ||||
-rw-r--r-- | src/test/test_bitcoin.h | 3 |
22 files changed, 347 insertions, 441 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md index e4dcc60cff..7db27f9fac 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -190,6 +190,21 @@ calculating the target. A more detailed documentation about keeping traffic low can be found in [/doc/reducetraffic.md](/doc/reducetraffic.md). +Signature validation using libsecp256k1 +--------------------------------------- + +ECDSA signatures inside Bitcoin transactions now use validation using +[https://github.com/bitcoin/secp256k1](libsecp256k1) instead of OpenSSL. + +Depending on the platform, this means a significant speedup for raw signature +validation speed. The advantage is largest on x86_64, where validation is over +five times faster. In practice, this translates to a raw reindexing and new +block validation times that are less than half of what it was before. + +Libsecp256k1 has undergone very extensive testing and validation. + +A side effect of this change is that libconsensus no longer depends on OpenSSL. + 0.12.0 Change log ================= diff --git a/src/Makefile.am b/src/Makefile.am index 834c3dc891..f1e98dabde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,8 +104,6 @@ BITCOIN_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ - eccryptoverify.h \ - ecwrapper.h \ hash.h \ httprpc.h \ httpserver.h \ @@ -272,8 +270,6 @@ libbitcoin_common_a_SOURCES = \ compressor.cpp \ core_read.cpp \ core_write.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ key.cpp \ keystore.cpp \ @@ -404,8 +400,6 @@ libbitcoinconsensus_la_SOURCES = \ crypto/sha1.cpp \ crypto/sha256.cpp \ crypto/sha512.cpp \ - eccryptoverify.cpp \ - ecwrapper.cpp \ hash.cpp \ primitives/transaction.cpp \ pubkey.cpp \ @@ -420,8 +414,8 @@ if GLIBC_BACK_COMPAT endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) -libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 48033cd8ad..9f8b2b98af 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -477,9 +477,15 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) class Secp256k1Init { + ECCVerifyHandle globalVerifyHandle; + public: - Secp256k1Init() { ECC_Start(); } - ~Secp256k1Init() { ECC_Stop(); } + Secp256k1Init() { + ECC_Start(); + } + ~Secp256k1Init() { + ECC_Stop(); + } }; static void MutateTx(CMutableTransaction& tx, const string& command, diff --git a/src/eccryptoverify.cpp b/src/eccryptoverify.cpp deleted file mode 100644 index e894e1122c..0000000000 --- a/src/eccryptoverify.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "eccryptoverify.h" - -namespace { - -int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) { - while (c1len > c2len) { - if (*c1) - return 1; - c1++; - c1len--; - } - while (c2len > c1len) { - if (*c2) - return -1; - c2++; - c2len--; - } - while (c1len > 0) { - if (*c1 > *c2) - return 1; - if (*c2 > *c1) - return -1; - c1++; - c2++; - c1len--; - } - return 0; -} - -/** Order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModOrder[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 -}; - -/** Half of the order of secp256k1's generator minus 1. */ -const unsigned char vchMaxModHalfOrder[32] = { - 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D, - 0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0 -}; - -const unsigned char vchZero[1] = {0}; -} // anon namespace - -namespace eccrypto { - -bool Check(const unsigned char *vch) { - return vch && - CompareBigEndian(vch, 32, vchZero, 0) > 0 && - CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0; -} - -bool CheckSignatureElement(const unsigned char *vch, int len, bool half) { - return vch && - CompareBigEndian(vch, len, vchZero, 0) > 0 && - CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0; -} - -} // namespace eccrypto diff --git a/src/eccryptoverify.h b/src/eccryptoverify.h deleted file mode 100644 index c67c1e44fc..0000000000 --- a/src/eccryptoverify.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ECCRYPTOVERIFY_H -#define BITCOIN_ECCRYPTOVERIFY_H - -#include <vector> -#include <cstdlib> - -class uint256; - -namespace eccrypto { - -bool Check(const unsigned char *vch); -bool CheckSignatureElement(const unsigned char *vch, int len, bool half); - -} // eccrypto namespace - -#endif // BITCOIN_ECCRYPTOVERIFY_H diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp deleted file mode 100644 index f94bc954fd..0000000000 --- a/src/ecwrapper.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "ecwrapper.h" - -#include "serialize.h" -#include "uint256.h" - -#include <openssl/bn.h> -#include <openssl/ecdsa.h> -#include <openssl/obj_mac.h> - -namespace { - -class ecgroup_order -{ -public: - static const EC_GROUP* get() - { - static const ecgroup_order wrapper; - return wrapper.pgroup; - } - -private: - ecgroup_order() - : pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1)) - { - } - - ~ecgroup_order() - { - EC_GROUP_free(pgroup); - } - - EC_GROUP* pgroup; -}; - -/** - * Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields - * recid selects which key is recovered - * if check is non-zero, additional checks are performed - */ -int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) -{ - if (!eckey) return 0; - - int ret = 0; - BN_CTX *ctx = NULL; - - BIGNUM *x = NULL; - BIGNUM *e = NULL; - BIGNUM *order = NULL; - BIGNUM *sor = NULL; - BIGNUM *eor = NULL; - BIGNUM *field = NULL; - EC_POINT *R = NULL; - EC_POINT *O = NULL; - EC_POINT *Q = NULL; - BIGNUM *rr = NULL; - BIGNUM *zero = NULL; - int n = 0; - int i = recid / 2; - - const EC_GROUP *group = EC_KEY_get0_group(eckey); - if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } - BN_CTX_start(ctx); - order = BN_CTX_get(ctx); - if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } - x = BN_CTX_get(ctx); - if (!BN_copy(x, order)) { ret=-1; goto err; } - if (!BN_mul_word(x, i)) { ret=-1; goto err; } - if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } - field = BN_CTX_get(ctx); - if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } - if (BN_cmp(x, field) >= 0) { ret=0; goto err; } - if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } - if (check) - { - if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } - if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } - } - if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } - n = EC_GROUP_get_degree(group); - e = BN_CTX_get(ctx); - if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } - if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); - zero = BN_CTX_get(ctx); - if (!BN_zero(zero)) { ret=-1; goto err; } - if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } - rr = BN_CTX_get(ctx); - if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } - sor = BN_CTX_get(ctx); - if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } - eor = BN_CTX_get(ctx); - if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } - if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } - if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } - - ret = 1; - -err: - if (ctx) { - BN_CTX_end(ctx); - BN_CTX_free(ctx); - } - if (R != NULL) EC_POINT_free(R); - if (O != NULL) EC_POINT_free(O); - if (Q != NULL) EC_POINT_free(Q); - return ret; -} - -} // anon namespace - -CECKey::CECKey() { - pkey = EC_KEY_new(); - assert(pkey != NULL); - int result = EC_KEY_set_group(pkey, ecgroup_order::get()); - assert(result); -} - -CECKey::~CECKey() { - EC_KEY_free(pkey); -} - -void CECKey::GetPubKey(std::vector<unsigned char> &pubkey, bool fCompressed) { - EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); - int nSize = i2o_ECPublicKey(pkey, NULL); - assert(nSize); - assert(nSize <= 65); - pubkey.clear(); - pubkey.resize(nSize); - unsigned char *pbegin(begin_ptr(pubkey)); - int nSize2 = i2o_ECPublicKey(pkey, &pbegin); - assert(nSize == nSize2); -} - -bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) { - return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL; -} - -bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) { - if (vchSig.empty()) - return false; - - // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. - unsigned char *norm_der = NULL; - ECDSA_SIG *norm_sig = ECDSA_SIG_new(); - const unsigned char* sigptr = &vchSig[0]; - assert(norm_sig); - if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) - { - /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on - * error. But OpenSSL's own use of this function redundantly frees the - * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a - * clear contract for the function behaving the same way is more - * conservative. - */ - ECDSA_SIG_free(norm_sig); - return false; - } - int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); - ECDSA_SIG_free(norm_sig); - if (derlen <= 0) - return false; - - // -1 = error, 0 = bad sig, 1 = good - bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; - OPENSSL_free(norm_der); - return ret; -} - -bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec) -{ - if (rec<0 || rec>=3) - return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&p64[0], 32, sig->r); - BN_bin2bn(&p64[32], 32, sig->s); - bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1; - ECDSA_SIG_free(sig); - return ret; -} - -bool CECKey::TweakPublic(const unsigned char vchTweak[32]) { - bool ret = true; - BN_CTX *ctx = BN_CTX_new(); - BN_CTX_start(ctx); - BIGNUM *bnTweak = BN_CTX_get(ctx); - BIGNUM *bnOrder = BN_CTX_get(ctx); - BIGNUM *bnOne = BN_CTX_get(ctx); - const EC_GROUP *group = EC_KEY_get0_group(pkey); - EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order... - BN_bin2bn(vchTweak, 32, bnTweak); - if (BN_cmp(bnTweak, bnOrder) >= 0) - ret = false; // extremely unlikely - EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group); - BN_one(bnOne); - EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx); - if (EC_POINT_is_at_infinity(group, point)) - ret = false; // ridiculously unlikely - EC_KEY_set_public_key(pkey, point); - EC_POINT_free(point); - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return ret; -} - -bool CECKey::SanityCheck() -{ - const EC_GROUP *pgroup = ecgroup_order::get(); - if(pgroup == NULL) - return false; - // TODO Is there more EC functionality that could be missing? - return true; -} diff --git a/src/ecwrapper.h b/src/ecwrapper.h deleted file mode 100644 index efb6cd18a7..0000000000 --- a/src/ecwrapper.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ECWRAPPER_H -#define BITCOIN_ECWRAPPER_H - -#include <cstddef> -#include <vector> - -#include <openssl/ec.h> - -class uint256; - -/** RAII Wrapper around OpenSSL's EC_KEY */ -class CECKey { -private: - EC_KEY *pkey; - -public: - CECKey(); - ~CECKey(); - - void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed); - bool SetPubKey(const unsigned char* pubkey, size_t size); - bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig); - - /** - * reconstruct public key from a compact signature - * This is only slightly more CPU intensive than just verifying it. - * If this function succeeds, the recovered public key is guaranteed to be valid - * (the signature is a valid signature of the given data for that key) - */ - bool Recover(const uint256 &hash, const unsigned char *p64, int rec); - - bool TweakPublic(const unsigned char vchTweak[32]); - static bool SanityCheck(); -}; - -#endif // BITCOIN_ECWRAPPER_H diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 424ef015c8..52f5675e85 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -365,6 +365,10 @@ static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue) /** libevent event log callback */ static void libevent_log_cb(int severity, const char *msg) { +#ifndef EVENT_LOG_WARN +// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed. +# define EVENT_LOG_WARN _EVENT_LOG_WARN +#endif if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category LogPrintf("libevent: %s\n", msg); else diff --git a/src/init.cpp b/src/init.cpp index 36c1dfbe86..cd84e7747a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -154,6 +154,7 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { @@ -243,6 +244,7 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif + globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -649,8 +651,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) bool InitSanityCheck(void) { if(!ECC_InitSanityCheck()) { - InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more " - "information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries"); + InitError("Elliptic curve cryptography sanity check failure. Aborting."); return false; } if (!glibc_sanity_test() || !glibcxx_sanity_test()) @@ -991,6 +992,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Initialize elliptic curve code ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); // Sanity check if (!InitSanityCheck()) @@ -1601,7 +1603,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) scheduler.scheduleEvery(f, nPowTargetSpacing); // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), Params()); + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), chainparams); // ********************************************************* Step 12: finished diff --git a/src/main.cpp b/src/main.cpp index 9fca183bb0..a1f326fb13 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2577,7 +2577,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd pos.nPos = vinfoBlockFile[nFile].nSize; } - if (nFile != nLastBlockFile) { + if ((int)nFile != nLastBlockFile) { if (!fKnown) { LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); } @@ -2927,9 +2927,8 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) { - const CChainParams& chainparams = Params(); // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -2958,9 +2957,8 @@ bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* return true; } -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { - const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); assert(pindexPrev && pindexPrev == chainActive.Tip()); if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) @@ -3500,7 +3498,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (ProcessNewBlock(state, NULL, &block, true, dbp)) + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) nLoaded++; if (state.IsError()) break; @@ -3522,7 +3520,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessNewBlock(dummy, NULL, &block, true, &it->second)) + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -4562,7 +4560,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes diff --git a/src/main.h b/src/main.h index c304b311e4..eb61ff9570 100644 --- a/src/main.h +++ b/src/main.h @@ -31,6 +31,7 @@ class CBlockIndex; class CBlockTreeDB; class CBloomFilter; +class CChainParams; class CInv; class CScriptCheck; class CTxMemPool; @@ -161,7 +162,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -380,7 +381,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); diff --git a/src/miner.cpp b/src/miner.cpp index 053d9cdbc4..bb6b513372 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -99,9 +99,8 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam return nNewTime - nOldTime; } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) { - const CChainParams& chainparams = Params(); // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) @@ -110,7 +109,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios - if (Params().MineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); // Create coinbase tx @@ -345,13 +344,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed"); } @@ -432,7 +431,7 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) return error("BitcoinMiner: ProcessNewBlock, block not accepted"); return true; @@ -478,7 +477,7 @@ void static BitcoinMiner(const CChainParams& chainparams) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); diff --git a/src/miner.h b/src/miner.h index ad13204818..7b544303e0 100644 --- a/src/miner.h +++ b/src/miner.h @@ -29,7 +29,7 @@ struct CBlockTemplate /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index bdab137600..6ebb152c75 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -4,19 +4,184 @@ #include "pubkey.h" -#include "eccryptoverify.h" +#include <secp256k1.h> +#include <secp256k1_recovery.h> -#include "ecwrapper.h" +namespace +{ +/* Global secp256k1_context object used for verification. */ +secp256k1_context* secp256k1_context_verify = NULL; +} + +/** This function is taken from the libsecp256k1 distribution and implements + * DER parsing for ECDSA signatures, while supporting an arbitrary subset of + * format violations. + * + * Supported violations include negative integers, excessive padding, garbage + * at the end, and overly long length descriptors. This is safe to use in + * Bitcoin because since the activation of BIP66, signatures are verified to be + * strict DER before being passed to this module, and we know it supports all + * violations present in the blockchain before that point. + */ +static int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + /* Overwrite the result again with a correctly-parsed but invalid + signature if parsing failed. */ + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - if (!key.Verify(hash, vchSig)) + } + if (vchSig.size() == 0) { return false; - return true; + } + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + /* libsecp256k1's ECDSA verification requires lower-S signatures, which have + * not historically been enforced in Bitcoin, so normalize them first. */ + secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig); + return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); } bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) { @@ -24,33 +189,39 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha return false; int recid = (vchSig[0] - 27) & 3; bool fComp = ((vchSig[0] - 27) & 4) != 0; - CECKey key; - if (!key.Recover(hash, &vchSig[1], recid)) + secp256k1_pubkey pubkey; + secp256k1_ecdsa_recoverable_signature sig; + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) { return false; - std::vector<unsigned char> pubkey; - key.GetPubKey(pubkey, fComp); - Set(pubkey.begin(), pubkey.end()); + } + if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { + return false; + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) - return false; - return true; + secp256k1_pubkey pubkey; + return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size()); } bool CPubKey::Decompress() { if (!IsValid()) return false; - CECKey key; - if (!key.SetPubKey(begin(), size())) + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; - std::vector<unsigned char> pubkey; - key.GetPubKey(pubkey, false); - Set(pubkey.begin(), pubkey.end()); + } + unsigned char pub[65]; + size_t publen = 65; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + Set(pub, pub + publen); return true; } @@ -61,13 +232,18 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi unsigned char out[64]; BIP32Hash(cc, nChild, *begin(), begin()+1, out); memcpy(ccChild.begin(), out+32, 32); - CECKey key; - bool ret = key.SetPubKey(begin(), size()); - ret &= key.TweakPublic(out); - std::vector<unsigned char> pubkey; - key.GetPubKey(pubkey, true); - pubkeyChild.Set(pubkey.begin(), pubkey.end()); - return ret; + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { + return false; + } + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) { + return false; + } + unsigned char pub[33]; + size_t publen = 33; + secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); + pubkeyChild.Set(pub, pub + publen); + return true; } void CExtPubKey::Encode(unsigned char code[74]) const { @@ -95,3 +271,33 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { out.nChild = nChild; return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode); } + +/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) { + secp256k1_ecdsa_signature sig; + if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { + return false; + } + return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig)); +} + +/* static */ int ECCVerifyHandle::refcount = 0; + +ECCVerifyHandle::ECCVerifyHandle() +{ + if (refcount == 0) { + assert(secp256k1_context_verify == NULL); + secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + assert(secp256k1_context_verify != NULL); + } + refcount++; +} + +ECCVerifyHandle::~ECCVerifyHandle() +{ + refcount--; + if (refcount == 0) { + assert(secp256k1_context_verify != NULL); + secp256k1_context_destroy(secp256k1_context_verify); + secp256k1_context_verify = NULL; + } +} diff --git a/src/pubkey.h b/src/pubkey.h index cce9c826e5..a1d437e706 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -177,6 +177,11 @@ public: */ bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const; + /** + * Check whether a signature is normalized (lower-S). + */ + static bool CheckLowS(const std::vector<unsigned char>& vchSig); + //! Recover a public key from a compact signature. bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig); @@ -205,4 +210,15 @@ struct CExtPubKey { bool Derive(CExtPubKey& out, unsigned int nChild) const; }; +/** Users of this module must hold an ECCVerifyHandle. The constructor and + * destructor of these are not allowed to run in parallel, though. */ +class ECCVerifyHandle +{ + static int refcount; + +public: + ECCVerifyHandle(); + ~ECCVerifyHandle(); +}; + #endif // BITCOIN_PUBKEY_H diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f42b31627c..3fd07fc374 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -157,7 +157,7 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -171,7 +171,7 @@ UniValue generate(const UniValue& params, bool fHelp) ++pblock->nNonce; } CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -426,7 +426,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, block, pindexPrev, false, true); + TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } @@ -510,7 +510,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -652,7 +652,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 9bf017e385..8915010649 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -368,7 +368,16 @@ UniValue getnettotals(const UniValue& params, bool fHelp) "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" - " \"timemillis\": t (numeric) Total cpu time\n" + " \"timemillis\": t, (numeric) Total cpu time\n" + " \"uploadtarget\":\n" + " {\n" + " \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n" + " \"target\": n, (numeric) Target in bytes\n" + " \"target_reached\": true|false, (boolean) True if target is reached\n" + " \"serve_historical_blocks\": true|false, (boolean) True if serving historical blocks\n" + " \"bytes_left_in_cycle\": t, (numeric) Bytes left in current time cycle\n" + " \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnettotals", "") diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index b0d5faaf77..79504f6ad3 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -6,6 +6,7 @@ #include "bitcoinconsensus.h" #include "primitives/transaction.h" +#include "pubkey.h" #include "script/interpreter.h" #include "version.h" @@ -60,7 +61,13 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) return 0; } -} // anon namespace +struct ECCryptoClosure +{ + ECCVerifyHandle handle; +}; + +ECCryptoClosure instance_of_eccryptoclosure; +} int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, const unsigned char *txTo , unsigned int txToLen, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 6a20d497c0..8dcab832cb 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -9,7 +9,6 @@ #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" -#include "eccryptoverify.h" #include "pubkey.h" #include "script/script.h" #include "uint256.h" @@ -165,16 +164,8 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { if (!IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } - unsigned int nLenR = vchSig[3]; - unsigned int nLenS = vchSig[5+nLenR]; - const unsigned char *S = &vchSig[6+nLenR]; - // If the S value is above the order of the curve divided by two, its - // complement modulo the order could have been used instead, which is - // one byte shorter when encoded correctly. - if (!eccrypto::CheckSignatureElement(S, nLenS, true)) - return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); - - return true; + std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); + return CPubKey::CheckLowS(vchSigCopy); } bool static IsDefinedHashtypeSignature(const valtype &vchSig) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 827525783a..f745b75a82 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -59,6 +59,7 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + const CChainParams& chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CMutableTransaction tx,tx2; @@ -69,7 +70,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -91,14 +92,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = pblock->ComputeMerkleRoot(); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -116,7 +117,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -136,14 +137,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -161,7 +162,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -172,7 +173,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -190,7 +191,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -204,17 +205,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; @@ -246,7 +247,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); // Neither tx should have make it into the template. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); @@ -261,7 +262,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) //BOOST_CHECK(CheckFinalTx(tx)); //BOOST_CHECK(CheckFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); delete pblocktemplate; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 23e5e66d84..319e63ba55 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -114,7 +114,8 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) { - CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey); + const CChainParams& chainparams = Params(); + CBlockTemplate *pblocktemplate = CreateNewBlock(chainparams, scriptPubKey); CBlock& block = pblocktemplate->block; // Replace mempool-selected txns with just coinbase plus passed-in txns: @@ -125,10 +126,10 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, NULL, &block, true, NULL); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); CBlock result = block; delete pblocktemplate; diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 0bab4b6831..f657d72038 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -3,6 +3,7 @@ #include "chainparamsbase.h" #include "key.h" +#include "pubkey.h" #include "txdb.h" #include <boost/filesystem.hpp> @@ -12,6 +13,8 @@ * This just configures logging and chain parameters. */ struct BasicTestingSetup { + ECCVerifyHandle globalVerifyHandle; + BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~BasicTestingSetup(); }; |