mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #4192 from UdjinM6/backports-0.17-pr32
Backports 0.17 pr32
This commit is contained in:
commit
eea77e9642
@ -107,9 +107,10 @@ BITCOIN_TESTS =\
|
||||
test/txindex_tests.cpp \
|
||||
test/txvalidation_tests.cpp \
|
||||
test/txvalidationcache_tests.cpp \
|
||||
test/versionbits_tests.cpp \
|
||||
test/uint256_tests.cpp \
|
||||
test/util_tests.cpp
|
||||
test/util_tests.cpp \
|
||||
test/validation_block_tests.cpp \
|
||||
test/versionbits_tests.cpp
|
||||
|
||||
if ENABLE_WALLET
|
||||
BITCOIN_TESTS += \
|
||||
|
@ -111,9 +111,9 @@ public:
|
||||
class ConsolePrinter : public Printer
|
||||
{
|
||||
public:
|
||||
void header();
|
||||
void result(const State& state);
|
||||
void footer();
|
||||
void header() override;
|
||||
void result(const State& state) override;
|
||||
void footer() override;
|
||||
};
|
||||
|
||||
// creates box plot with plotly.js
|
||||
@ -121,9 +121,9 @@ class PlotlyPrinter : public Printer
|
||||
{
|
||||
public:
|
||||
PlotlyPrinter(std::string plotly_url, int64_t width, int64_t height);
|
||||
void header();
|
||||
void result(const State& state);
|
||||
void footer();
|
||||
void header() override;
|
||||
void result(const State& state) override;
|
||||
void footer() override;
|
||||
|
||||
private:
|
||||
std::string m_plotly_url;
|
||||
|
@ -523,7 +523,7 @@ public:
|
||||
chainTxData = ChainTxData{
|
||||
1617874573, // * UNIX timestamp of last known number of transactions (Block 1450962)
|
||||
34709765, // * total number of transactions between genesis and that timestamp
|
||||
// (the tx=... number in the SetBestChain debug.log lines)
|
||||
// (the tx=... number in the ChainStateFlushed debug.log lines)
|
||||
0.3 // * estimated number of transactions per second after that timestamp
|
||||
};
|
||||
}
|
||||
@ -703,7 +703,7 @@ public:
|
||||
chainTxData = ChainTxData{
|
||||
1617874832, // * UNIX timestamp of last known number of transactions (Block 477483)
|
||||
4926985, // * total number of transactions between genesis and that timestamp
|
||||
// (the tx=... number in the SetBestChain debug.log lines)
|
||||
// (the tx=... number in the ChainStateFlushed debug.log lines)
|
||||
0.01 // * estimated number of transactions per second after that timestamp
|
||||
};
|
||||
|
||||
|
@ -192,7 +192,7 @@ void TxIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const C
|
||||
}
|
||||
}
|
||||
|
||||
void TxIndex::SetBestChain(const CBlockLocator& locator)
|
||||
void TxIndex::ChainStateFlushed(const CBlockLocator& locator)
|
||||
{
|
||||
if (!m_synced) {
|
||||
return;
|
||||
@ -211,7 +211,7 @@ void TxIndex::SetBestChain(const CBlockLocator& locator)
|
||||
return;
|
||||
}
|
||||
|
||||
// This checks that SetBestChain callbacks are received after BlockConnected. The check may fail
|
||||
// This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
|
||||
// immediately after the the sync thread catches up and sets m_synced. Consider the case where
|
||||
// there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
|
||||
// backlog even after the sync thread has caught up to the new chain tip. In this unlikely
|
||||
@ -268,7 +268,9 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
|
||||
CBlockHeader header;
|
||||
try {
|
||||
file >> header;
|
||||
fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
|
||||
if (fseek(file.Get(), postx.nTxOffset, SEEK_CUR)) {
|
||||
return error("%s: fseek(...) failed", __func__);
|
||||
}
|
||||
file >> tx;
|
||||
} catch (const std::exception& e) {
|
||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||
|
@ -55,7 +55,7 @@ protected:
|
||||
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
|
||||
const std::vector<CTransactionRef>& txn_conflicted) override;
|
||||
|
||||
void SetBestChain(const CBlockLocator& locator) override;
|
||||
void ChainStateFlushed(const CBlockLocator& locator) override;
|
||||
|
||||
public:
|
||||
/// Constructs the TxIndex, which becomes available to be queried.
|
||||
|
@ -312,7 +312,7 @@ void PrepareShutdown()
|
||||
fFeeEstimatesInitialized = false;
|
||||
}
|
||||
|
||||
// FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
|
||||
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
|
||||
if (pcoinsTip != nullptr) {
|
||||
FlushStateToDisk();
|
||||
}
|
||||
|
@ -308,7 +308,11 @@ void BCLog::Logger::ShrinkDebugFile()
|
||||
{
|
||||
// Restart the file with some of the end
|
||||
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
|
||||
fseek(file, -((long)vch.size()), SEEK_END);
|
||||
if (fseek(file, -((long)vch.size()), SEEK_END)) {
|
||||
LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
int nBytes = fread(vch.data(), 1, vch.size(), file);
|
||||
fclose(file);
|
||||
|
||||
|
@ -22,6 +22,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 2000000;
|
||||
static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
|
||||
/** The maximum size for transactions we're willing to relay/mine */
|
||||
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
|
||||
/** The minimum size for transactions we're willing to relay/mine (1 empty scriptSig input + 1 P2PKH output = 85 bytes) */
|
||||
static const unsigned int MIN_STANDARD_TX_SIZE = 85;
|
||||
/** Maximum number of signature check operations in an IsStandard() P2SH script */
|
||||
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
||||
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
||||
@ -52,7 +54,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
|
||||
SCRIPT_VERIFY_LOW_S |
|
||||
SCRIPT_ENABLE_DIP0020_OPCODES;
|
||||
SCRIPT_ENABLE_DIP0020_OPCODES |
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE;
|
||||
|
||||
/** 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;
|
||||
|
@ -76,8 +76,20 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Non-canonical public key: neither compressed nor uncompressed
|
||||
return false;
|
||||
// Non-canonical public key: neither compressed nor uncompressed
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool static IsCompressedPubKey(const valtype &vchPubKey) {
|
||||
if (vchPubKey.size() != 33) {
|
||||
// Non-canonical public key: invalid length for compressed key
|
||||
return false;
|
||||
}
|
||||
if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
|
||||
// Non-canonical public key: invalid prefix for compressed key
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -202,8 +214,8 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
||||
return true;
|
||||
}
|
||||
|
||||
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
|
||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
|
||||
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
|
||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
||||
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
||||
}
|
||||
return true;
|
||||
@ -328,6 +340,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
opcode == OP_RSHIFT)
|
||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
|
||||
|
||||
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR is rejected even in an unexecuted branch
|
||||
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);
|
||||
|
||||
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
|
||||
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
|
||||
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
|
||||
@ -944,6 +960,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
|
||||
case OP_CODESEPARATOR:
|
||||
{
|
||||
// If SCRIPT_VERIFY_CONST_SCRIPTCODE flag is set, use of OP_CODESEPARATOR is rejected,
|
||||
// even in an unexecuted branch (this is checked above the opcode case statement).
|
||||
|
||||
// Hash starts after the code separator
|
||||
pbegincodehash = pc;
|
||||
}
|
||||
@ -964,10 +983,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
|
||||
// Drop the signature, since there's no way for a signature to sign itself
|
||||
if (sigversion == SigVersion::BASE) {
|
||||
FindAndDelete(scriptCode, CScript(vchSig));
|
||||
int found = FindAndDelete(scriptCode, CScript(vchSig));
|
||||
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
|
||||
}
|
||||
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
|
||||
//serror is set
|
||||
return false;
|
||||
}
|
||||
@ -1000,7 +1021,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
valtype &vchMessage = stacktop(-2);
|
||||
valtype &vchPubKey = stacktop(-1);
|
||||
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
|
||||
// serror is set
|
||||
return false;
|
||||
}
|
||||
@ -1071,7 +1092,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
{
|
||||
valtype& vchSig = stacktop(-isig-k);
|
||||
if (sigversion == SigVersion::BASE) {
|
||||
FindAndDelete(scriptCode, CScript(vchSig));
|
||||
int found = FindAndDelete(scriptCode, CScript(vchSig));
|
||||
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1084,7 +1107,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
// Note how this makes the exact order of pubkey/signature evaluation
|
||||
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
|
||||
// See the script_(in)valid tests for details.
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
|
||||
// serror is set
|
||||
return false;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@ -98,6 +98,10 @@ enum
|
||||
|
||||
// Enable the opcodes listed in DIP0020 (OP_CAT, OP_AND, OP_OR, OP_XOR, OP_DIV, OP_MOD, OP_SPLIT, OP_BIN2NUM, OP_NUM2BIN, OP_CHECKDATASIG, OP_CHECKDATASIGVERIFY).
|
||||
SCRIPT_ENABLE_DIP0020_OPCODES = (1U << 15),
|
||||
|
||||
// Making OP_CODESEPARATOR and FindAndDelete fail
|
||||
//
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
|
||||
};
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
||||
|
@ -13,7 +13,26 @@
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
static bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* This is an enum that tracks the execution context of a script, similar to
|
||||
* SigVersion in script/interpreter. It is separate however because we want to
|
||||
* distinguish between top-level scriptPubKey execution and P2SH redeemScript
|
||||
* execution (a distinction that has no impact on consensus rules).
|
||||
*/
|
||||
enum class IsMineSigVersion
|
||||
{
|
||||
TOP = 0, //! scriptPubKey execution
|
||||
P2SH = 1, //! P2SH redeemScript
|
||||
};
|
||||
|
||||
bool PermitsUncompressed(IsMineSigVersion sigversion)
|
||||
{
|
||||
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
|
||||
}
|
||||
|
||||
bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
{
|
||||
for (const valtype& pubkey : pubkeys) {
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
@ -22,13 +41,7 @@ static bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keyst
|
||||
return true;
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
|
||||
{
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
return IsMine(keystore, script);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, IsMineSigVersion sigversion)
|
||||
{
|
||||
std::vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
@ -46,11 +59,22 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
break;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
|
||||
isInvalid = true;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
if (keystore.HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
CPubKey pubkey;
|
||||
if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
|
||||
isInvalid = true;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
}
|
||||
if (keystore.HaveKey(keyID))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
@ -59,20 +83,31 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
|
||||
CScript subscript;
|
||||
if (keystore.GetCScript(scriptID, subscript)) {
|
||||
isminetype ret = IsMine(keystore, subscript);
|
||||
if (ret == ISMINE_SPENDABLE)
|
||||
isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::P2SH);
|
||||
if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TX_MULTISIG:
|
||||
{
|
||||
// Never treat bare multisig outputs as ours (they can still be made watchonly-though)
|
||||
if (sigversion == IsMineSigVersion::TOP) break;
|
||||
|
||||
// Only consider transactions "mine" if we own ALL the
|
||||
// keys involved. Multi-signature transactions that are
|
||||
// partially owned (somebody else has a key that can spend
|
||||
// them) enable spend-out-from-under-you attacks, especially
|
||||
// in shared-wallet situations.
|
||||
std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
|
||||
if (!PermitsUncompressed(sigversion)) {
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i].size() != 33) {
|
||||
isInvalid = true;
|
||||
return ISMINE_NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HaveKeys(keys, keystore))
|
||||
return ISMINE_SPENDABLE;
|
||||
break;
|
||||
@ -86,3 +121,22 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||
}
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid)
|
||||
{
|
||||
return IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::TOP);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
|
||||
{
|
||||
bool isInvalid = false;
|
||||
return IsMine(keystore, scriptPubKey, isInvalid);
|
||||
}
|
||||
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest)
|
||||
{
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
return IsMine(keystore, script);
|
||||
}
|
||||
|
@ -28,6 +28,12 @@ enum isminetype
|
||||
/** used for bitflags of isminetype */
|
||||
typedef uint8_t isminefilter;
|
||||
|
||||
/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion
|
||||
* and return a ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as
|
||||
* different SIGVERSION may have different network rules. Currently there is no use of isInvalid but it could be
|
||||
* used in the future. See https://github.com/bitcoin/bitcoin/pull/8499 (segwit policy limits) as an example.
|
||||
*/
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
|
||||
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
|
||||
|
||||
|
@ -86,6 +86,10 @@ const char* ScriptErrorString(const ScriptError serror)
|
||||
return "Public key is neither compressed or uncompressed";
|
||||
case SCRIPT_ERR_CLEANSTACK:
|
||||
return "Extra items left on stack after execution";
|
||||
case SCRIPT_ERR_OP_CODESEPARATOR:
|
||||
return "Using OP_CODESEPARATOR";
|
||||
case SCRIPT_ERR_SIG_FINDANDDELETE:
|
||||
return "Signature is found in scriptCode";
|
||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||
case SCRIPT_ERR_ERROR_COUNT:
|
||||
default: break;
|
||||
|
@ -64,6 +64,10 @@ typedef enum ScriptError_t
|
||||
/* softfork safeness */
|
||||
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
|
||||
|
||||
/* Constant scriptCode */
|
||||
SCRIPT_ERR_OP_CODESEPARATOR,
|
||||
SCRIPT_ERR_SIG_FINDANDDELETE,
|
||||
|
||||
SCRIPT_ERR_ERROR_COUNT
|
||||
} ScriptError;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
||||
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -23,7 +23,7 @@ class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
CScriptID(const CScript& in);
|
||||
explicit CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
|
@ -255,5 +255,53 @@
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
["SCRIPT_VERIFY_CONST_SCRIPTCODE tests"],
|
||||
["All transactions are copied from OP_CODESEPARATOR tests in tx_valid.json"],
|
||||
|
||||
[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
|
||||
"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["CODESEPARATOR in an unexecuted IF block is still invalid"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["CODESEPARATOR in an executed IF block is invalid"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
|
||||
["Using CHECKSIG with singatures in scriptSigs will trigger FindAndDelete, which is invalid"],
|
||||
[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["OP_CODESEPARATOR in scriptSig is invalid"],
|
||||
[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["Again, FindAndDelete() in scriptSig"],
|
||||
[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["FindAndDelete() in redeemScript"],
|
||||
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
|
||||
"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["FindAndDelete() in bare CHECKMULTISIG"],
|
||||
[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
|
||||
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH,CONST_SCRIPTCODE"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
@ -12,12 +12,6 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
static isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid)
|
||||
{
|
||||
isInvalid = false;
|
||||
return IsMine(keystore, scriptPubKey);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||
@ -454,7 +448,14 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
|
||||
keystore.AddKey(keys[1]);
|
||||
|
||||
result = IsMine(keystore, scriptPubKey, isInvalid);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
BOOST_CHECK(!isInvalid);
|
||||
|
||||
// Keystore has 2/2 keys and the script
|
||||
keystore.AddCScript(scriptPubKey);
|
||||
|
||||
result = IsMine(keystore, scriptPubKey, isInvalid);
|
||||
BOOST_CHECK_EQUAL(result, ISMINE_NO);
|
||||
BOOST_CHECK(!isInvalid);
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,8 @@ static ScriptErrorDesc script_errors[]={
|
||||
{SCRIPT_ERR_INVALID_NUMBER_RANGE, "INVALID_NUMBER_RANGE"},
|
||||
{SCRIPT_ERR_DIV_BY_ZERO, "DIV_BY_ZERO"},
|
||||
{SCRIPT_ERR_MOD_BY_ZERO, "MOD_BY_ZERO"},
|
||||
{SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"},
|
||||
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
||||
};
|
||||
|
||||
static const char *FormatScriptError(ScriptError_t err)
|
||||
|
@ -53,6 +53,12 @@ FastRandomContext insecure_rand_ctx(insecure_rand_seed);
|
||||
extern bool fPrintToConsole;
|
||||
extern void noui_connect();
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const uint256& num)
|
||||
{
|
||||
os << num.ToString();
|
||||
return os;
|
||||
}
|
||||
|
||||
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
|
||||
: m_path_root(fs::temp_directory_path() / "test_dash" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
|
||||
{
|
||||
|
@ -161,4 +161,7 @@ private:
|
||||
const std::string m_reason;
|
||||
};
|
||||
|
||||
// define an implicit conversion here so that uint256 may be used directly in BOOST_CHECK_*
|
||||
std::ostream& operator<<(std::ostream& os, const uint256& num);
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
||||
// Copyright (c) 2011-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@ -46,6 +46,7 @@ static std::map<std::string, unsigned int> mapFlagNames = {
|
||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int) SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int) SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||
{std::string("DIP0020_OPCODES"), (unsigned int) SCRIPT_ENABLE_DIP0020_OPCODES},
|
||||
{std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE},
|
||||
};
|
||||
|
||||
unsigned int ParseScriptFlags(std::string strFlags)
|
||||
|
180
src/test/validation_block_tests.cpp
Normal file
180
src/test/validation_block_tests.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <miner.h>
|
||||
#include <pow.h>
|
||||
#include <random.h>
|
||||
#include <test/test_dash.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
struct RegtestingSetup : public TestingSetup {
|
||||
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup)
|
||||
|
||||
struct TestSubscriber : public CValidationInterface {
|
||||
uint256 m_expected_tip;
|
||||
|
||||
TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
|
||||
|
||||
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override
|
||||
{
|
||||
BOOST_CHECK_EQUAL(m_expected_tip, pindexNew->GetBlockHash());
|
||||
}
|
||||
|
||||
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex, const std::vector<CTransactionRef>& txnConflicted) override
|
||||
{
|
||||
BOOST_CHECK_EQUAL(m_expected_tip, block->hashPrevBlock);
|
||||
BOOST_CHECK_EQUAL(m_expected_tip, pindex->pprev->GetBlockHash());
|
||||
|
||||
m_expected_tip = block->GetHash();
|
||||
}
|
||||
|
||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindexDisconnected) override
|
||||
{
|
||||
BOOST_CHECK_EQUAL(m_expected_tip, block->GetHash());
|
||||
BOOST_CHECK_EQUAL(m_expected_tip, pindexDisconnected->GetBlockHash());
|
||||
|
||||
m_expected_tip = block->hashPrevBlock;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<CBlock> Block(const uint256& prev_hash)
|
||||
{
|
||||
static int i = 0;
|
||||
static uint64_t time = Params().GenesisBlock().nTime;
|
||||
|
||||
CScript pubKey;
|
||||
pubKey << i++ << OP_TRUE;
|
||||
|
||||
auto ptemplate = BlockAssembler(Params()).CreateNewBlock(pubKey);
|
||||
auto pblock = std::make_shared<CBlock>(ptemplate->block);
|
||||
pblock->hashPrevBlock = prev_hash;
|
||||
pblock->nTime = ++time;
|
||||
|
||||
return pblock;
|
||||
}
|
||||
|
||||
std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
|
||||
{
|
||||
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
|
||||
|
||||
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
|
||||
++(pblock->nNonce);
|
||||
}
|
||||
|
||||
return pblock;
|
||||
}
|
||||
|
||||
// construct a valid block
|
||||
const std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash)
|
||||
{
|
||||
return FinalizeBlock(Block(prev_hash));
|
||||
}
|
||||
|
||||
// construct an invalid block (but with a valid header)
|
||||
const std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash)
|
||||
{
|
||||
auto pblock = Block(prev_hash);
|
||||
|
||||
CMutableTransaction coinbase_spend;
|
||||
coinbase_spend.vin.push_back(CTxIn(COutPoint(pblock->vtx[0]->GetHash(), 0), CScript(), 0));
|
||||
coinbase_spend.vout.push_back(pblock->vtx[0]->vout[0]);
|
||||
|
||||
CTransactionRef tx = MakeTransactionRef(coinbase_spend);
|
||||
pblock->vtx.push_back(tx);
|
||||
|
||||
auto ret = FinalizeBlock(pblock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BuildChain(const uint256& root, int height, const unsigned int invalid_rate, const unsigned int branch_rate, const unsigned int max_size, std::vector<std::shared_ptr<const CBlock>>& blocks)
|
||||
{
|
||||
if (height <= 0 || blocks.size() >= max_size) return;
|
||||
|
||||
bool gen_invalid = GetRand(100) < invalid_rate;
|
||||
bool gen_fork = GetRand(100) < branch_rate;
|
||||
|
||||
const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root);
|
||||
blocks.push_back(pblock);
|
||||
if (!gen_invalid) {
|
||||
BuildChain(pblock->GetHash(), height - 1, invalid_rate, branch_rate, max_size, blocks);
|
||||
}
|
||||
|
||||
if (gen_fork) {
|
||||
blocks.push_back(GoodBlock(root));
|
||||
BuildChain(blocks.back()->GetHash(), height - 1, invalid_rate, branch_rate, max_size, blocks);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
|
||||
{
|
||||
// build a large-ish chain that's likely to have some forks
|
||||
std::vector<std::shared_ptr<const CBlock>> blocks;
|
||||
while (blocks.size() < 50) {
|
||||
blocks.clear();
|
||||
BuildChain(Params().GenesisBlock().GetHash(), 100, 15, 10, 500, blocks);
|
||||
}
|
||||
|
||||
bool ignored;
|
||||
CValidationState state;
|
||||
std::vector<CBlockHeader> headers;
|
||||
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
|
||||
|
||||
// Process all the headers so we understand the toplogy of the chain
|
||||
BOOST_CHECK(ProcessNewBlockHeaders(headers, state, Params()));
|
||||
|
||||
// Connect the genesis block and drain any outstanding events
|
||||
ProcessNewBlock(Params(), std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored);
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
// subscribe to events (this subscriber will validate event ordering)
|
||||
const CBlockIndex* initial_tip = nullptr;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
initial_tip = chainActive.Tip();
|
||||
}
|
||||
TestSubscriber sub(initial_tip->GetBlockHash());
|
||||
RegisterValidationInterface(&sub);
|
||||
|
||||
// create a bunch of threads that repeatedly process a block generated above at random
|
||||
// this will create parallelism and randomness inside validation - the ValidationInterface
|
||||
// will subscribe to events generated during block validation and assert on ordering invariance
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
threads.create_thread([&blocks]() {
|
||||
bool ignored;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
auto block = blocks[GetRand(blocks.size() - 1)];
|
||||
ProcessNewBlock(Params(), block, true, &ignored);
|
||||
}
|
||||
|
||||
// to make sure that eventually we process the full chain - do it here
|
||||
for (auto block : blocks) {
|
||||
if (block->vtx.size() == 1) {
|
||||
bool processed = ProcessNewBlock(Params(), block, true, &ignored);
|
||||
assert(processed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
threads.join_all();
|
||||
while (GetMainSignals().CallbacksPending() > 0) {
|
||||
MilliSleep(100);
|
||||
}
|
||||
|
||||
UnregisterValidationInterface(&sub);
|
||||
|
||||
BOOST_CHECK_EQUAL(sub.m_expected_tip, chainActive.Tip()->GetBlockHash());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -1024,7 +1024,9 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
|
||||
// Fallback version
|
||||
// TODO: just write one byte per block
|
||||
static const char buf[65536] = {};
|
||||
fseek(file, offset, SEEK_SET);
|
||||
if (fseek(file, offset, SEEK_SET)) {
|
||||
return;
|
||||
}
|
||||
while (length > 0) {
|
||||
unsigned int now = 65536;
|
||||
if (length < now)
|
||||
|
@ -153,6 +153,12 @@ private:
|
||||
*/
|
||||
std::set<CBlockIndex*> m_failed_blocks;
|
||||
|
||||
/**
|
||||
* the ChainState CriticalSection
|
||||
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
|
||||
*/
|
||||
CCriticalSection m_cs_chainstate;
|
||||
|
||||
public:
|
||||
CChain chainActive;
|
||||
BlockMap mapBlockIndex;
|
||||
@ -658,6 +664,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
||||
if (fRequireStandard && !IsStandardTx(tx, reason))
|
||||
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
|
||||
|
||||
// Do not work on transactions that are too small.
|
||||
// A transaction with 1 empty scriptSig input and 1 P2PKH output has size of 85 bytes.
|
||||
// Transactions smaller than this are not relayed to reduce unnecessary malloc overhead.
|
||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) < MIN_STANDARD_TX_SIZE)
|
||||
return state.DoS(0, false, REJECT_NONSTANDARD, "tx-size-small");
|
||||
|
||||
// Only accept nLockTime-using transactions that can be mined in the next
|
||||
// block; we don't want our mempool filled up with transactions that can't
|
||||
// be mined yet.
|
||||
@ -2450,13 +2462,12 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||
LOCK(cs_main);
|
||||
static int64_t nLastWrite = 0;
|
||||
static int64_t nLastFlush = 0;
|
||||
static int64_t nLastSetChain = 0;
|
||||
std::set<int> setFilesToPrune;
|
||||
bool fFlushForPrune = false;
|
||||
bool fDoFullFlush = false;
|
||||
int64_t nNow = 0;
|
||||
bool full_flush_completed = false;
|
||||
try {
|
||||
{
|
||||
bool fFlushForPrune = false;
|
||||
bool fDoFullFlush = false;
|
||||
LOCK(cs_LastBlockFile);
|
||||
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
|
||||
if (nManualPruneHeight > 0) {
|
||||
@ -2473,7 +2484,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||
}
|
||||
}
|
||||
}
|
||||
nNow = GetTimeMicros();
|
||||
int64_t nNow = GetTimeMicros();
|
||||
// Avoid writing/flushing immediately after startup.
|
||||
if (nLastWrite == 0) {
|
||||
nLastWrite = nNow;
|
||||
@ -2481,9 +2492,6 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||
if (nLastFlush == 0) {
|
||||
nLastFlush = nNow;
|
||||
}
|
||||
if (nLastSetChain == 0) {
|
||||
nLastSetChain = nNow;
|
||||
}
|
||||
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
|
||||
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
|
||||
cacheSize += evoDb->GetMemoryUsage();
|
||||
@ -2544,12 +2552,12 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||
return AbortNode(state, "Failed to commit EvoDB");
|
||||
}
|
||||
nLastFlush = nNow;
|
||||
full_flush_completed = true;
|
||||
}
|
||||
}
|
||||
if (fDoFullFlush || ((mode == FlushStateMode::ALWAYS || mode == FlushStateMode::PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
|
||||
if (full_flush_completed) {
|
||||
// Update best block in wallet (so we can detect restored wallets).
|
||||
GetMainSignals().SetBestChain(chainActive.GetLocator());
|
||||
nLastSetChain = nNow;
|
||||
GetMainSignals().ChainStateFlushed(chainActive.GetLocator());
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
||||
@ -2927,6 +2935,7 @@ void CChainState::PruneBlockIndexCandidates() {
|
||||
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||
|
||||
@ -3044,10 +3053,11 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
|
||||
// sanely for performance or correctness!
|
||||
AssertLockNotHeld(cs_main);
|
||||
|
||||
// make sure that no matter what, only one thread is executing ActivateBestChain. This avoids a race condition when
|
||||
// validation signals are invoked, which might result in out-of-order execution.
|
||||
static CCriticalSection cs_activateBestChain;
|
||||
LOCK(cs_activateBestChain);
|
||||
// ABC maintains a fair degree of expensive-to-calculate internal state
|
||||
// because this function periodically releases cs_main so that it does not lock up other threads for too long
|
||||
// during large connects - and to allow for e.g. the callback queue to drain
|
||||
// we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time
|
||||
LOCK(m_cs_chainstate);
|
||||
|
||||
boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
|
||||
|
||||
@ -3067,47 +3077,54 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
|
||||
SyncWithValidationInterfaceQueue();
|
||||
}
|
||||
|
||||
|
||||
const CBlockIndex *pindexFork;
|
||||
bool fInitialDownload;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
|
||||
CBlockIndex* starting_tip = chainActive.Tip();
|
||||
bool blocks_connected = false;
|
||||
do {
|
||||
// We absolutely may not unlock cs_main until we've made forward progress
|
||||
// (with the exception of shutdown due to hardware issues, low disk space, etc).
|
||||
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
|
||||
|
||||
CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
if (pindexMostWork == nullptr) {
|
||||
pindexMostWork = FindMostWorkChain();
|
||||
}
|
||||
if (pindexMostWork == nullptr) {
|
||||
pindexMostWork = FindMostWorkChain();
|
||||
}
|
||||
|
||||
// Whether we have anything to do at all.
|
||||
if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip())
|
||||
return true;
|
||||
// Whether we have anything to do at all.
|
||||
if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool fInvalidFound = false;
|
||||
std::shared_ptr<const CBlock> nullBlockPtr;
|
||||
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
|
||||
return false;
|
||||
bool fInvalidFound = false;
|
||||
std::shared_ptr<const CBlock> nullBlockPtr;
|
||||
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
|
||||
return false;
|
||||
blocks_connected = true;
|
||||
|
||||
if (fInvalidFound) {
|
||||
// Wipe cache, we may need another branch now.
|
||||
pindexMostWork = nullptr;
|
||||
}
|
||||
pindexNewTip = chainActive.Tip();
|
||||
pindexFork = chainActive.FindFork(pindexOldTip);
|
||||
fInitialDownload = IsInitialBlockDownload();
|
||||
if (fInvalidFound) {
|
||||
// Wipe cache, we may need another branch now.
|
||||
pindexMostWork = nullptr;
|
||||
}
|
||||
pindexNewTip = chainActive.Tip();
|
||||
|
||||
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
|
||||
assert(trace.pblock && trace.pindex);
|
||||
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
|
||||
}
|
||||
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
|
||||
assert(trace.pblock && trace.pindex);
|
||||
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
|
||||
}
|
||||
} while (!chainActive.Tip() || (starting_tip && CBlockIndexWorkComparator()(chainActive.Tip(), starting_tip)));
|
||||
if (!blocks_connected) return true;
|
||||
|
||||
const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip);
|
||||
bool fInitialDownload = IsInitialBlockDownload();
|
||||
|
||||
// Notify external listeners about the new tip.
|
||||
// Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
|
||||
GetMainSignals().SynchronousUpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
|
||||
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
|
||||
|
||||
// Always notify the UI if a new block tip was connected
|
||||
if (pindexFork != pindexNewTip) {
|
||||
// Notify ValidationInterface subscribers
|
||||
GetMainSignals().SynchronousUpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
|
||||
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
|
||||
|
||||
// Always notify the UI if a new block tip was connected
|
||||
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct MainSignalsInstance {
|
||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
|
||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex* pindexDisconnected)> BlockDisconnected;
|
||||
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
|
||||
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
||||
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
||||
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
||||
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
||||
@ -93,7 +93,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->NotifyChainLock.connect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.m_internals->ChainStateFlushed.connect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
|
||||
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
||||
@ -107,7 +107,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.m_internals->ChainStateFlushed.disconnect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
|
||||
g_signals.m_internals->NotifyChainLock.disconnect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2));
|
||||
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1, _2));
|
||||
@ -132,7 +132,7 @@ void UnregisterAllValidationInterfaces() {
|
||||
}
|
||||
g_signals.m_internals->BlockChecked.disconnect_all_slots();
|
||||
g_signals.m_internals->Broadcast.disconnect_all_slots();
|
||||
g_signals.m_internals->SetBestChain.disconnect_all_slots();
|
||||
g_signals.m_internals->ChainStateFlushed.disconnect_all_slots();
|
||||
g_signals.m_internals->NotifyTransactionLock.disconnect_all_slots();
|
||||
g_signals.m_internals->NotifyChainLock.disconnect_all_slots();
|
||||
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
|
||||
@ -205,9 +205,9 @@ void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock
|
||||
});
|
||||
}
|
||||
|
||||
void CMainSignals::SetBestChain(const CBlockLocator &locator) {
|
||||
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
||||
m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
|
||||
m_internals->SetBestChain(locator);
|
||||
m_internals->ChainStateFlushed(locator);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,11 @@ protected:
|
||||
*/
|
||||
~CValidationInterface() = default;
|
||||
/**
|
||||
* Notifies listeners of updated block chain tip
|
||||
* Notifies listeners when the block chain tip advances.
|
||||
*
|
||||
* When multiple blocks are connected at once, UpdatedBlockTip will be called on the final tip
|
||||
* but may not be called on every intermediate tip. If the latter behavior is desired,
|
||||
* subscribe to BlockConnected() instead.
|
||||
*
|
||||
* Called on a background thread.
|
||||
*/
|
||||
@ -136,9 +140,20 @@ protected:
|
||||
/**
|
||||
* Notifies listeners of the new active block chain on-disk.
|
||||
*
|
||||
* Prior to this callback, any updates are not guaranteed to persist on disk
|
||||
* (ie clients need to handle shutdown/restart safety by being able to
|
||||
* understand when some updates were lost due to unclean shutdown).
|
||||
*
|
||||
* When this callback is invoked, the validation changes done by any prior
|
||||
* callback are guaranteed to exist on disk and survive a restart, including
|
||||
* an unclean shutdown.
|
||||
*
|
||||
* Provides a locator describing the best chain, which is likely useful for
|
||||
* storing current state on disk in client DBs.
|
||||
*
|
||||
* Called on a background thread.
|
||||
*/
|
||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
||||
/** Tells listeners to broadcast their data. */
|
||||
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
|
||||
/**
|
||||
@ -198,7 +213,7 @@ public:
|
||||
void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef ¤tTx, const CTransactionRef &previousTx);
|
||||
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
|
||||
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff);
|
||||
void SetBestChain(const CBlockLocator &);
|
||||
void ChainStateFlushed(const CBlockLocator &);
|
||||
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
|
||||
void BlockChecked(const CBlock&, const CValidationState&);
|
||||
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
||||
|
@ -198,10 +198,11 @@ static void ImportScript(CWallet * const pwallet, const CScript& script, const s
|
||||
}
|
||||
|
||||
if (isRedeemScript) {
|
||||
if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
|
||||
const CScriptID id(script);
|
||||
if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
|
||||
}
|
||||
ImportAddress(pwallet, CScriptID(script), strLabel);
|
||||
ImportAddress(pwallet, id, strLabel);
|
||||
} else {
|
||||
CTxDestination destination;
|
||||
if (ExtractDestination(script, destination)) {
|
||||
@ -578,7 +579,8 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
} else if(IsHex(vstr[0])) {
|
||||
std::vector<unsigned char> vData(ParseHex(vstr[0]));
|
||||
CScript script = CScript(vData.begin(), vData.end());
|
||||
if (pwallet->HaveCScript(script)) {
|
||||
CScriptID id(script);
|
||||
if (pwallet->HaveCScript(id)) {
|
||||
LogPrintf("Skipping import of %s (script already present)\n", vstr[0]);
|
||||
continue;
|
||||
}
|
||||
@ -589,7 +591,7 @@ UniValue importwallet(const JSONRPCRequest& request)
|
||||
}
|
||||
int64_t birth_time = DecodeDumpTime(vstr[1]);
|
||||
if (birth_time > 0) {
|
||||
pwallet->m_script_metadata[CScriptID(script)].nCreateTime = birth_time;
|
||||
pwallet->m_script_metadata[id].nCreateTime = birth_time;
|
||||
nTimeBegin = std::min(nTimeBegin, birth_time);
|
||||
}
|
||||
}
|
||||
@ -1093,12 +1095,12 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
|
||||
if (!pwallet->HaveCScript(redeemScript) && !pwallet->AddCScript(redeemScript)) {
|
||||
CScriptID redeem_id(redeemScript);
|
||||
if (!pwallet->HaveCScript(redeem_id) && !pwallet->AddCScript(redeemScript)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
|
||||
}
|
||||
|
||||
CTxDestination redeem_dest = CScriptID(redeemScript);
|
||||
CScript redeemDestination = GetScriptForDestination(redeem_dest);
|
||||
CScript redeemDestination = GetScriptForDestination(redeem_id);
|
||||
|
||||
if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
|
||||
|
@ -627,7 +627,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
||||
return false;
|
||||
}
|
||||
|
||||
void CWallet::SetBestChain(const CBlockLocator& loc)
|
||||
void CWallet::ChainStateFlushed(const CBlockLocator& loc)
|
||||
{
|
||||
WalletBatch batch(*database);
|
||||
batch.WriteBestBlock(loc);
|
||||
@ -5093,7 +5093,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
|
||||
return error(_("Unable to generate initial keys"));
|
||||
}
|
||||
|
||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
||||
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
||||
|
||||
// Try to create wallet backup right after new wallet was created
|
||||
std::string strBackupWarning;
|
||||
@ -5240,7 +5240,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
|
||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
|
||||
}
|
||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
|
||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
||||
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
||||
walletInstance->database->IncrementUpdateCounter();
|
||||
|
||||
// Restore wallet transaction metadata after -zapwallettxes=1
|
||||
|
@ -1120,7 +1120,7 @@ public:
|
||||
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetChange(const CTransaction& tx) const;
|
||||
void SetBestChain(const CBlockLocator& loc) override;
|
||||
void ChainStateFlushed(const CBlockLocator& loc) override;
|
||||
|
||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||
void AutoLockMasternodeCollaterals();
|
||||
|
@ -81,7 +81,7 @@ class BIP68Test(BitcoinTestFramework):
|
||||
tx2.nVersion = 2
|
||||
sequence_value = sequence_value & 0x7fffffff
|
||||
tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)]
|
||||
tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))]
|
||||
tx2.vout = [CTxOut(int(value - self.relayfee * COIN), CScript([b'a' * 35]))]
|
||||
tx2.rehash()
|
||||
|
||||
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
|
||||
@ -223,7 +223,7 @@ class BIP68Test(BitcoinTestFramework):
|
||||
tx = CTransaction()
|
||||
tx.nVersion = 2
|
||||
tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]
|
||||
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))]
|
||||
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), CScript([b'a' * 35]))]
|
||||
tx.rehash()
|
||||
|
||||
if (orig_tx.hash in node.getrawmempool()):
|
||||
@ -351,7 +351,7 @@ class BIP68Test(BitcoinTestFramework):
|
||||
tx3 = CTransaction()
|
||||
tx3.nVersion = 2
|
||||
tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)]
|
||||
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
|
||||
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), CScript([b'a' * 35]))]
|
||||
tx3.rehash()
|
||||
|
||||
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
|
||||
|
@ -31,6 +31,7 @@ from test_framework.script import (
|
||||
OP_ELSE,
|
||||
OP_ENDIF,
|
||||
OP_EQUAL,
|
||||
OP_DROP,
|
||||
OP_FALSE,
|
||||
OP_HASH160,
|
||||
OP_IF,
|
||||
@ -1219,7 +1220,7 @@ class FullBlockTest(BitcoinTestFramework):
|
||||
block.vtx.extend(tx_list)
|
||||
|
||||
# this is a little handier to use than the version in blocktools.py
|
||||
def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE])):
|
||||
def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])):
|
||||
return create_transaction(spend_tx, n, b"", value, script)
|
||||
|
||||
# sign a transaction, using the key we know about
|
||||
|
@ -4,7 +4,7 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
from test_framework.messages import COutPoint, CTransaction, CTxIn, CTxOut, ToHex
|
||||
from test_framework.mininode import COIN
|
||||
from test_framework.script import CScript, OP_CAT
|
||||
from test_framework.script import CScript, OP_CAT, OP_DROP, OP_TRUE
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, assert_raises_rpc_error, get_bip9_status, satoshi_round
|
||||
|
||||
@ -47,7 +47,7 @@ class DIP0020ActivationTest(BitcoinTestFramework):
|
||||
value = int(value - self.relayfee * COIN)
|
||||
tx0 = CTransaction()
|
||||
tx0.vin.append(CTxIn(COutPoint(int(txid, 16), 0)))
|
||||
tx0.vout.append(CTxOut(value, CScript([])))
|
||||
tx0.vout.append(CTxOut(value, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
|
||||
tx0.rehash()
|
||||
tx0_hex = ToHex(tx0)
|
||||
|
||||
|
@ -9,7 +9,8 @@ from test_framework.mininode import *
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.blocktools import create_block, create_coinbase
|
||||
from test_framework.script import CScript, OP_TRUE
|
||||
from test_framework.script import CScript, OP_TRUE, OP_DROP
|
||||
|
||||
|
||||
# TestP2PConn: A peer we use to send messages to dashd, and store responses.
|
||||
class TestP2PConn(P2PInterface):
|
||||
@ -375,7 +376,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||
for i in range(num_transactions):
|
||||
tx = CTransaction()
|
||||
tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))
|
||||
tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE])))
|
||||
tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
|
||||
tx.rehash()
|
||||
utxo = [tx.sha256, 0, tx.vout[0].nValue]
|
||||
block.vtx.append(tx)
|
||||
|
@ -81,7 +81,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
|
||||
# Transaction will be rejected with code 16 (REJECT_INVALID)
|
||||
# and we get disconnected immediately
|
||||
self.log.info('Test a transaction that is rejected')
|
||||
tx1 = create_transaction(block1.vtx[0], 0, b'\x64', 50 * COIN)
|
||||
tx1 = create_transaction(block1.vtx[0], 0, b'\x64' * 35, 50 * COIN)
|
||||
node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
|
||||
|
||||
# Make two p2p connections to provide the node with orphans
|
||||
@ -114,32 +114,33 @@ class InvalidTxRequestTest(BitcoinTestFramework):
|
||||
|
||||
# Create a root transaction that we withold until all dependend transactions
|
||||
# are sent out and in the orphan cache
|
||||
SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51'
|
||||
tx_withhold = CTransaction()
|
||||
tx_withhold.vin.append(CTxIn(outpoint=COutPoint(base_tx, 0)))
|
||||
tx_withhold.vout.append(CTxOut(nValue=50 * COIN - 12000, scriptPubKey=b'\x51'))
|
||||
tx_withhold.vout.append(CTxOut(nValue=50 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
|
||||
tx_withhold.calc_sha256()
|
||||
|
||||
# Our first orphan tx with some outputs to create further orphan txs
|
||||
tx_orphan_1 = CTransaction()
|
||||
tx_orphan_1.vin.append(CTxIn(outpoint=COutPoint(tx_withhold.sha256, 0)))
|
||||
tx_orphan_1.vout = [CTxOut(nValue=10 * COIN, scriptPubKey=b'\x51')] * 3
|
||||
tx_orphan_1.vout = [CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 3
|
||||
tx_orphan_1.calc_sha256()
|
||||
|
||||
# A valid transaction with low fee
|
||||
tx_orphan_2_no_fee = CTransaction()
|
||||
tx_orphan_2_no_fee.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 0)))
|
||||
tx_orphan_2_no_fee.vout.append(CTxOut(nValue=10 * COIN, scriptPubKey=b'\x51'))
|
||||
tx_orphan_2_no_fee.vout.append(CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
|
||||
|
||||
# A valid transaction with sufficient fee
|
||||
tx_orphan_2_valid = CTransaction()
|
||||
tx_orphan_2_valid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 1)))
|
||||
tx_orphan_2_valid.vout.append(CTxOut(nValue=10 * COIN - 12000, scriptPubKey=b'\x51'))
|
||||
tx_orphan_2_valid.vout.append(CTxOut(nValue=10 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
|
||||
tx_orphan_2_valid.calc_sha256()
|
||||
|
||||
# An invalid transaction with negative fee
|
||||
tx_orphan_2_invalid = CTransaction()
|
||||
tx_orphan_2_invalid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 2)))
|
||||
tx_orphan_2_invalid.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=b'\x51'))
|
||||
tx_orphan_2_invalid.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))
|
||||
|
||||
self.log.info('Send the orphans ... ')
|
||||
# Send valid orphan txs from p2ps[0]
|
||||
|
64
test/functional/test_framework/address.py
Normal file
64
test/functional/test_framework/address.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# address.py
|
||||
#
|
||||
# This file encodes and decodes BASE58 P2PKH and P2SH addresses
|
||||
#
|
||||
|
||||
from .script import hash256, hash160, CScript
|
||||
from .util import bytes_to_hex_str, hex_str_to_bytes
|
||||
|
||||
chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||
|
||||
def byte_to_base58(b, version):
|
||||
result = ''
|
||||
str = bytes_to_hex_str(b)
|
||||
str = bytes_to_hex_str(chr(version).encode('latin-1')) + str
|
||||
checksum = bytes_to_hex_str(hash256(hex_str_to_bytes(str)))
|
||||
str += checksum[:8]
|
||||
value = int('0x'+str,0)
|
||||
while value > 0:
|
||||
result = chars[value % 58] + result
|
||||
value //= 58
|
||||
while (str[:2] == '00'):
|
||||
result = chars[0] + result
|
||||
str = str[2:]
|
||||
return result
|
||||
|
||||
# TODO: def base58_decode
|
||||
|
||||
def keyhash_to_p2pkh(hash, main = False):
|
||||
assert (len(hash) == 20)
|
||||
version = 76 if main else 140
|
||||
return byte_to_base58(hash, version)
|
||||
|
||||
def scripthash_to_p2sh(hash, main = False):
|
||||
assert (len(hash) == 20)
|
||||
version = 16 if main else 19
|
||||
return byte_to_base58(hash, version)
|
||||
|
||||
def key_to_p2pkh(key, main = False):
|
||||
key = check_key(key)
|
||||
return keyhash_to_p2pkh(hash160(key), main)
|
||||
|
||||
def script_to_p2sh(script, main = False):
|
||||
script = check_script(script)
|
||||
return scripthash_to_p2sh(hash160(script), main)
|
||||
|
||||
def check_key(key):
|
||||
if (type(key) is str):
|
||||
key = hex_str_to_bytes(key) # Assuming this is hex string
|
||||
if (type(key) is bytes and (len(key) == 33 or len(key) == 65)):
|
||||
return key
|
||||
assert(False)
|
||||
|
||||
def check_script(script):
|
||||
if (type(script) is str):
|
||||
script = hex_str_to_bytes(script) # Assuming this is hex string
|
||||
if (type(script) is bytes or type(script) is CScript):
|
||||
return script
|
||||
assert(False)
|
@ -70,6 +70,9 @@ ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p,
|
||||
# this specifies the curve used with ECDSA.
|
||||
NID_secp256k1 = 714 # from openssl/obj_mac.h
|
||||
|
||||
SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
|
||||
SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2
|
||||
|
||||
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
|
||||
def _check_result(val, func, args):
|
||||
if val == 0:
|
||||
@ -142,7 +145,7 @@ class CECKey():
|
||||
r = self.get_raw_ecdh_key(other_pubkey)
|
||||
return kdf(r)
|
||||
|
||||
def sign(self, hash):
|
||||
def sign(self, hash, low_s = True):
|
||||
# FIXME: need unit tests for below cases
|
||||
if not isinstance(hash, bytes):
|
||||
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
|
||||
@ -154,7 +157,25 @@ class CECKey():
|
||||
mb_sig = ctypes.create_string_buffer(sig_size0.value)
|
||||
result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
|
||||
assert 1 == result
|
||||
return mb_sig.raw[:sig_size0.value]
|
||||
assert mb_sig.raw[0] == 0x30
|
||||
assert mb_sig.raw[1] == sig_size0.value - 2
|
||||
total_size = mb_sig.raw[1]
|
||||
assert mb_sig.raw[2] == 2
|
||||
r_size = mb_sig.raw[3]
|
||||
assert mb_sig.raw[4 + r_size] == 2
|
||||
s_size = mb_sig.raw[5 + r_size]
|
||||
s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big')
|
||||
if (not low_s) or s_value <= SECP256K1_ORDER_HALF:
|
||||
return mb_sig.raw[:sig_size0.value]
|
||||
else:
|
||||
low_s_value = SECP256K1_ORDER - s_value
|
||||
low_s_bytes = (low_s_value).to_bytes(33, byteorder='big')
|
||||
while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80:
|
||||
low_s_bytes = low_s_bytes[1:]
|
||||
new_s_size = len(low_s_bytes)
|
||||
new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big')
|
||||
new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big')
|
||||
return b'\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes
|
||||
|
||||
def verify(self, hash, sig):
|
||||
"""Verify a DER signature"""
|
||||
|
Loading…
Reference in New Issue
Block a user